about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/documentation.md16
-rw-r--r--.github/ISSUE_TEMPLATE/library_tracking_issue.md4
-rw-r--r--Cargo.lock79
-rw-r--r--RELEASES.md3
-rw-r--r--compiler/rustc_arena/src/lib.rs27
-rw-r--r--compiler/rustc_arena/src/tests.rs24
-rw-r--r--compiler/rustc_ast/src/ast.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/asm.rs54
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs33
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs34
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs191
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs4
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs72
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs8
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs28
-rw-r--r--compiler/rustc_borrowck/src/constraint_generation.rs6
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs299
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_use.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs24
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs8
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs12
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs60
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs486
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/mod.rs51
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/polonius.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs47
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs6
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs2
-rw-r--r--compiler/rustc_borrowck/src/used_muts.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs47
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs34
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs99
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs51
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs96
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs23
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs14
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs43
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs896
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs20
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch32
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/common.rs25
-rw-r--r--compiler/rustc_codegen_gcc/src/context.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs9
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs47
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs18
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/type_of.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/command.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs42
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs97
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs75
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs89
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/consts.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs4
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs8
-rw-r--r--compiler/rustc_const_eval/src/errors.rs89
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs35
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs126
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs47
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs18
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs41
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs53
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs84
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs28
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs394
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs38
-rw-r--r--compiler/rustc_const_eval/src/interpret/traits.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs24
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs24
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs49
-rw-r--r--compiler/rustc_const_eval/src/lib.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs29
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs100
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs9
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs105
-rw-r--r--compiler/rustc_const_eval/src/util/collect_writes.rs4
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/sync.rs27
-rw-r--r--compiler/rustc_driver/src/lib.rs20
-rw-r--r--compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/const_eval.ftl31
-rw-r--r--compiler/rustc_error_messages/locales/en-US/expand.ftl5
-rw-r--r--compiler/rustc_error_messages/locales/en-US/lint.ftl400
-rw-r--r--compiler/rustc_error_messages/src/lib.rs7
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs121
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs25
-rw-r--r--compiler/rustc_errors/src/emitter.rs16
-rw-r--r--compiler/rustc_errors/src/json.rs16
-rw-r--r--compiler/rustc_errors/src/lib.rs50
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/build.rs13
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs38
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs4
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/arena.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs33
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir/src/lib.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs545
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs18
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs11
-rw-r--r--compiler/rustc_incremental/src/persist/work_product.rs46
-rw-r--r--compiler/rustc_index/src/bit_set.rs10
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs2
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs107
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs4
-rw-r--r--compiler/rustc_infer/src/infer/free_regions.rs32
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs2
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs38
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs42
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs30
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs7
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/env.rs88
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs57
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs9
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs2
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs4
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs8
-rw-r--r--compiler/rustc_infer/src/traits/project.rs4
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs5
-rw-r--r--compiler/rustc_interface/src/passes.rs54
-rw-r--r--compiler/rustc_interface/src/queries.rs10
-rw-r--r--compiler/rustc_interface/src/tests.rs3
-rw-r--r--compiler/rustc_interface/src/util.rs20
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs21
-rw-r--r--compiler/rustc_lint/src/builtin.rs366
-rw-r--r--compiler/rustc_lint/src/context.rs56
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs32
-rw-r--r--compiler/rustc_lint/src/expect.rs5
-rw-r--r--compiler/rustc_lint/src/hidden_unicode_codepoints.rs44
-rw-r--r--compiler/rustc_lint/src/internal.rs67
-rw-r--r--compiler/rustc_lint/src/late.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs10
-rw-r--r--compiler/rustc_lint/src/lib.rs2
-rw-r--r--compiler/rustc_lint/src/methods.rs17
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs35
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs73
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs40
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs21
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs7
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs12
-rw-r--r--compiler/rustc_lint/src/traits.rs21
-rw-r--r--compiler/rustc_lint/src/types.rs285
-rw-r--r--compiler/rustc_lint/src/unused.rs100
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs45
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs7
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs704
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs590
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs22
-rw-r--r--compiler/rustc_macros/src/diagnostics/fluent.rs8
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs55
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs9
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs41
-rw-r--r--compiler/rustc_macros/src/lib.rs21
-rw-r--r--compiler/rustc_macros/src/type_foldable.rs13
-rw-r--r--compiler/rustc_macros/src/type_visitable.rs33
-rw-r--r--compiler/rustc_metadata/src/creader.rs2
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs22
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs27
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs3
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs5
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs140
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs10
-rw-r--r--compiler/rustc_middle/src/hir/nested_filter.rs2
-rw-r--r--compiler/rustc_middle/src/hir/place.rs48
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs12
-rw-r--r--compiler/rustc_middle/src/infer/mod.rs2
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs26
-rw-r--r--compiler/rustc_middle/src/macros.rs46
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs147
-rw-r--r--compiler/rustc_middle/src/mir/coverage.rs19
-rw-r--r--compiler/rustc_middle/src/mir/graph_cyclic_cache.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs46
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs126
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs12
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs21
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs16
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs200
-rw-r--r--compiler/rustc_middle/src/mir/predecessors.rs2
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs7
-rw-r--r--compiler/rustc_middle/src/mir/query.rs2
-rw-r--r--compiler/rustc_middle/src/mir/switch_sources.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs56
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs2
-rw-r--r--compiler/rustc_middle/src/mir/traversal.rs33
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs154
-rw-r--r--compiler/rustc_middle/src/mir/type_visitable.rs186
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs276
-rw-r--r--compiler/rustc_middle/src/query/mod.rs22
-rw-r--r--compiler/rustc_middle/src/thir.rs24
-rw-r--r--compiler/rustc_middle/src/thir/abstract_const.rs2
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs45
-rw-r--r--compiler/rustc_middle/src/traits/query.rs21
-rw-r--r--compiler/rustc_middle/src/traits/select.rs22
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs10
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs5
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs2
-rw-r--r--compiler/rustc_middle/src/ty/cast.rs6
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs29
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs50
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs156
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs1
-rw-r--r--compiler/rustc_middle/src/ty/error.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs2
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs768
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs17
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs13
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs85
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs20
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs16
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs2
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs90
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs52
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs15
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs2
-rw-r--r--compiler/rustc_middle/src/ty/util.rs12
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs745
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs13
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs30
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs1
-rw-r--r--compiler/rustc_mir_build/src/lints.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs59
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs12
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/init_locals.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs8
-rw-r--r--compiler/rustc_mir_dataflow/src/storage.rs2
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs7
-rw-r--r--compiler/rustc_mir_transform/src/add_call_guards.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs3
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs3
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs4
-rw-r--r--compiler/rustc_mir_transform/src/const_debuginfo.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs68
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs48
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs9
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs1
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deaggregator.rs5
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs4
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs170
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs106
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs4
-rw-r--r--compiler/rustc_mir_transform/src/instcombine.rs5
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs9
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs6
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs4
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs4
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_unneeded_drops.rs5
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs5
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs8
-rw-r--r--compiler/rustc_mir_transform/src/simplify_try.rs19
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs9
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs2
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs4
-rw-r--r--compiler/rustc_parse/src/parser/item.rs3
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs11
-rw-r--r--compiler/rustc_passes/src/check_attr.rs4
-rw-r--r--compiler/rustc_passes/src/check_const.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs26
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs41
-rw-r--r--compiler/rustc_passes/src/liveness.rs2
-rw-r--r--compiler/rustc_passes/src/loops.rs2
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs6
-rw-r--r--compiler/rustc_query_impl/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs9
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs40
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs11
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs37
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs6
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs13
-rw-r--r--compiler/rustc_query_system/src/query/job.rs5
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs1
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs3
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs49
-rw-r--r--compiler/rustc_resolve/src/imports.rs46
-rw-r--r--compiler/rustc_resolve/src/late.rs12
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs4
-rw-r--r--compiler/rustc_resolve/src/lib.rs7
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs6
-rw-r--r--compiler/rustc_session/src/config.rs60
-rw-r--r--compiler/rustc_session/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/options.rs13
-rw-r--r--compiler/rustc_session/src/parse.rs4
-rw-r--r--compiler/rustc_session/src/session.rs71
-rw-r--r--compiler/rustc_span/src/hygiene.rs3
-rw-r--r--compiler/rustc_span/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/source_map.rs7
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs75
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs4
-rw-r--r--compiler/rustc_target/src/asm/mod.rs56
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs14
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs2
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs2
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs2
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs544
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs111
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs70
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs47
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs49
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs75
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs5
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs8
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_type_ir/src/lib.rs9
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs56
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs4
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs31
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs2
-rw-r--r--compiler/rustc_typeck/src/check/check.rs37
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs2
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs54
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs10
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs25
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs4
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs22
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs46
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs46
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs19
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs7
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs42
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs10
-rw-r--r--compiler/rustc_typeck/src/check/inherited.rs1
-rw-r--r--compiler/rustc_typeck/src/check/intrinsicck.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs105
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs23
-rw-r--r--compiler/rustc_typeck/src/check/op.rs6
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs2
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs843
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs12
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs104
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs3
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs6
-rw-r--r--compiler/rustc_typeck/src/coherence/mod.rs43
-rw-r--r--compiler/rustc_typeck/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_typeck/src/constrained_generic_params.rs4
-rw-r--r--compiler/rustc_typeck/src/hir_wf_check.rs4
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs31
-rw-r--r--compiler/rustc_typeck/src/lib.rs17
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs1
-rw-r--r--compiler/rustc_typeck/src/outlives/outlives_bounds.rs8
-rw-r--r--compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs2
-rw-r--r--compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs2
-rw-r--r--compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs6
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs76
-rw-r--r--compiler/rustc_typeck/src/variance/solve.rs3
-rw-r--r--compiler/rustc_typeck/src/variance/terms.rs90
-rw-r--r--library/alloc/src/borrow.rs2
-rw-r--r--library/alloc/src/boxed.rs25
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/macros.rs20
-rw-r--r--library/alloc/src/vec/mod.rs17
-rw-r--r--library/alloc/tests/string.rs126
-rw-r--r--library/alloc/tests/vec.rs166
-rw-r--r--library/alloc/tests/vec_deque.rs161
-rw-r--r--library/core/src/alloc/layout.rs34
-rw-r--r--library/core/src/char/convert.rs4
-rw-r--r--library/core/src/clone.rs3
-rw-r--r--library/core/src/cmp.rs9
-rw-r--r--library/core/src/fmt/mod.rs2
-rw-r--r--library/core/src/future/into_future.rs18
-rw-r--r--library/core/src/future/mod.rs2
-rw-r--r--library/core/src/hash/mod.rs4
-rw-r--r--library/core/src/intrinsics.rs6
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/option.rs6
-rw-r--r--library/core/src/panic/unwind_safe.rs4
-rw-r--r--library/core/src/primitive_docs.rs4
-rw-r--r--library/core/src/ptr/mod.rs83
-rw-r--r--library/core/src/result.rs6
-rw-r--r--library/core/src/slice/raw.rs4
-rw-r--r--library/core/src/sync/atomic.rs387
-rw-r--r--library/core/src/tuple.rs2
-rw-r--r--library/core/tests/atomic.rs85
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/ptr.rs42
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/net/tcp.rs7
-rw-r--r--library/std/src/os/fd/owned.rs31
-rw-r--r--library/std/src/os/fd/raw.rs33
-rw-r--r--library/std/src/os/windows/ffi.rs1
-rw-r--r--library/std/src/os/windows/process.rs23
-rw-r--r--library/std/src/primitive_docs.rs4
-rw-r--r--library/std/src/process.rs16
-rw-r--r--library/std/src/sys/windows/c.rs14
-rw-r--r--library/std/src/sys/windows/handle.rs25
-rw-r--r--library/std/src/sys/windows/handle/tests.rs22
-rw-r--r--library/std/src/sys/windows/process.rs6
-rw-r--r--library/test/src/cli.rs3
-rw-r--r--library/unwind/src/lib.rs1
-rw-r--r--src/bootstrap/CHANGELOG.md1
-rw-r--r--src/bootstrap/Cargo.lock102
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/bin/main.rs18
-rw-r--r--src/bootstrap/bin/rustdoc.rs4
-rw-r--r--src/bootstrap/bootstrap.py45
-rw-r--r--src/bootstrap/builder.rs34
-rw-r--r--src/bootstrap/builder/tests.rs125
-rw-r--r--src/bootstrap/cache.rs123
-rw-r--r--src/bootstrap/check.rs4
-rw-r--r--src/bootstrap/compile.rs141
-rw-r--r--src/bootstrap/config.rs41
-rwxr-xr-xsrc/bootstrap/configure.py7
-rw-r--r--src/bootstrap/dist.rs8
-rw-r--r--src/bootstrap/doc.rs46
-rw-r--r--src/bootstrap/flags.rs13
-rw-r--r--src/bootstrap/format.rs13
-rw-r--r--src/bootstrap/lib.rs32
-rw-r--r--src/bootstrap/native.rs43
-rw-r--r--src/bootstrap/sanity.rs2
-rw-r--r--src/bootstrap/setup.rs17
-rw-r--r--src/bootstrap/test.rs47
-rw-r--r--src/bootstrap/tool.rs16
-rw-r--r--src/bootstrap/toolstate.rs8
-rw-r--r--src/bootstrap/util.rs9
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/shared.sh12
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile1
-rw-r--r--src/ci/docker/scripts/musl.sh2
-rwxr-xr-xsrc/ci/init_repo.sh83
-rwxr-xr-xsrc/ci/run.sh2
-rwxr-xr-xsrc/ci/scripts/checkout-submodules.sh72
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/unstable-book/src/compiler-flags/dwarf-version.md9
-rw-r--r--src/librustdoc/clean/mod.rs6
-rw-r--r--src/librustdoc/clean/utils.rs93
-rw-r--r--src/librustdoc/config.rs31
-rw-r--r--src/librustdoc/core.rs7
-rw-r--r--src/librustdoc/html/format.rs30
-rw-r--r--src/librustdoc/html/render/mod.rs92
-rw-r--r--src/librustdoc/html/render/print_item.rs78
-rw-r--r--src/librustdoc/html/static/.eslintrc.js1
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css84
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css5
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css9
-rw-r--r--src/librustdoc/html/static/css/themes/light.css12
-rw-r--r--src/librustdoc/html/static/js/source-script.js48
-rw-r--r--src/librustdoc/html/static/js/storage.js5
-rw-r--r--src/librustdoc/lib.rs41
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs8
-rw-r--r--src/librustdoc/scrape_examples.rs2
m---------src/llvm-project0
-rw-r--r--src/stage0.json676
-rw-r--r--src/test/assembly/dwarf5.rs20
-rw-r--r--src/test/codegen/consts.rs2
-rw-r--r--src/test/codegen/enum-bounds-check-derived-idx.rs6
-rw-r--r--src/test/codegen/enum-bounds-check-issue-13926.rs3
-rw-r--r--src/test/codegen/enum-bounds-check-issue-82871.rs9
-rw-r--r--src/test/codegen/enum-bounds-check.rs3
-rw-r--r--src/test/codegen/generator-debug-msvc.rs4
-rw-r--r--src/test/codegen/generator-debug.rs4
-rw-r--r--src/test/codegen/issue-37945.rs8
-rw-r--r--src/test/codegen/issue-75659.rs2
-rw-r--r--src/test/codegen/mem-replace-direct-memcpy.rs12
-rw-r--r--src/test/codegen/remap_path_prefix/main.rs2
-rw-r--r--src/test/codegen/simd-wide-sum.rs7
-rw-r--r--src/test/codegen/slice-ref-equality.rs2
-rw-r--r--src/test/codegen/swap-small-types.rs7
-rw-r--r--src/test/codegen/vec-in-place.rs10
-rw-r--r--src/test/incremental/async-lifetimes.rs19
-rw-r--r--src/test/incremental/split_debuginfo_cached.rs25
-rw-r--r--src/test/incremental/split_debuginfo_mode.rs33
-rw-r--r--src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir2
-rw-r--r--src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir2
-rw-r--r--src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir6
-rw-r--r--src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff118
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/boxes.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff4
-rw-r--r--src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff4
-rw-r--r--src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff2
-rw-r--r--src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff2
-rw-r--r--src/test/mir-opt/derefer_complex_case.main.Derefer.diff6
-rw-r--r--src/test/mir-opt/derefer_inline_test.main.Derefer.diff6
-rw-r--r--src/test/mir-opt/derefer_terminator_test.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff6
-rw-r--r--src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff2
-rw-r--r--src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff2
-rw-r--r--src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff2
-rw-r--r--src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff2
-rw-r--r--src/test/mir-opt/enum_cast.bar.mir_map.0.mir13
-rw-r--r--src/test/mir-opt/enum_cast.boo.mir_map.0.mir13
-rw-r--r--src/test/mir-opt/enum_cast.droppy.mir_map.0.mir54
-rw-r--r--src/test/mir-opt/enum_cast.foo.mir_map.0.mir13
-rw-r--r--src/test/mir-opt/enum_cast.rs50
-rw-r--r--src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff8
-rw-r--r--src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir32
-rw-r--r--src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir12
-rw-r--r--src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir34
-rw-r--r--src/test/mir-opt/inline/caller-with-trivial-bound.rs26
-rw-r--r--src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff33
-rw-r--r--src/test/mir-opt/inline/cycle.f.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/cycle.g.Inline.diff9
-rw-r--r--src/test/mir-opt/inline/cycle.main.Inline.diff9
-rw-r--r--src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff6
-rw-r--r--src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir8
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_cycle.one.Inline.diff11
-rw-r--r--src/test/mir-opt/inline/inline_cycle.two.Inline.diff25
-rw-r--r--src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff20
-rw-r--r--src/test/mir-opt/inline/inline_diverging.f.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_diverging.g.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_diverging.h.Inline.diff21
-rw-r--r--src/test/mir-opt/inline/inline_generator.main.Inline.diff72
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff6
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff6
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff6
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff6
-rw-r--r--src/test/mir-opt/inline/inline_options.main.Inline.after.mir8
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_shims.clone.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_shims.drop.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_specialization.main.Inline.diff2
-rw-r--r--src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir2
-rw-r--r--src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff6
-rw-r--r--src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff2
-rw-r--r--src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir4
-rw-r--r--src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir2
-rw-r--r--src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir2
-rw-r--r--src/test/mir-opt/issue_49232.main.mir_map.0.mir2
-rw-r--r--src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir6
-rw-r--r--src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir2
-rw-r--r--src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir2
-rw-r--r--src/test/mir-opt/issue_72181_1.main.mir_map.0.mir4
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff2
-rw-r--r--src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff2
-rw-r--r--src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir6
-rw-r--r--src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff8
-rw-r--r--src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir2
-rw-r--r--src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir7
-rw-r--r--src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff6
-rw-r--r--src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff2
-rw-r--r--src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir2
-rw-r--r--src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir2
-rw-r--r--src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir4
-rw-r--r--src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir12
-rw-r--r--src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir12
-rw-r--r--src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir2
-rw-r--r--src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir4
-rw-r--r--src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir6
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff2
-rw-r--r--src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir6
-rw-r--r--src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir2
-rw-r--r--src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir6
-rw-r--r--src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir8
-rw-r--r--src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff2
-rw-r--r--src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff2
-rw-r--r--src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff2
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff19
-rw-r--r--src/test/mir-opt/simplify_match.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir4
-rw-r--r--src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir4
-rw-r--r--src/test/mir-opt/unreachable.main.UnreachablePropagation.diff2
-rw-r--r--src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff4
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir10
-rw-r--r--src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir10
-rw-r--r--src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir2
-rw-r--r--src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir2
-rw-r--r--src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir4
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt16
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt2
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt4
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt4
-rw-r--r--src/test/run-make/const_fn_mir/dump.mir2
-rw-r--r--src/test/run-make/issue-88756-default-output/output-default.stdout3
-rw-r--r--src/test/run-make/issue-88756-opt-help/Makefile4
-rw-r--r--src/test/run-make/issue-88756-opt-help/README.md1
-rw-r--r--src/test/run-make/issue-88756-opt-help/output-default.stdout193
-rw-r--r--src/test/run-make/issue-88756-opt-help/x.rs1
-rw-r--r--src/test/run-make/native-link-modifier-bundle/Makefile24
-rw-r--r--src/test/run-pass-valgrind/cast-enum-with-dtor.rs2
-rw-r--r--src/test/rustdoc-gui/anchors.goml4
-rw-r--r--src/test/rustdoc-gui/headers-color.goml12
-rw-r--r--src/test/rustdoc-gui/headings.goml12
-rw-r--r--src/test/rustdoc-gui/implementors.goml16
-rw-r--r--src/test/rustdoc-gui/item-info-overflow.goml11
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml28
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml142
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml23
-rw-r--r--src/test/rustdoc-gui/toggle-click-deadspace.goml2
-rw-r--r--src/test/rustdoc-ui/deny-missing-docs-crate.stderr2
-rw-r--r--src/test/rustdoc-ui/diagnostic-width.rs5
-rw-r--r--src/test/rustdoc-ui/diagnostic-width.stderr15
-rw-r--r--src/test/rustdoc-ui/issue-79467.rs8
-rw-r--r--src/test/rustdoc-ui/issue-79467.stderr9
-rw-r--r--src/test/rustdoc-ui/issue-79494.rs5
-rw-r--r--src/test/rustdoc-ui/issue-79494.stderr12
-rw-r--r--src/test/rustdoc-ui/issue-83883-describe-lints.rs4
-rw-r--r--src/test/rustdoc-ui/issue-83883-describe-lints.stdout215
-rw-r--r--src/test/rustdoc/anchors.no_const_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_const_anchor2.html1
-rw-r--r--src/test/rustdoc/anchors.no_method_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_trait_method_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_tymethod_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_type_anchor.html1
-rw-r--r--src/test/rustdoc/anchors.no_type_anchor2.html1
-rw-r--r--src/test/rustdoc/anchors.rs49
-rw-r--r--src/test/rustdoc/assoc-consts.rs4
-rw-r--r--src/test/rustdoc/assoc-types.rs2
-rw-r--r--src/test/rustdoc/auto-trait-not-send.rs4
-rw-r--r--src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs8
-rw-r--r--src/test/rustdoc/blanket-reexport-item.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generics-docs.rs4
-rw-r--r--src/test/rustdoc/const-generics/const-impl.rs10
-rw-r--r--src/test/rustdoc/const-value-display.rs4
-rw-r--r--src/test/rustdoc/decl-trailing-whitespace.declaration.html7
-rw-r--r--src/test/rustdoc/decl-trailing-whitespace.rs30
-rw-r--r--src/test/rustdoc/double-quote-escape.rs3
-rw-r--r--src/test/rustdoc/empty-impls.rs6
-rw-r--r--src/test/rustdoc/generic-impl.rs6
-rw-r--r--src/test/rustdoc/hidden-trait-struct-impls.rs6
-rw-r--r--src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs82
-rw-r--r--src/test/rustdoc/hide-complex-unevaluated-consts.rs71
-rw-r--r--src/test/rustdoc/impl-box.rs2
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs14
-rw-r--r--src/test/rustdoc/issue-29503.rs2
-rw-r--r--src/test/rustdoc/issue-75588.rs2
-rw-r--r--src/test/rustdoc/issue-78701.rs4
-rw-r--r--src/test/rustdoc/issue-98697.rs4
-rw-r--r--src/test/rustdoc/primitive/primitive-generic-impl.rs2
-rw-r--r--src/test/rustdoc/rfc-2632-const-trait-impl.rs9
-rw-r--r--src/test/rustdoc/show-const-contents.rs2
-rw-r--r--src/test/rustdoc/sized_trait.rs2
-rw-r--r--src/test/rustdoc/src-links-auto-impls.rs12
-rw-r--r--src/test/rustdoc/trait-impl.rs2
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.enum.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.enum2.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.rs77
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.struct.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.struct2.html4
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.trait.html6
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.trait2.html6
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.union.html3
-rw-r--r--src/test/rustdoc/whitespace-after-where-clause.union2.html3
-rw-r--r--src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr2
-rw-r--r--src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs81
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs21
-rw-r--r--src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr138
-rw-r--r--src/test/ui/abi/rustcall-generic.rs3
-rw-r--r--src/test/ui/aligned_enum_cast.rs12
-rw-r--r--src/test/ui/asm/aarch64/type-check-2-2.rs4
-rw-r--r--src/test/ui/asm/aarch64/type-check-2-2.stderr12
-rw-r--r--src/test/ui/asm/aarch64/type-check-2.stderr2
-rw-r--r--src/test/ui/asm/x86_64/type-check-2.stderr2
-rw-r--r--src/test/ui/asm/x86_64/type-check-5.rs4
-rw-r--r--src/test/ui/asm/x86_64/type-check-5.stderr12
-rw-r--r--src/test/ui/associated-item/associated-item-enum.stderr6
-rw-r--r--src/test/ui/async-await/await-into-future.rs2
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr7
-rw-r--r--src/test/ui/async-await/issue-70935-complex-spans.normal.stderr2
-rw-r--r--src/test/ui/async-await/issues/issue-62009-1.stderr10
-rw-r--r--src/test/ui/async-await/no-non-guaranteed-initialization.rs3
-rw-r--r--src/test/ui/async-await/no-non-guaranteed-initialization.stderr11
-rw-r--r--src/test/ui/async-await/partial-initialization-across-await.rs9
-rw-r--r--src/test/ui/async-await/partial-initialization-across-await.stderr28
-rw-r--r--src/test/ui/async-await/pin-needed-to-poll.stderr2
-rw-r--r--src/test/ui/block-result/issue-20862.stderr2
-rw-r--r--src/test/ui/bogus-tag.stderr2
-rw-r--r--src/test/ui/borrowck/assign_mutable_fields.stderr16
-rw-r--r--src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr16
-rw-r--r--src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr47
-rw-r--r--src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr36
-rw-r--r--src/test/ui/borrowck/borrowck-and-init.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-and-init.stderr9
-rw-r--r--src/test/ui/borrowck/borrowck-block-unint.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-block-unint.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit-2.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit-2.stderr7
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-break-uninit.stderr7
-rw-r--r--src/test/ui/borrowck/borrowck-field-sensitivity.rs6
-rw-r--r--src/test/ui/borrowck/borrowck-field-sensitivity.stderr24
-rw-r--r--src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs7
-rw-r--r--src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr13
-rw-r--r--src/test/ui/borrowck/borrowck-if-no-else.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-if-no-else.stderr9
-rw-r--r--src/test/ui/borrowck/borrowck-if-with-else.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-if-with-else.stderr9
-rw-r--r--src/test/ui/borrowck/borrowck-in-static.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fn-expr.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fru.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-init-in-fru.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-init-op-equal.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-init-op-equal.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-init-plus-equal.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-init-plus-equal.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-move-by-capture.stderr22
-rw-r--r--src/test/ui/borrowck/borrowck-or-init.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-or-init.stderr9
-rw-r--r--src/test/ui/borrowck/borrowck-partial-reinit-4.rs3
-rw-r--r--src/test/ui/borrowck/borrowck-partial-reinit-4.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-return.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-return.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-storage-dead.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-after-item.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-after-item.stderr7
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-field-access.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-in-assignop.rs20
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr60
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-ref-chain.rs14
-rw-r--r--src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr50
-rw-r--r--src/test/ui/borrowck/borrowck-uninit.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-uninit.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-union-uninitialized.rs4
-rw-r--r--src/test/ui/borrowck/borrowck-union-uninitialized.stderr18
-rw-r--r--src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr12
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-while-break.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-while-break.stderr9
-rw-r--r--src/test/ui/borrowck/borrowck-while-cond.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-while-cond.stderr6
-rw-r--r--src/test/ui/borrowck/borrowck-while.rs2
-rw-r--r--src/test/ui/borrowck/borrowck-while.stderr8
-rw-r--r--src/test/ui/borrowck/disallow-possibly-uninitialized.rs8
-rw-r--r--src/test/ui/borrowck/disallow-possibly-uninitialized.stderr32
-rw-r--r--src/test/ui/borrowck/issue-24267-flow-exit.rs4
-rw-r--r--src/test/ui/borrowck/issue-24267-flow-exit.stderr14
-rw-r--r--src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr2
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs6
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr24
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs6
-rw-r--r--src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr24
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.rs2
-rw-r--r--src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr6
-rw-r--r--src/test/ui/borrowck/issue-81899.stderr2
-rw-r--r--src/test/ui/borrowck/issue-87456-point-to-closure.stderr24
-rw-r--r--src/test/ui/borrowck/issue-88434-minimal-example.stderr2
-rw-r--r--src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr2
-rw-r--r--src/test/ui/borrowck/mutability-errors.stderr174
-rw-r--r--src/test/ui/borrowck/reassignment_immutable_fields.stderr16
-rw-r--r--src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr8
-rw-r--r--src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr8
-rw-r--r--src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr19
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs17
-rw-r--r--src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr53
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr12
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr4
-rw-r--r--src/test/ui/closures/closure-move-sync.stderr10
-rw-r--r--src/test/ui/closures/closure-no-fn-1.stderr2
-rw-r--r--src/test/ui/closures/closure-no-fn-2.stderr2
-rw-r--r--src/test/ui/closures/closure-no-fn-3.stderr2
-rw-r--r--src/test/ui/closures/closure-no-fn-4.stderr2
-rw-r--r--src/test/ui/closures/closure-no-fn-5.stderr2
-rw-r--r--src/test/ui/closures/closure-reform-bad.stderr4
-rw-r--r--src/test/ui/closures/closure-wrong-kind.stderr5
-rw-r--r--src/test/ui/closures/closure_cap_coerce_many_fail.stderr20
-rw-r--r--src/test/ui/closures/print/closure-print-generic-1.stderr2
-rw-r--r--src/test/ui/closures/print/closure-print-generic-2.stderr4
-rw-r--r--src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr2
-rw-r--r--src/test/ui/closures/print/closure-print-generic-verbose-2.stderr2
-rw-r--r--src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr6
-rw-r--r--src/test/ui/coherence/coherence-projection-conflict-orphan.stderr1
-rw-r--r--src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs19
-rw-r--r--src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr14
-rw-r--r--src/test/ui/confuse-field-and-method/issue-18343.stderr2
-rw-r--r--src/test/ui/confuse-field-and-method/issue-2392.stderr22
-rw-r--r--src/test/ui/confuse-field-and-method/issue-32128.stderr2
-rw-r--r--src/test/ui/confuse-field-and-method/issue-33784.stderr4
-rw-r--r--src/test/ui/confuse-field-and-method/private-field.stderr2
-rw-r--r--src/test/ui/const-generics/const-generic-default-wont-borrowck.rs3
-rw-r--r--src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr6
-rw-r--r--src/test/ui/const-generics/float-generic.adt_const_params.stderr11
-rw-r--r--src/test/ui/const-generics/float-generic.rs12
-rw-r--r--src/test/ui/const-generics/float-generic.simple.stderr11
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs25
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr19
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs23
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr19
-rw-r--r--src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr2
-rw-r--r--src/test/ui/const-generics/issue-70408.rs13
-rw-r--r--src/test/ui/const-generics/issue-80471.rs13
-rw-r--r--src/test/ui/const-generics/issue-80471.stderr18
-rw-r--r--src/test/ui/const-ptr/allowed_slices.rs1
-rw-r--r--src/test/ui/const-ptr/forbidden_slices.32bit.stderr66
-rw-r--r--src/test/ui/const-ptr/forbidden_slices.64bit.stderr66
-rw-r--r--src/test/ui/const-ptr/forbidden_slices.rs1
-rw-r--r--src/test/ui/consts/const-deref-ptr.stderr2
-rw-r--r--src/test/ui/consts/const-enum-cast.rs15
-rw-r--r--src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr4
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs4
-rw-r--r--src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr4
-rw-r--r--src/test/ui/consts/const-eval/issue-91827-extern-types.rs1
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr4
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr2
-rw-r--r--src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr2
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs2
-rw-r--r--src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr2
-rw-r--r--src/test/ui/consts/const-needs_drop-monomorphic.stderr2
-rw-r--r--src/test/ui/consts/const-size_of_val-align_of_val.rs1
-rw-r--r--src/test/ui/consts/issue-50439.rs29
-rw-r--r--src/test/ui/consts/issue-50439.stderr10
-rw-r--r--src/test/ui/consts/issue-78655.rs2
-rw-r--r--src/test/ui/consts/issue-78655.stderr6
-rw-r--r--src/test/ui/consts/issue-96169.rs18
-rw-r--r--src/test/ui/consts/offset_from_ub.rs4
-rw-r--r--src/test/ui/consts/offset_from_ub.stderr10
-rw-r--r--src/test/ui/consts/offset_ub.stderr14
-rw-r--r--src/test/ui/consts/ptr_comparisons.stderr2
-rw-r--r--src/test/ui/copy-a-resource.stderr2
-rw-r--r--src/test/ui/dep-graph/dep-graph-struct-signature.stderr72
-rw-r--r--src/test/ui/dep-graph/dep-graph-type-alias.stderr36
-rw-r--r--src/test/ui/derives/derive-assoc-type-not-impl.stderr4
-rw-r--r--src/test/ui/derives/issue-91492.stderr2
-rw-r--r--src/test/ui/derives/issue-91550.stderr6
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.rs25
-rw-r--r--src/test/ui/deriving/deriving-all-codegen.stdout1123
-rw-r--r--src/test/ui/diagnostic-width/flag-human.rs9
-rw-r--r--src/test/ui/diagnostic-width/flag-human.stderr (renamed from src/test/ui/terminal-width/flag-human.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/flag-json.rs9
-rw-r--r--src/test/ui/diagnostic-width/flag-json.stderr (renamed from src/test/ui/terminal-width/flag-json.stderr)2
-rw-r--r--src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs (renamed from src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs)0
-rw-r--r--src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr (renamed from src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming-2.rs (renamed from src/test/ui/terminal-width/non-whitespace-trimming-2.rs)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming-2.stderr (renamed from src/test/ui/terminal-width/non-whitespace-trimming-2.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.rs (renamed from src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr (renamed from src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming.rs (renamed from src/test/ui/terminal-width/non-whitespace-trimming.rs)0
-rw-r--r--src/test/ui/diagnostic-width/non-whitespace-trimming.stderr (renamed from src/test/ui/terminal-width/non-whitespace-trimming.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/tabs-trimming.rs (renamed from src/test/ui/terminal-width/tabs-trimming.rs)0
-rw-r--r--src/test/ui/diagnostic-width/tabs-trimming.stderr (renamed from src/test/ui/terminal-width/tabs-trimming.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/whitespace-trimming-2.rs (renamed from src/test/ui/terminal-width/whitespace-trimming-2.rs)0
-rw-r--r--src/test/ui/diagnostic-width/whitespace-trimming-2.stderr (renamed from src/test/ui/terminal-width/whitespace-trimming-2.stderr)0
-rw-r--r--src/test/ui/diagnostic-width/whitespace-trimming.rs (renamed from src/test/ui/terminal-width/whitespace-trimming.rs)0
-rw-r--r--src/test/ui/diagnostic-width/whitespace-trimming.stderr (renamed from src/test/ui/terminal-width/whitespace-trimming.stderr)0
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr2
-rw-r--r--src/test/ui/dont-suggest-private-trait-method.stderr2
-rw-r--r--src/test/ui/drop/repeat-drop-2.rs2
-rw-r--r--src/test/ui/drop/repeat-drop-2.stderr6
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs1
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr10
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs1
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr10
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs3
-rw-r--r--src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr10
-rw-r--r--src/test/ui/empty/empty-struct-braces-pat-3.stderr4
-rw-r--r--src/test/ui/empty/empty-struct-tuple-pat.stderr12
-rw-r--r--src/test/ui/empty/empty-struct-unit-pat.stderr4
-rw-r--r--src/test/ui/enum/suggest-default-attribute.rs8
-rw-r--r--src/test/ui/enum/suggest-default-attribute.stderr14
-rw-r--r--src/test/ui/error-codes/E0396-fixed.stderr2
-rw-r--r--src/test/ui/error-codes/E0599.stderr2
-rw-r--r--src/test/ui/extern/not-in-block.rs6
-rw-r--r--src/test/ui/extern/not-in-block.stderr32
-rw-r--r--src/test/ui/fn/fn-closure-mutable-capture.rs1
-rw-r--r--src/test/ui/fn/fn-closure-mutable-capture.stderr5
-rw-r--r--src/test/ui/functions-closures/fn-help-with-err.stderr4
-rw-r--r--src/test/ui/generator/drop-yield-twice.stderr2
-rw-r--r--src/test/ui/generator/generator-yielding-or-returning-itself.stderr4
-rw-r--r--src/test/ui/generator/issue-68112.stderr15
-rw-r--r--src/test/ui/generator/not-send-sync.stderr11
-rw-r--r--src/test/ui/generator/partial-drop.stderr6
-rw-r--r--src/test/ui/generator/partial-initialization-across-yield.rs9
-rw-r--r--src/test/ui/generator/partial-initialization-across-yield.stderr28
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.stderr15
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-2.stderr9
-rw-r--r--src/test/ui/generator/static-not-unpin.stderr4
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr2
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.rs1
-rw-r--r--src/test/ui/generic-associated-types/issue-91139.stderr14
-rw-r--r--src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr4
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.stderr2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr8
-rw-r--r--src/test/ui/hrtb/issue-30786.stderr28
-rw-r--r--src/test/ui/hrtb/issue-62203-hrtb-ice.stderr8
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak.rs1
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak.stderr112
-rw-r--r--src/test/ui/impl-trait/auto-trait-leak2.stderr4
-rw-r--r--src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr2
-rw-r--r--src/test/ui/impl-trait/issues/issue-62742.stderr2
-rw-r--r--src/test/ui/impl-trait/issues/issue-74282.stderr2
-rw-r--r--src/test/ui/impl-trait/method-suggestion-no-duplication.stderr2
-rw-r--r--src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr2
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait.stderr2
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait2.stderr2
-rw-r--r--src/test/ui/impl-trait/nested-return-type2-tait3.stderr2
-rw-r--r--src/test/ui/impl-trait/nested-return-type2.stderr2
-rw-r--r--src/test/ui/impl-trait/no-method-suggested-traits.stderr6
-rw-r--r--src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr12
-rw-r--r--src/test/ui/impl-trait/static-return-lifetime-infered.stderr8
-rw-r--r--src/test/ui/imports/inaccessible_type_aliases.rs14
-rw-r--r--src/test/ui/imports/inaccessible_type_aliases.stderr30
-rw-r--r--src/test/ui/inference/ambiguous_type_parameter.stderr7
-rw-r--r--src/test/ui/inference/cannot-infer-partial-try-return.rs2
-rw-r--r--src/test/ui/inference/cannot-infer-partial-try-return.stderr15
-rw-r--r--src/test/ui/inference/need_type_info/channel.rs19
-rw-r--r--src/test/ui/inference/need_type_info/channel.stderr25
-rw-r--r--src/test/ui/infinite/infinite-autoderef.stderr2
-rw-r--r--src/test/ui/infinite/infinite-struct.rs1
-rw-r--r--src/test/ui/infinite/infinite-struct.stderr14
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.rs1
-rw-r--r--src/test/ui/infinite/infinite-tag-type-recursion.stderr14
-rw-r--r--src/test/ui/interior-mutability/interior-mutability.stderr2
-rw-r--r--src/test/ui/intrinsics/const-eval-select-bad.stderr10
-rw-r--r--src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr2
-rw-r--r--src/test/ui/issues/issue-12127.stderr2
-rw-r--r--src/test/ui/issues/issue-19692.stderr2
-rw-r--r--src/test/ui/issues/issue-21600.stderr31
-rw-r--r--src/test/ui/issues/issue-21974.stderr8
-rw-r--r--src/test/ui/issues/issue-22933-2.stderr2
-rw-r--r--src/test/ui/issues/issue-23041.stderr9
-rw-r--r--src/test/ui/issues/issue-23173.stderr8
-rw-r--r--src/test/ui/issues/issue-23217.stderr2
-rw-r--r--src/test/ui/issues/issue-24013.stderr9
-rw-r--r--src/test/ui/issues/issue-24036.stderr6
-rw-r--r--src/test/ui/issues/issue-24424.stderr6
-rw-r--r--src/test/ui/issues/issue-25368.rs4
-rw-r--r--src/test/ui/issues/issue-25368.stderr14
-rw-r--r--src/test/ui/issues/issue-2823.stderr2
-rw-r--r--src/test/ui/issues/issue-28971.stderr2
-rw-r--r--src/test/ui/issues/issue-3044.rs3
-rw-r--r--src/test/ui/issues/issue-3044.stderr18
-rw-r--r--src/test/ui/issues/issue-31173.stderr14
-rw-r--r--src/test/ui/issues/issue-34209.stderr2
-rw-r--r--src/test/ui/issues/issue-37884.stderr9
-rw-r--r--src/test/ui/issues/issue-41880.stderr4
-rw-r--r--src/test/ui/issues/issue-4335.stderr5
-rw-r--r--src/test/ui/issues/issue-48838.stderr2
-rw-r--r--src/test/ui/issues/issue-50600.stderr2
-rw-r--r--src/test/ui/issues/issue-50688.stderr2
-rw-r--r--src/test/ui/issues/issue-51154.stderr2
-rw-r--r--src/test/ui/issues/issue-64430.stderr2
-rw-r--r--src/test/ui/issues/issue-67552.rs1
-rw-r--r--src/test/ui/issues/issue-67552.stderr4
-rw-r--r--src/test/ui/issues/issue-77919.stderr2
-rw-r--r--src/test/ui/issues/issue-7950.stderr2
-rw-r--r--src/test/ui/kindck/kindck-nonsendable-1.stderr6
-rw-r--r--src/test/ui/layout/issue-96185-overaligned-enum.rs19
-rw-r--r--src/test/ui/layout/issue-96185-overaligned-enum.stderr172
-rw-r--r--src/test/ui/lifetimes/issue-34979.stderr8
-rw-r--r--src/test/ui/lifetimes/issue-79187-2.stderr2
-rw-r--r--src/test/ui/lifetimes/issue-79187.stderr2
-rw-r--r--src/test/ui/lint/lint-missing-doc.stderr16
-rw-r--r--src/test/ui/lint/trivial_casts.stderr2
-rw-r--r--src/test/ui/loops/loop-proper-liveness.rs2
-rw-r--r--src/test/ui/loops/loop-proper-liveness.stderr7
-rw-r--r--src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr6
-rw-r--r--src/test/ui/methods/method-call-err-msg.stderr4
-rw-r--r--src/test/ui/methods/method-missing-call.stderr2
-rw-r--r--src/test/ui/methods/method-not-found-generic-arg-elision.stderr16
-rw-r--r--src/test/ui/mir/drop-elaboration-after-borrowck-error.rs2
-rw-r--r--src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr7
-rw-r--r--src/test/ui/mir/ssa-analysis-regression-50041.rs4
-rw-r--r--src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr6
-rw-r--r--src/test/ui/mismatched_types/closure-mismatch.stderr2
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr18
-rw-r--r--src/test/ui/mismatched_types/issue-47706.stderr2
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.rs12
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.stderr13
-rw-r--r--src/test/ui/moves/move-into-dead-array-1.rs2
-rw-r--r--src/test/ui/moves/move-into-dead-array-1.stderr6
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.rs2
-rw-r--r--src/test/ui/moves/move-of-addr-of-mut.stderr6
-rw-r--r--src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr5
-rw-r--r--src/test/ui/namespace/namespace-mix.stderr2
-rw-r--r--src/test/ui/never_type/fallback-closure-wrap.fallback.stderr4
-rw-r--r--src/test/ui/nll/closure-captures.stderr132
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument-callee.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr10
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr8
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr9
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr15
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr10
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr10
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr9
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr8
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr9
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr9
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr11
-rw-r--r--src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr2
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs12
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr42
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-use.rs36
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-use.stderr140
-rw-r--r--src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr5
-rw-r--r--src/test/ui/nll/issue-54556-stephaneyfx.stderr2
-rw-r--r--src/test/ui/nll/issue-98693.rs21
-rw-r--r--src/test/ui/nll/issue-98693.stderr17
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.rs2
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr10
-rw-r--r--src/test/ui/nll/match-on-borrowed.stderr6
-rw-r--r--src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr8
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr10
-rw-r--r--src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr10
-rw-r--r--src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr16
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr4
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr2
-rw-r--r--src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr39
-rw-r--r--src/test/ui/nll/user-annotations/adt-nullary-enums.stderr5
-rw-r--r--src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr10
-rw-r--r--src/test/ui/nll/user-annotations/fns.stderr6
-rw-r--r--src/test/ui/nll/user-annotations/method-call.stderr5
-rw-r--r--src/test/ui/nll/user-annotations/method-ufcs-3.stderr5
-rw-r--r--src/test/ui/no-send-res-ports.stderr24
-rw-r--r--src/test/ui/non-fmt-panic.stderr100
-rw-r--r--src/test/ui/noncopyable-class.stderr2
-rw-r--r--src/test/ui/not-clone-closure.stderr22
-rw-r--r--src/test/ui/panic-runtime/auxiliary/needs-abort.rs5
-rw-r--r--src/test/ui/panic-runtime/auxiliary/needs-unwind.rs13
-rw-r--r--src/test/ui/panic-runtime/need-abort-got-unwind.rs9
-rw-r--r--src/test/ui/panic-runtime/need-abort-got-unwind.stderr4
-rw-r--r--src/test/ui/panic-runtime/need-unwind-got-abort.rs9
-rw-r--r--src/test/ui/panic-runtime/need-unwind-got-abort.stderr4
-rw-r--r--src/test/ui/panic-runtime/transitive-link-a-bunch.stderr6
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort.rs2
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort.stderr4
-rw-r--r--src/test/ui/panic-runtime/want-unwind-got-abort2.stderr6
-rw-r--r--src/test/ui/panics/location-detail-unwrap-no-file.rs2
-rw-r--r--src/test/ui/parser/emoji-identifiers.stderr2
-rw-r--r--src/test/ui/parser/expr-as-stmt.stderr2
-rw-r--r--src/test/ui/parser/macro/macro-doc-comments-1.stderr5
-rw-r--r--src/test/ui/parser/macro/macro-doc-comments-2.stderr5
-rw-r--r--src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr2
-rw-r--r--src/test/ui/pattern/non-structural-match-types.stderr2
-rw-r--r--src/test/ui/pattern/pat-tuple-field-count-cross.stderr13
-rw-r--r--src/test/ui/pattern/pat-tuple-overfield.stderr9
-rw-r--r--src/test/ui/pattern/pattern-binding-disambiguation.stderr10
-rw-r--r--src/test/ui/polymorphization/const_parameters/closures.stderr6
-rw-r--r--src/test/ui/polymorphization/generators.rs2
-rw-r--r--src/test/ui/polymorphization/generators.stderr28
-rw-r--r--src/test/ui/polymorphization/lifetimes.stderr2
-rw-r--r--src/test/ui/polymorphization/predicates.rs3
-rw-r--r--src/test/ui/polymorphization/predicates.stderr16
-rw-r--r--src/test/ui/polymorphization/type_parameters/closures.stderr32
-rw-r--r--src/test/ui/polymorphization/unsized_cast.stderr25
-rw-r--r--src/test/ui/proc-macro/auxiliary/expand-expr.rs71
-rw-r--r--src/test/ui/proc-macro/parent-source-spans.stderr6
-rw-r--r--src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs14
-rw-r--r--src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr15
-rw-r--r--src/test/ui/recursion/issue-83150.rs3
-rw-r--r--src/test/ui/recursion/issue-83150.stderr6
-rw-r--r--src/test/ui/recursion/issue-86784.rs2597
-rw-r--r--src/test/ui/repr/repr-transparent.stderr2
-rw-r--r--src/test/ui/resolve/issue-55673.rs12
-rw-r--r--src/test/ui/resolve/issue-55673.stderr9
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr6
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/variant.stderr6
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs6
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr24
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr4
-rw-r--r--src/test/ui/rust-2018/uniform-paths/issue-87932.stderr2
-rw-r--r--src/test/ui/self/point-at-arbitrary-self-type-method.stderr2
-rw-r--r--src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr2
-rw-r--r--src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr17
-rw-r--r--src/test/ui/span/issue-7575.stderr2
-rw-r--r--src/test/ui/span/move-closure.stderr2
-rw-r--r--src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr4
-rw-r--r--src/test/ui/specialization/min_specialization/repeated_projection_type.stderr6
-rw-r--r--src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr4
-rw-r--r--src/test/ui/specialization/min_specialization/specialization_super_trait.stderr4
-rw-r--r--src/test/ui/specialization/min_specialization/specialization_trait.stderr4
-rw-r--r--src/test/ui/specialization/min_specialization/specialize_on_trait.stderr4
-rw-r--r--src/test/ui/stability-attribute/missing-const-stability.stderr12
-rw-r--r--src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr8
-rw-r--r--src/test/ui/suggestions/auxiliary/meow.rs11
-rw-r--r--src/test/ui/suggestions/derive-trait-for-method-call.stderr6
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr657
-rw-r--r--src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr2
-rw-r--r--src/test/ui/suggestions/field-has-method.stderr2
-rw-r--r--src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr4
-rw-r--r--src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr6
-rw-r--r--src/test/ui/suggestions/issue-84973-blacklist.stderr4
-rw-r--r--src/test/ui/suggestions/issue-99080.rs16
-rw-r--r--src/test/ui/suggestions/issue-99080.stderr20
-rw-r--r--src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr2
-rw-r--r--src/test/ui/suggestions/option-content-move2.stderr29
-rw-r--r--src/test/ui/suggestions/parenthesized-deref-suggestion.rs (renamed from src/test/ui/parenthesized-deref-suggestion.rs)0
-rw-r--r--src/test/ui/suggestions/parenthesized-deref-suggestion.stderr (renamed from src/test/ui/parenthesized-deref-suggestion.stderr)0
-rw-r--r--src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr2
-rw-r--r--src/test/ui/suggestions/suggest-box.stderr2
-rw-r--r--src/test/ui/suggestions/suggest-methods.stderr2
-rw-r--r--src/test/ui/suggestions/suggest-on-bare-closure-call.rs7
-rw-r--r--src/test/ui/suggestions/suggest-on-bare-closure-call.stderr17
-rw-r--r--src/test/ui/suggestions/suggest-variants.stderr12
-rw-r--r--src/test/ui/suggestions/unnamable-types.stderr6
-rw-r--r--src/test/ui/suggestions/use-placement-typeck.stderr2
-rw-r--r--src/test/ui/terminal-width/flag-human.rs9
-rw-r--r--src/test/ui/terminal-width/flag-json.rs9
-rw-r--r--src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs33
-rw-r--r--src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr31
-rw-r--r--src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs36
-rw-r--r--src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr31
-rw-r--r--src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs43
-rw-r--r--src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr18
-rw-r--r--src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr1
-rw-r--r--src/test/ui/traits/issue-3973.stderr2
-rw-r--r--src/test/ui/traits/issue-59029-1.stderr4
-rw-r--r--src/test/ui/traits/issue-85735.stderr9
-rw-r--r--src/test/ui/traits/issue-91949-hangs-on-recursion.rs1
-rw-r--r--src/test/ui/traits/issue-91949-hangs-on-recursion.stderr4
-rw-r--r--src/test/ui/traits/item-privacy.stderr12
-rw-r--r--src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr4
-rw-r--r--src/test/ui/try-block/try-block-opt-init.rs2
-rw-r--r--src/test/ui/try-block/try-block-opt-init.stderr10
-rw-r--r--src/test/ui/tuple/wrong_argument_ice-4.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/inference-cycle.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/inference-cycle.stderr27
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53092-2.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-63279.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-94429.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-98604.rs13
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-98604.stderr18
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-98608.rs9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-98608.stderr16
-rw-r--r--src/test/ui/type-alias-impl-trait/not_well_formed.stderr2
-rw-r--r--src/test/ui/type-alias-impl-trait/reveal_local.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/reveal_local.stderr33
-rw-r--r--src/test/ui/type/type-check/issue-40294.stderr8
-rw-r--r--src/test/ui/type_length_limit.rs2
-rw-r--r--src/test/ui/typeck/issue-91334.stderr2
-rw-r--r--src/test/ui/typeck/return_type_containing_closure.stderr2
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr20
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr5
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr18
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr19
-rw-r--r--src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr4
-rw-r--r--src/test/ui/uninhabited/privately-uninhabited-mir-call.rs2
-rw-r--r--src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr7
-rw-r--r--src/test/ui/union/union-derive-clone.mirunsafeck.stderr4
-rw-r--r--src/test/ui/union/union-derive-clone.thirunsafeck.stderr4
-rw-r--r--src/test/ui/unsized/box-instead-of-dyn-fn.stderr4
-rw-r--r--src/test/ui/unsized/issue-91801.stderr2
-rw-r--r--src/test/ui/unwind-abis/feature-gate-c-unwind.rs4
-rw-r--r--src/test/ui/unwind-abis/feature-gate-c-unwind.stderr25
-rw-r--r--src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs27
-rw-r--r--src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr20
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/duplicate_mod.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/vec_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs4
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs0
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs13
-rw-r--r--src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr19
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6251.stderr2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr2
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.rs6
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.stderr2
-rw-r--r--src/tools/compiletest/src/common.rs4
-rw-r--r--src/tools/compiletest/src/header.rs1
-rw-r--r--src/tools/compiletest/src/main.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs31
m---------src/tools/miri12
m---------src/tools/rust-analyzer14
m---------src/tools/rust-installer0
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustbook/src/main.rs41
-rw-r--r--src/tools/rustc-workspace-hack/Cargo.toml2
-rw-r--r--src/tools/rustfmt/src/items.rs2
-rw-r--r--src/tools/rustfmt/src/utils.rs4
-rw-r--r--src/tools/tidy/src/bins.rs23
-rw-r--r--src/tools/tidy/src/main.rs9
-rwxr-xr-xsuggest-blanket-impl-local-traitbin479160 -> 0 bytes
1335 files changed, 20021 insertions, 14104 deletions
diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md
new file mode 100644
index 00000000000..1d93939e233
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation.md
@@ -0,0 +1,16 @@
+---
+name: Documentation problem
+about: Create a report for a documentation problem.
+labels: A-docs
+---
+<!--
+Thank you for finding a documentation problem! 📚
+
+Documentation problems might be grammatical issues, typos, or unclear wording, please provide details regarding the documentation including where it is present.
+
+-->
+
+### Location
+
+### Summary
+
diff --git a/.github/ISSUE_TEMPLATE/library_tracking_issue.md b/.github/ISSUE_TEMPLATE/library_tracking_issue.md
index 32fccfcfb16..91c06402ca1 100644
--- a/.github/ISSUE_TEMPLATE/library_tracking_issue.md
+++ b/.github/ISSUE_TEMPLATE/library_tracking_issue.md
@@ -50,7 +50,7 @@ If the feature is changed later, please add those PRs here as well.
 -->
 
 - [ ] Implementation: #...
-- [ ] Final comment period (FCP)
+- [ ] Final comment period (FCP)[^1]
 - [ ] Stabilization PR
 
 <!--
@@ -81,3 +81,5 @@ Zulip, or the internals forum) here.
 -->
 
 - None yet.
+
+[^1]: https://std-dev-guide.rust-lang.org/feature-lifecycle/stabilization.html
diff --git a/Cargo.lock b/Cargo.lock
index ba0098a9775..2bf07149cc8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -298,7 +298,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.64.0"
+version = "0.65.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -307,7 +307,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 3.2.5",
+ "clap",
  "crates-io",
  "crossbeam-utils",
  "curl",
@@ -445,7 +445,7 @@ dependencies = [
 
 [[package]]
 name = "cargo-util"
-version = "0.1.4"
+version = "0.2.1"
 dependencies = [
  "anyhow",
  "core-foundation",
@@ -574,22 +574,6 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "2.34.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
-dependencies = [
- "ansi_term",
- "atty",
- "bitflags",
- "strsim 0.8.0",
- "textwrap 0.11.0",
- "unicode-width",
- "vec_map",
- "yaml-rust 0.3.5",
-]
-
-[[package]]
-name = "clap"
 version = "3.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d53da17d37dba964b9b3ecb5c5a1f193a2762c700e6829201e645b9381c99dc7"
@@ -600,9 +584,9 @@ dependencies = [
  "clap_lex",
  "indexmap",
  "once_cell",
- "strsim 0.10.0",
+ "strsim",
  "termcolor",
- "textwrap 0.15.0",
+ "textwrap",
 ]
 
 [[package]]
@@ -611,7 +595,7 @@ version = "3.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"
 dependencies = [
- "clap 3.2.5",
+ "clap",
 ]
 
 [[package]]
@@ -669,7 +653,7 @@ name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
  "aho-corasick",
- "clap 3.2.5",
+ "clap",
  "indoc",
  "itertools",
  "opener",
@@ -1242,7 +1226,7 @@ name = "expand-yaml-anchors"
 version = "0.1.0"
 dependencies = [
  "yaml-merge-keys",
- "yaml-rust 0.4.4",
+ "yaml-rust",
 ]
 
 [[package]]
@@ -1862,7 +1846,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "anyhow",
- "clap 2.34.0",
+ "clap",
  "flate2",
  "lazy_static",
  "num_cpus",
@@ -2310,7 +2294,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 3.2.5",
+ "clap",
  "clap_complete",
  "elasticlunr-rs",
  "env_logger 0.7.1",
@@ -2617,9 +2601,9 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
 
 [[package]]
 name = "os_info"
-version = "3.0.7"
+version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ac91020bfed8cc3f8aa450d4c3b5fa1d3373fc091c8a92009f3b27749d5a227"
+checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62"
 dependencies = [
  "log",
  "serde",
@@ -3385,7 +3369,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 2.34.0",
+ "clap",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3473,13 +3457,14 @@ version = "1.0.0"
 dependencies = [
  "bstr",
  "byteorder",
- "clap 3.2.5",
+ "clap",
  "crossbeam-utils",
  "libc",
  "libz-sys",
  "proc-macro2",
  "quote",
  "rand_core 0.5.1",
+ "regex",
  "serde",
  "serde_json",
  "smallvec",
@@ -3813,6 +3798,7 @@ dependencies = [
  "atty",
  "rustc_data_structures",
  "rustc_error_messages",
+ "rustc_hir",
  "rustc_lint_defs",
  "rustc_macros",
  "rustc_serialize",
@@ -3869,6 +3855,7 @@ name = "rustc_hir"
 version = "0.0.0"
 dependencies = [
  "odht",
+ "rustc_arena",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_error_messages",
@@ -4009,6 +3996,7 @@ dependencies = [
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
+ "rustc_macros",
  "rustc_middle",
  "rustc_parse_format",
  "rustc_session",
@@ -4658,7 +4646,7 @@ dependencies = [
  "anyhow",
  "bytecount",
  "cargo_metadata",
- "clap 3.2.5",
+ "clap",
  "derive-new",
  "diff",
  "dirs",
@@ -5051,12 +5039,6 @@ dependencies = [
 
 [[package]]
 name = "strsim"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
-
-[[package]]
-name = "strsim"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
@@ -5197,15 +5179,6 @@ dependencies = [
 
 [[package]]
 name = "textwrap"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
-dependencies = [
- "unicode-width",
-]
-
-[[package]]
-name = "textwrap"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
@@ -5725,12 +5698,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
 
 [[package]]
-name = "vec_map"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
-
-[[package]]
 name = "vergen"
 version = "5.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5888,17 +5855,11 @@ checksum = "fd236a7dc9bb598f349fe4a8754f49181fee50284daa15cd1ba652d722280004"
 dependencies = [
  "lazy_static",
  "thiserror",
- "yaml-rust 0.4.4",
+ "yaml-rust",
 ]
 
 [[package]]
 name = "yaml-rust"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
-
-[[package]]
-name = "yaml-rust"
 version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
diff --git a/RELEASES.md b/RELEASES.md
index ea6ae46b0ed..8154eab2059 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -78,6 +78,8 @@ Compatibility Notes
 - [rustdoc: doctests are now run on unexported `macro_rules!` macros, matching other private items][96630]
 - [rustdoc: Remove .woff font files][96279]
 - [Enforce Copy bounds for repeat elements while considering lifetimes][95819]
+- [Windows: Fix potentinal unsoundness by aborting if `File` reads or writes cannot
+  complete synchronously][95469].
 
 Internal Changes
 ----------------
@@ -99,6 +101,7 @@ and related tools.
 [95372]: https://github.com/rust-lang/rust/pull/95372/
 [95380]: https://github.com/rust-lang/rust/pull/95380/
 [95431]: https://github.com/rust-lang/rust/pull/95431/
+[95469]: https://github.com/rust-lang/rust/pull/95469/
 [95705]: https://github.com/rust-lang/rust/pull/95705/
 [95801]: https://github.com/rust-lang/rust/pull/95801/
 [95819]: https://github.com/rust-lang/rust/pull/95819/
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 62995dfd2e2..a5f1cbc96da 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -19,6 +19,7 @@
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
+#![feature(ptr_const_cast)]
 
 use smallvec::SmallVec;
 
@@ -27,7 +28,7 @@ use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::marker::{PhantomData, Send};
 use std::mem::{self, MaybeUninit};
-use std::ptr;
+use std::ptr::{self, NonNull};
 use std::slice;
 
 #[inline(never)]
@@ -55,15 +56,24 @@ pub struct TypedArena<T> {
 
 struct ArenaChunk<T = u8> {
     /// The raw storage for the arena chunk.
-    storage: Box<[MaybeUninit<T>]>,
+    storage: NonNull<[MaybeUninit<T>]>,
     /// The number of valid entries in the chunk.
     entries: usize,
 }
 
+unsafe impl<#[may_dangle] T> Drop for ArenaChunk<T> {
+    fn drop(&mut self) {
+        unsafe { Box::from_raw(self.storage.as_mut()) };
+    }
+}
+
 impl<T> ArenaChunk<T> {
     #[inline]
     unsafe fn new(capacity: usize) -> ArenaChunk<T> {
-        ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
+        ArenaChunk {
+            storage: NonNull::new(Box::into_raw(Box::new_uninit_slice(capacity))).unwrap(),
+            entries: 0,
+        }
     }
 
     /// Destroys this arena chunk.
@@ -72,14 +82,15 @@ impl<T> ArenaChunk<T> {
         // The branch on needs_drop() is an -O1 performance optimization.
         // Without the branch, dropping TypedArena<u8> takes linear time.
         if mem::needs_drop::<T>() {
-            ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len]));
+            let slice = &mut *(self.storage.as_mut());
+            ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
         }
     }
 
     // Returns a pointer to the first allocated object.
     #[inline]
     fn start(&mut self) -> *mut T {
-        MaybeUninit::slice_as_mut_ptr(&mut self.storage)
+        self.storage.as_ptr() as *mut T
     }
 
     // Returns a pointer to the end of the allocated space.
@@ -90,7 +101,7 @@ impl<T> ArenaChunk<T> {
                 // A pointer as large as possible for zero-sized elements.
                 ptr::invalid_mut(!0)
             } else {
-                self.start().add(self.storage.len())
+                self.start().add((*self.storage.as_ptr()).len())
             }
         }
     }
@@ -274,7 +285,7 @@ impl<T> TypedArena<T> {
                 // If the previous chunk's len is less than HUGE_PAGE
                 // bytes, then this chunk will be least double the previous
                 // chunk's size.
-                new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2);
+                new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / elem_size / 2);
                 new_cap *= 2;
             } else {
                 new_cap = PAGE / elem_size;
@@ -382,7 +393,7 @@ impl DroplessArena {
                 // If the previous chunk's len is less than HUGE_PAGE
                 // bytes, then this chunk will be least double the previous
                 // chunk's size.
-                new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2);
+                new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / 2);
                 new_cap *= 2;
             } else {
                 new_cap = PAGE;
diff --git a/compiler/rustc_arena/src/tests.rs b/compiler/rustc_arena/src/tests.rs
index 911e577c1ed..ad61464343a 100644
--- a/compiler/rustc_arena/src/tests.rs
+++ b/compiler/rustc_arena/src/tests.rs
@@ -79,7 +79,11 @@ fn test_arena_alloc_nested() {
 #[test]
 pub fn test_copy() {
     let arena = TypedArena::default();
-    for _ in 0..100000 {
+    #[cfg(not(miri))]
+    const N: usize = 100000;
+    #[cfg(miri)]
+    const N: usize = 1000;
+    for _ in 0..N {
         arena.alloc(Point { x: 1, y: 2, z: 3 });
     }
 }
@@ -106,7 +110,11 @@ struct Noncopy {
 #[test]
 pub fn test_noncopy() {
     let arena = TypedArena::default();
-    for _ in 0..100000 {
+    #[cfg(not(miri))]
+    const N: usize = 100000;
+    #[cfg(miri)]
+    const N: usize = 1000;
+    for _ in 0..N {
         arena.alloc(Noncopy { string: "hello world".to_string(), array: vec![1, 2, 3, 4, 5] });
     }
 }
@@ -114,7 +122,11 @@ pub fn test_noncopy() {
 #[test]
 pub fn test_typed_arena_zero_sized() {
     let arena = TypedArena::default();
-    for _ in 0..100000 {
+    #[cfg(not(miri))]
+    const N: usize = 100000;
+    #[cfg(miri)]
+    const N: usize = 1000;
+    for _ in 0..N {
         arena.alloc(());
     }
 }
@@ -124,7 +136,11 @@ pub fn test_typed_arena_clear() {
     let mut arena = TypedArena::default();
     for _ in 0..10 {
         arena.clear();
-        for _ in 0..10000 {
+        #[cfg(not(miri))]
+        const N: usize = 10000;
+        #[cfg(miri)]
+        const N: usize = 100;
+        for _ in 0..N {
             arena.alloc(Point { x: 1, y: 2, z: 3 });
         }
     }
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index e5b61d7000a..f705d004422 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2036,6 +2036,14 @@ impl TyKind {
     pub fn is_unit(&self) -> bool {
         matches!(self, TyKind::Tup(tys) if tys.is_empty())
     }
+
+    pub fn is_simple_path(&self) -> Option<Symbol> {
+        if let TyKind::Path(None, Path { segments, .. }) = &self && segments.len() == 1 {
+            Some(segments[0].ident.name)
+        } else {
+            None
+        }
+    }
 }
 
 /// Syntax used to declare a trait object.
@@ -2667,13 +2675,16 @@ impl Item {
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub enum Extern {
     None,
-    Implicit,
-    Explicit(StrLit),
+    Implicit(Span),
+    Explicit(StrLit, Span),
 }
 
 impl Extern {
-    pub fn from_abi(abi: Option<StrLit>) -> Extern {
-        abi.map_or(Extern::Implicit, Extern::Explicit)
+    pub fn from_abi(abi: Option<StrLit>, span: Span) -> Extern {
+        match abi {
+            Some(name) => Extern::Explicit(name, span),
+            None => Extern::Implicit(span),
+        }
     }
 }
 
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index aab9b90e4b7..0e395d70335 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -24,10 +24,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> &'hir hir::InlineAsm<'hir> {
         // Rustdoc needs to support asm! from foreign architectures: don't try
         // lowering the register constraints in this case.
-        let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
-        if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
-            struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
-                .emit();
+        let asm_arch =
+            if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch };
+        if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc {
+            struct_span_err!(
+                self.tcx.sess,
+                sp,
+                E0472,
+                "inline assembly is unsupported on this target"
+            )
+            .emit();
         }
         if let Some(asm_arch) = asm_arch {
             // Inline assembly is currently only stable for these architectures.
@@ -40,9 +46,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     | asm::InlineAsmArch::RiscV32
                     | asm::InlineAsmArch::RiscV64
             );
-            if !is_stable && !self.sess.features_untracked().asm_experimental_arch {
+            if !is_stable && !self.tcx.features().asm_experimental_arch {
                 feature_err(
-                    &self.sess.parse_sess,
+                    &self.tcx.sess.parse_sess,
                     sym::asm_experimental_arch,
                     sp,
                     "inline assembly is not stable yet on this architecture",
@@ -52,17 +58,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
         if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
             && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
-            && !self.sess.opts.actually_rustdoc
+            && !self.tcx.sess.opts.actually_rustdoc
         {
-            self.sess
+            self.tcx
+                .sess
                 .struct_span_err(sp, "the `att_syntax` option is only supported on x86")
                 .emit();
         }
-        if asm.options.contains(InlineAsmOptions::MAY_UNWIND)
-            && !self.sess.features_untracked().asm_unwind
-        {
+        if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
             feature_err(
-                &self.sess.parse_sess,
+                &self.tcx.sess.parse_sess,
                 sym::asm_unwind,
                 sp,
                 "the `may_unwind` option is unstable",
@@ -73,12 +78,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut clobber_abis = FxHashMap::default();
         if let Some(asm_arch) = asm_arch {
             for (abi_name, abi_span) in &asm.clobber_abis {
-                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
+                match asm::InlineAsmClobberAbi::parse(asm_arch, &self.tcx.sess.target, *abi_name) {
                     Ok(abi) => {
                         // If the abi was already in the list, emit an error
                         match clobber_abis.get(&abi) {
                             Some((prev_name, prev_sp)) => {
-                                let mut err = self.sess.struct_span_err(
+                                let mut err = self.tcx.sess.struct_span_err(
                                     *abi_span,
                                     &format!("`{}` ABI specified multiple times", prev_name),
                                 );
@@ -86,7 +91,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                                 // Multiple different abi names may actually be the same ABI
                                 // If the specified ABIs are not the same name, alert the user that they resolve to the same ABI
-                                let source_map = self.sess.source_map();
+                                let source_map = self.tcx.sess.source_map();
                                 if source_map.span_to_snippet(*prev_sp)
                                     != source_map.span_to_snippet(*abi_span)
                                 {
@@ -101,7 +106,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     Err(&[]) => {
-                        self.sess
+                        self.tcx
+                            .sess
                             .struct_span_err(
                                 *abi_span,
                                 "`clobber_abi` is not supported on this target",
@@ -109,8 +115,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             .emit();
                     }
                     Err(supported_abis) => {
-                        let mut err =
-                            self.sess.struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
+                        let mut err = self
+                            .tcx
+                            .sess
+                            .struct_span_err(*abi_span, "invalid ABI for `clobber_abi`");
                         let mut abis = format!("`{}`", supported_abis[0]);
                         for m in &supported_abis[1..] {
                             let _ = write!(abis, ", `{}`", m);
@@ -128,7 +136,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Lower operands to HIR. We use dummy register classes if an error
         // occurs during lowering because we still need to be able to produce a
         // valid HIR.
-        let sess = self.sess;
+        let sess = self.tcx.sess;
         let mut operands: Vec<_> = asm
             .operands
             .iter()
@@ -184,9 +192,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     InlineAsmOperand::Const { ref anon_const } => {
-                        if !self.sess.features_untracked().asm_const {
+                        if !self.tcx.features().asm_const {
                             feature_err(
-                                &self.sess.parse_sess,
+                                &sess.parse_sess,
                                 sym::asm_const,
                                 *op_sp,
                                 "const operands for inline assembly are unstable",
@@ -198,9 +206,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     InlineAsmOperand::Sym { ref sym } => {
-                        if !self.sess.features_untracked().asm_sym {
+                        if !self.tcx.features().asm_sym {
                             feature_err(
-                                &self.sess.parse_sess,
+                                &sess.parse_sess,
                                 sym::asm_sym,
                                 *op_sp,
                                 "sym operands for inline assembly are unstable",
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 3a7e0a70585..9444fffc331 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -159,9 +159,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             span,
             kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
         });
-        if !self.sess.features_untracked().let_else {
+        if !self.tcx.features().let_else {
             feature_err(
-                &self.sess.parse_sess,
+                &self.tcx.sess.parse_sess,
                 sym::let_else,
                 local.span,
                 "`let...else` statements are unstable",
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 3babe73030a..9e02e7ed3b9 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -46,7 +46,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             let hir_id = self.lower_node_id(e.id);
                             return hir::Expr { hir_id, kind, span: self.lower_span(e.span) };
                         } else {
-                            self.sess
+                            self.tcx.sess
                                 .struct_span_err(
                                     e.span,
                                     "#[rustc_box] requires precisely one argument \
@@ -207,8 +207,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
                 }
                 ExprKind::Underscore => {
-                    self.sess
-                        .struct_span_err(
+                    self.tcx
+                        .sess.struct_span_err(
                             e.span,
                             "in expressions, `_` can only be used on the left-hand side of an assignment",
                         )
@@ -245,7 +245,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
                         StructRest::Rest(sp) => {
-                            self.sess
+                            self.tcx
+                                .sess
                                 .struct_span_err(*sp, "base expression required after `..`")
                                 .span_label(*sp, "add a base expression here")
                                 .emit();
@@ -474,7 +475,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             } else {
                 let try_span = this.mark_span_with_reason(
                     DesugaringKind::TryBlock,
-                    this.sess.source_map().end_point(body.span),
+                    this.tcx.sess.source_map().end_point(body.span),
                     this.allow_try_trait.clone(),
                 );
 
@@ -653,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::GeneratorKind::Async(_)) => {}
             Some(hir::GeneratorKind::Gen) | None => {
                 let mut err = struct_span_err!(
-                    self.sess,
+                    self.tcx.sess,
                     dot_await_span,
                     E0728,
                     "`await` is only allowed inside `async` functions and blocks"
@@ -878,7 +879,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::GeneratorKind::Gen) => {
                 if decl.inputs.len() > 1 {
                     struct_span_err!(
-                        self.sess,
+                        self.tcx.sess,
                         fn_decl_span,
                         E0628,
                         "too many parameters for a generator (expected 0 or 1 parameters)"
@@ -892,8 +893,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             None => {
                 if movability == Movability::Static {
-                    struct_span_err!(self.sess, fn_decl_span, E0697, "closures cannot be static")
-                        .emit();
+                    struct_span_err!(
+                        self.tcx.sess,
+                        fn_decl_span,
+                        E0697,
+                        "closures cannot be static"
+                    )
+                    .emit();
                 }
                 None
             }
@@ -916,7 +922,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
                 struct_span_err!(
-                    this.sess,
+                    this.tcx.sess,
                     fn_decl_span,
                     E0708,
                     "`async` non-`move` closures with parameters are not currently supported",
@@ -1163,7 +1169,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 let fields_omitted = match &se.rest {
                     StructRest::Base(e) => {
-                        self.sess
+                        self.tcx
+                            .sess
                             .struct_span_err(
                                 e.span,
                                 "functional record updates are not allowed in destructuring \
@@ -1371,7 +1378,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::GeneratorKind::Gen) => {}
             Some(hir::GeneratorKind::Async(_)) => {
                 struct_span_err!(
-                    self.sess,
+                    self.tcx.sess,
                     span,
                     E0727,
                     "`async` generators are not yet supported"
@@ -1516,7 +1523,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             span,
             self.allow_try_trait.clone(),
         );
-        let try_span = self.sess.source_map().end_point(span);
+        let try_span = self.tcx.sess.source_map().end_point(span);
         let try_span = self.mark_span_with_reason(
             DesugaringKind::QuestionMark,
             try_span,
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index 4be22020ba1..ddd54f7c208 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -192,9 +192,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_pat(&mut self, pat: &'hir Pat<'hir>) {
-        let node =
-            if let PatKind::Binding(..) = pat.kind { Node::Binding(pat) } else { Node::Pat(pat) };
-        self.insert(pat.span, pat.hir_id, node);
+        self.insert(pat.span, pat.hir_id, Node::Pat(pat));
 
         self.with_parent(pat.hir_id, |this| {
             intravisit::walk_pat(this, pat);
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 0ef21371694..7da49143b46 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1,7 +1,6 @@
 use super::ResolverAstLoweringExt;
 use super::{AstOwner, ImplTraitContext, ImplTraitPosition};
-use super::{LoweringContext, ParamMode};
-use crate::{Arena, FnDeclKind};
+use super::{FnDeclKind, LoweringContext, ParamMode};
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::AssocCtxt;
@@ -12,12 +11,9 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
-use rustc_hir::definitions::Definitions;
 use rustc_hir::PredicateOrigin;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs};
-use rustc_session::cstore::CrateStoreDyn;
-use rustc_session::Session;
+use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -27,12 +23,8 @@ use smallvec::{smallvec, SmallVec};
 use std::iter;
 
 pub(super) struct ItemLowerer<'a, 'hir> {
-    pub(super) sess: &'a Session,
-    pub(super) definitions: &'a mut Definitions,
-    pub(super) cstore: &'a CrateStoreDyn,
-    pub(super) resolutions: &'a ResolverOutputs,
+    pub(super) tcx: TyCtxt<'hir>,
     pub(super) resolver: &'a mut ResolverAstLowering,
-    pub(super) arena: &'hir Arena<'hir>,
     pub(super) ast_index: &'a IndexVec<LocalDefId, AstOwner<'a>>,
     pub(super) owners: &'a mut IndexVec<LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>>,
 }
@@ -65,12 +57,9 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
     ) {
         let mut lctx = LoweringContext {
             // Pseudo-globals.
-            sess: &self.sess,
-            definitions: self.definitions,
-            cstore: self.cstore,
-            resolutions: self.resolutions,
+            tcx: self.tcx,
             resolver: self.resolver,
-            arena: self.arena,
+            arena: self.tcx.hir_arena,
 
             // HirId handling.
             bodies: Vec::new(),
@@ -144,12 +133,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
     fn lower_assoc_item(&mut self, item: &AssocItem, ctxt: AssocCtxt) {
         let def_id = self.resolver.node_id_to_def_id[&item.id];
 
-        let parent_id = {
-            let parent = self.definitions.def_key(def_id).parent;
-            let local_def_index = parent.unwrap();
-            LocalDefId { local_def_index }
-        };
-
+        let parent_id = self.tcx.local_parent(def_id);
         let parent_hir = self.lower_node(parent_id).unwrap();
         self.with_lctx(item.id, |lctx| {
             // Evaluate with the lifetimes in `params` in-scope.
@@ -1272,13 +1256,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
     pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
         match ext {
             Extern::None => abi::Abi::Rust,
-            Extern::Implicit => abi::Abi::FALLBACK,
-            Extern::Explicit(abi) => self.lower_abi(abi),
+            Extern::Implicit(_) => abi::Abi::FALLBACK,
+            Extern::Explicit(abi, _) => self.lower_abi(abi),
         }
     }
 
     fn error_on_invalid_abi(&self, abi: StrLit) {
-        struct_span_err!(self.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol)
+        struct_span_err!(self.tcx.sess, abi.span, E0703, "invalid ABI: found `{}`", abi.symbol)
             .span_label(abi.span, "invalid ABI")
             .help(&format!("valid ABIs: {}", abi::all_names().join(", ")))
             .emit();
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index cab2de0ced8..fdf60e60914 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -49,18 +49,15 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::{struct_span_err, Applicability, Handler};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
-use rustc_hir::definitions::{DefPathData, Definitions};
+use rustc_hir::definitions::DefPathData;
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::ty::{ResolverAstLowering, ResolverOutputs};
-use rustc_query_system::ich::StableHashingContext;
-use rustc_session::cstore::CrateStoreDyn;
+use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -83,19 +80,12 @@ mod item;
 mod pat;
 mod path;
 
-rustc_hir::arena_types!(rustc_arena::declare_arena);
-
-struct LoweringContext<'a, 'hir: 'a> {
-    /// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
-    sess: &'a Session,
-
-    definitions: &'a mut Definitions,
-    cstore: &'a CrateStoreDyn,
-    resolutions: &'a ResolverOutputs,
+struct LoweringContext<'a, 'hir> {
+    tcx: TyCtxt<'hir>,
     resolver: &'a mut ResolverAstLowering,
 
     /// Used to allocate HIR nodes.
-    arena: &'hir Arena<'hir>,
+    arena: &'hir hir::Arena<'hir>,
 
     /// Bodies inside the owner being lowered.
     bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
@@ -391,61 +381,58 @@ fn index_crate<'a>(
 /// Compute the hash for the HIR of the full crate.
 /// This hash will then be part of the crate_hash which is stored in the metadata.
 fn compute_hir_hash(
-    sess: &Session,
-    definitions: &Definitions,
-    cstore: &CrateStoreDyn,
-    resolver: &ResolverOutputs,
+    tcx: TyCtxt<'_>,
     owners: &IndexVec<LocalDefId, hir::MaybeOwner<&hir::OwnerInfo<'_>>>,
 ) -> Fingerprint {
     let mut hir_body_nodes: Vec<_> = owners
         .iter_enumerated()
         .filter_map(|(def_id, info)| {
             let info = info.as_owner()?;
-            let def_path_hash = definitions.def_path_hash(def_id);
+            let def_path_hash = tcx.hir().def_path_hash(def_id);
             Some((def_path_hash, info))
         })
         .collect();
     hir_body_nodes.sort_unstable_by_key(|bn| bn.0);
 
-    let mut stable_hasher = StableHasher::new();
-    let mut hcx = StableHashingContext::new(sess, definitions, cstore, &resolver.source_span);
-    hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
-    stable_hasher.finish()
+    tcx.with_stable_hashing_context(|mut hcx| {
+        let mut stable_hasher = StableHasher::new();
+        hir_body_nodes.hash_stable(&mut hcx, &mut stable_hasher);
+        stable_hasher.finish()
+    })
 }
 
-pub fn lower_crate<'hir>(
-    sess: &Session,
-    krate: &Crate,
-    definitions: &mut Definitions,
-    cstore: &CrateStoreDyn,
-    resolutions: &ResolverOutputs,
-    mut resolver: ResolverAstLowering,
-    arena: &'hir Arena<'hir>,
-) -> &'hir hir::Crate<'hir> {
-    let _prof_timer = sess.prof.verbose_generic_activity("hir_lowering");
-
-    let ast_index = index_crate(&resolver.node_id_to_def_id, krate);
+pub fn lower_to_hir<'hir>(tcx: TyCtxt<'hir>, (): ()) -> hir::Crate<'hir> {
+    let sess = tcx.sess;
+    let krate = tcx.untracked_crate.steal();
+    let mut resolver = tcx.resolver_for_lowering(()).steal();
 
-    let mut owners =
-        IndexVec::from_fn_n(|_| hir::MaybeOwner::Phantom, definitions.def_index_count());
+    let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
+    let mut owners = IndexVec::from_fn_n(
+        |_| hir::MaybeOwner::Phantom,
+        tcx.definitions_untracked().def_index_count(),
+    );
 
     for def_id in ast_index.indices() {
         item::ItemLowerer {
-            sess,
-            definitions,
-            cstore,
-            resolutions,
+            tcx,
             resolver: &mut resolver,
-            arena,
             ast_index: &ast_index,
             owners: &mut owners,
         }
         .lower_node(def_id);
     }
 
-    let hir_hash = compute_hir_hash(sess, definitions, cstore, resolutions, &owners);
-    let krate = hir::Crate { owners, hir_hash };
-    arena.alloc(krate)
+    // Drop AST to free memory
+    std::mem::drop(ast_index);
+    sess.time("drop_ast", || std::mem::drop(krate));
+
+    // Discard hygiene data, which isn't required after lowering to HIR.
+    if !sess.opts.debugging_opts.keep_hygiene_data {
+        rustc_span::hygiene::clear_syntax_context_map();
+    }
+
+    let hir_hash = compute_hir_hash(tcx, &owners);
+    hir::Crate { owners, hir_hash }
 }
 
 #[derive(Copy, Clone, PartialEq, Debug)]
@@ -464,38 +451,25 @@ enum ParenthesizedGenericArgs {
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
-    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
-        StableHashingContext::new(
-            self.sess,
-            self.definitions,
-            self.cstore,
-            &self.resolutions.source_span,
-        )
-    }
-
     fn create_def(
         &mut self,
         parent: LocalDefId,
         node_id: ast::NodeId,
         data: DefPathData,
     ) -> LocalDefId {
+        debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
         assert!(
             self.opt_local_def_id(node_id).is_none(),
             "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
             node_id,
             data,
-            self.definitions.def_key(self.local_def_id(node_id)),
+            self.tcx.hir().def_key(self.local_def_id(node_id)),
         );
 
-        let def_id = self.definitions.create_def(parent, data);
+        let def_id = self.tcx.create_def(parent, data);
 
-        // Some things for which we allocate `LocalDefId`s don't correspond to
-        // anything in the AST, so they don't have a `NodeId`. For these cases
-        // we don't need a mapping from `NodeId` to `LocalDefId`.
-        if node_id != ast::DUMMY_NODE_ID {
-            debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
-            self.resolver.node_id_to_def_id.insert(node_id, def_id);
-        }
+        debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
+        self.resolver.node_id_to_def_id.insert(node_id, def_id);
 
         def_id
     }
@@ -515,6 +489,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{:?}`", node))
     }
 
+    /// Freshen the `LoweringContext` and ready it to lower a nested item.
+    /// The lowered item is registered into `self.children`.
+    ///
+    /// This function sets up `HirId` lowering infrastructure,
+    /// and stashes the shared mutable state to avoid pollution by the closure.
     #[instrument(level = "debug", skip(self, f))]
     fn with_hir_id_owner(
         &mut self,
@@ -533,8 +512,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
         let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
         let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
-        // Do not reset `next_node_id` and `node_id_to_def_id` as we want to refer to the
-        // subdefinitions' nodes.
+
+        // Do not reset `next_node_id` and `node_id_to_def_id`:
+        // we want `f` to be able to refer to the `LocalDefId`s that the caller created.
+        // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
 
         // Always allocate the first `HirId` for the owner itself.
         let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::new(0));
@@ -578,7 +559,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         bodies.sort_by_key(|(k, _)| *k);
         let bodies = SortedMap::from_presorted_elements(bodies);
         let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
-        let (nodes, parenting) = index::index_hir(self.sess, self.definitions, node, &bodies);
+        let (nodes, parenting) =
+            index::index_hir(self.tcx.sess, &*self.tcx.definitions_untracked(), node, &bodies);
         let nodes = hir::OwnerNodes {
             hash_including_bodies,
             hash_without_bodies,
@@ -587,10 +569,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             local_id_to_def_id,
         };
         let attrs = {
-            let mut hcx = self.create_stable_hashing_context();
-            let mut stable_hasher = StableHasher::new();
-            attrs.hash_stable(&mut hcx, &mut stable_hasher);
-            let hash = stable_hasher.finish();
+            let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
+                let mut stable_hasher = StableHasher::new();
+                attrs.hash_stable(&mut hcx, &mut stable_hasher);
+                stable_hasher.finish()
+            });
             hir::AttributeMap { map: attrs, hash }
         };
 
@@ -604,18 +587,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         node: hir::OwnerNode<'hir>,
         bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
     ) -> (Fingerprint, Fingerprint) {
-        let mut hcx = self.create_stable_hashing_context();
-        let mut stable_hasher = StableHasher::new();
-        hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
-            node.hash_stable(hcx, &mut stable_hasher)
-        });
-        let hash_including_bodies = stable_hasher.finish();
-        let mut stable_hasher = StableHasher::new();
-        hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
-            node.hash_stable(hcx, &mut stable_hasher)
-        });
-        let hash_without_bodies = stable_hasher.finish();
-        (hash_including_bodies, hash_without_bodies)
+        self.tcx.with_stable_hashing_context(|mut hcx| {
+            let mut stable_hasher = StableHasher::new();
+            hcx.with_hir_bodies(true, node.def_id(), bodies, |hcx| {
+                node.hash_stable(hcx, &mut stable_hasher)
+            });
+            let hash_including_bodies = stable_hasher.finish();
+            let mut stable_hasher = StableHasher::new();
+            hcx.with_hir_bodies(false, node.def_id(), bodies, |hcx| {
+                node.hash_stable(hcx, &mut stable_hasher)
+            });
+            let hash_without_bodies = stable_hasher.finish();
+            (hash_including_bodies, hash_without_bodies)
+        })
     }
 
     /// This method allocates a new `HirId` for the given `NodeId` and stores it in
@@ -656,9 +640,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
+    /// Generate a new `HirId` without a backing `NodeId`.
     fn next_id(&mut self) -> hir::HirId {
-        let node_id = self.next_node_id();
-        self.lower_node_id(node_id)
+        let owner = self.current_hir_id_owner;
+        let local_id = self.item_local_id_counter;
+        assert_ne!(local_id, hir::ItemLocalId::new(0));
+        self.item_local_id_counter.increment_by(1);
+        hir::HirId { owner, local_id }
     }
 
     #[instrument(level = "trace", skip(self))]
@@ -691,8 +679,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.resolver.get_import_res(id).present_items()
     }
 
-    fn diagnostic(&self) -> &rustc_errors::Handler {
-        self.sess.diagnostic()
+    fn diagnostic(&self) -> &Handler {
+        self.tcx.sess.diagnostic()
     }
 
     /// Reuses the span but adds information like the kind of the desugaring and features that are
@@ -703,18 +691,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         span: Span,
         allow_internal_unstable: Option<Lrc<[Symbol]>>,
     ) -> Span {
-        span.mark_with_reason(
-            allow_internal_unstable,
-            reason,
-            self.sess.edition(),
-            self.create_stable_hashing_context(),
-        )
+        self.tcx.with_stable_hashing_context(|hcx| {
+            span.mark_with_reason(allow_internal_unstable, reason, self.tcx.sess.edition(), hcx)
+        })
     }
 
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.sess.opts.debugging_opts.incremental_relative_spans {
+        if self.tcx.sess.opts.debugging_opts.incremental_relative_spans {
             span.with_parent(Some(self.current_hir_id_owner))
         } else {
             // Do not make spans relative when not using incremental compilation.
@@ -1061,7 +1046,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn emit_bad_parenthesized_trait_in_assoc_ty(&self, data: &ParenthesizedArgs) {
-        let mut err = self.sess.struct_span_err(
+        let mut err = self.tcx.sess.struct_span_err(
             data.span,
             "parenthesized generic arguments cannot be used in associated type constraints",
         );
@@ -1106,7 +1091,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
             ast::GenericArg::Type(ty) => {
                 match ty.kind {
-                    TyKind::Infer if self.sess.features_untracked().generic_arg_infer => {
+                    TyKind::Infer if self.tcx.features().generic_arg_infer => {
                         return GenericArg::Infer(hir::InferArg {
                             hir_id: self.lower_node_id(ty.id),
                             span: self.lower_span(ty.span),
@@ -1230,7 +1215,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     } else {
                         self.next_node_id()
                     };
-                    let span = self.sess.source_map().next_point(t.span.shrink_to_lo());
+                    let span = self.tcx.sess.source_map().next_point(t.span.shrink_to_lo());
                     Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
                 });
                 let lifetime = self.lower_lifetime(&region);
@@ -1334,7 +1319,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     ImplTraitContext::Disallowed(position) => {
                         let mut err = struct_span_err!(
-                            self.sess,
+                            self.tcx.sess,
                             t.span,
                             E0562,
                             "`impl Trait` only allowed in function and inherent method return types, not in {}",
@@ -1347,7 +1332,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
             TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
             TyKind::CVarArgs => {
-                self.sess.delay_span_bug(
+                self.tcx.sess.delay_span_bug(
                     t.span,
                     "`TyKind::CVarArgs` should have been handled elsewhere",
                 );
@@ -1952,7 +1937,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             hir_id,
             name,
             span: self.lower_span(param.span()),
-            pure_wrt_drop: self.sess.contains_name(&param.attrs, sym::may_dangle),
+            pure_wrt_drop: self.tcx.sess.contains_name(&param.attrs, sym::may_dangle),
             kind,
             colon_span: param.colon_span.map(|s| self.lower_span(s)),
         }
@@ -2094,11 +2079,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
         match c.value.kind {
             ExprKind::Underscore => {
-                if self.sess.features_untracked().generic_arg_infer {
+                if self.tcx.features().generic_arg_infer {
                     hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
                 } else {
                     feature_err(
-                        &self.sess.parse_sess,
+                        &self.tcx.sess.parse_sess,
                         sym::generic_arg_infer,
                         c.value.span,
                         "using `_` for array lengths is unstable",
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 52ba5daf014..393be3b454c 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -133,7 +133,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // We should've returned in the for loop above.
 
-        self.sess.diagnostic().span_bug(
+        self.diagnostic().span_bug(
             p.span,
             &format!(
                 "lower_qpath: no final extension segment in {}..{}",
@@ -193,7 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
                     ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
                     ParenthesizedGenericArgs::Err => {
-                        let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
+                        let mut err = struct_span_err!(self.tcx.sess, data.span, E0214, "{}", msg);
                         err.span_label(data.span, "only `Fn` traits may use parentheses");
                         // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
                         if !data.inputs.is_empty() {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 503bdbad258..3942062656f 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,7 +13,9 @@ use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
+use rustc_errors::{
+    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
+};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -476,6 +478,17 @@ impl<'a> AstValidator<'a> {
     }
 
     fn error_item_without_body(&self, sp: Span, ctx: &str, msg: &str, sugg: &str) {
+        self.error_item_without_body_with_help(sp, ctx, msg, sugg, |_| ());
+    }
+
+    fn error_item_without_body_with_help(
+        &self,
+        sp: Span,
+        ctx: &str,
+        msg: &str,
+        sugg: &str,
+        help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
+    ) {
         let source_map = self.session.source_map();
         let end = source_map.end_point(sp);
         let replace_span = if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
@@ -483,15 +496,15 @@ impl<'a> AstValidator<'a> {
         } else {
             sp.shrink_to_hi()
         };
-        self.err_handler()
-            .struct_span_err(sp, msg)
-            .span_suggestion(
-                replace_span,
-                &format!("provide a definition for the {}", ctx),
-                sugg,
-                Applicability::HasPlaceholders,
-            )
-            .emit();
+        let mut err = self.err_handler().struct_span_err(sp, msg);
+        err.span_suggestion(
+            replace_span,
+            &format!("provide a definition for the {}", ctx),
+            sugg,
+            Applicability::HasPlaceholders,
+        );
+        help(&mut err);
+        err.emit();
     }
 
     fn check_impl_item_provided<T>(&self, sp: Span, body: &Option<T>, ctx: &str, sugg: &str) {
@@ -630,7 +643,8 @@ impl<'a> AstValidator<'a> {
         match (fk.ctxt(), fk.header()) {
             (Some(FnCtxt::Foreign), _) => return,
             (Some(FnCtxt::Free), Some(header)) => match header.ext {
-                Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }) | Extern::Implicit
+                Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
+                | Extern::Implicit(_)
                     if matches!(header.unsafety, Unsafe::Yes(_)) =>
                 {
                     return;
@@ -842,7 +856,7 @@ impl<'a> AstValidator<'a> {
                     .emit();
                 });
                 self.check_late_bound_lifetime_defs(&bfty.generic_params);
-                if let Extern::Implicit = bfty.ext {
+                if let Extern::Implicit(_) = bfty.ext {
                     let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
                     self.maybe_lint_missing_abi(sig_span, ty.id);
                 }
@@ -1190,8 +1204,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 if body.is_none() {
                     let msg = "free function without a body";
-                    self.error_item_without_body(item.span, "function", msg, " { <body> }");
+                    let ext = sig.header.ext;
+
+                    let f = |e: &mut DiagnosticBuilder<'_, _>| {
+                        if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
+                        {
+                            let start_suggestion = if let Extern::Explicit(abi, _) = ext {
+                                format!("extern \"{}\" {{", abi.symbol_unescaped)
+                            } else {
+                                "extern {".to_owned()
+                            };
+
+                            let end_suggestion = " }".to_owned();
+                            let end_span = item.span.shrink_to_hi();
+
+                            e
+                            .multipart_suggestion(
+                                "if you meant to declare an externally defined function, use an `extern` block",
+                                vec![(*start_span, start_suggestion), (end_span, end_suggestion)],
+                                Applicability::MaybeIncorrect,
+                             );
+                        }
+                    };
+
+                    self.error_item_without_body_with_help(
+                        item.span,
+                        "function",
+                        msg,
+                        " { <body> }",
+                        f,
+                    );
                 }
+
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
                 let kind =
@@ -1556,7 +1600,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let FnKind::Fn(
             _,
             _,
-            FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
+            FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit(_), .. }, .. },
             _,
             _,
             _,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 37c4f665415..fd2dd6cf6c7 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -283,7 +283,7 @@ impl<'a> PostExpansionVisitor<'a> {
     }
 
     fn check_extern(&self, ext: ast::Extern, constness: ast::Const) {
-        if let ast::Extern::Explicit(abi) = ext {
+        if let ast::Extern::Explicit(abi, _) = ext {
             self.check_abi(abi, constness);
         }
     }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index ad8dbfd506d..c9e3a7edfa6 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1734,10 +1734,10 @@ impl<'a> State<'a> {
 
         match header.ext {
             ast::Extern::None => {}
-            ast::Extern::Implicit => {
+            ast::Extern::Implicit(_) => {
                 self.word_nbsp("extern");
             }
-            ast::Extern::Explicit(abi) => {
+            ast::Extern::Explicit(abi, _) => {
                 self.word_nbsp("extern");
                 self.print_literal(&abi.as_lit());
                 self.nbsp();
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index c7d0e336133..41279588e63 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -92,9 +92,9 @@ impl LocalsStateAtExit {
         struct HasStorageDead(BitSet<Local>);
 
         impl<'tcx> Visitor<'tcx> for HasStorageDead {
-            fn visit_local(&mut self, local: &Local, ctx: PlaceContext, _: Location) {
+            fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) {
                 if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
-                    self.0.insert(*local);
+                    self.0.insert(local);
                 }
             }
         }
@@ -223,7 +223,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
         self.super_assign(assigned_place, rvalue, location)
     }
 
-    fn visit_local(&mut self, temp: &Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, temp: Local, context: PlaceContext, location: Location) {
         if !context.is_use() {
             return;
         }
@@ -232,7 +232,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
         // check whether we (earlier) saw a 2-phase borrow like
         //
         //     TMP = &mut place
-        if let Some(&borrow_index) = self.pending_activations.get(temp) {
+        if let Some(&borrow_index) = self.pending_activations.get(&temp) {
             let borrow_data = &mut self.location_map[borrow_index.as_usize()];
 
             // Watch out: the use of TMP in the borrow itself
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 708fe8719a1..08ea00d71ef 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -33,22 +33,6 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         err
     }
 
-    pub(crate) fn cannot_act_on_uninitialized_variable(
-        &self,
-        span: Span,
-        verb: &str,
-        desc: &str,
-    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
-        struct_span_err!(
-            self,
-            span,
-            E0381,
-            "{} of possibly-uninitialized variable: `{}`",
-            verb,
-            desc,
-        )
-    }
-
     pub(crate) fn cannot_mutably_borrow_multiply(
         &self,
         new_loan_span: Span,
@@ -175,8 +159,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
             self,
             new_loan_span,
             E0501,
-            "cannot borrow {}{} as {} because previous closure \
-             requires unique access",
+            "cannot borrow {}{} as {} because previous closure requires unique access",
             desc_new,
             opt_via,
             kind_new,
@@ -453,9 +436,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
             self,
             closure_span,
             E0373,
-            "{} may outlive the current function, \
-             but it borrows {}, \
-             which is owned by the current function",
+            "{} may outlive the current function, but it borrows {}, which is owned by the current \
+             function",
             closure_kind,
             borrowed_path,
         );
@@ -478,8 +460,8 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
-    fn struct_span_err_with_code<S: Into<MultiSpan>>(
+    #[rustc_lint_diagnostics]
+    pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
         msg: impl Into<DiagnosticMessage>,
diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs
index e4ffae38c33..5e9cec5c350 100644
--- a/compiler/rustc_borrowck/src/constraint_generation.rs
+++ b/compiler/rustc_borrowck/src/constraint_generation.rs
@@ -5,8 +5,8 @@ use rustc_middle::mir::{
     BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue,
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UserTypeProjection,
 };
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, RegionVid, Ty};
 
 use crate::{
@@ -149,7 +149,7 @@ impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
     fn visit_ascribe_user_ty(
         &mut self,
         _place: &Place<'tcx>,
-        _variance: &ty::Variance,
+        _variance: ty::Variance,
         _user_ty: &UserTypeProjection,
         _location: Location,
     ) {
@@ -163,7 +163,7 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
     /// `location`.
     fn add_regular_live_constraint<T>(&mut self, live_ty: T, location: Location)
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         debug!("add_regular_live_constraint(live_ty={:?}, location={:?})", live_ty, location);
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 73c0bf16a1f..687ff0fb505 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2,9 +2,12 @@ use either::Either;
 use rustc_const_eval::util::CallKind;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::ObligationCause;
@@ -18,6 +21,7 @@ use rustc_middle::ty::{
     self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty,
 };
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
+use rustc_span::hygiene::DesugaringKind;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, Span};
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -94,32 +98,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 return;
             }
 
-            let item_msg =
-                match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
-                    Some(name) => format!("`{}`", name),
-                    None => "value".to_owned(),
-                };
-            let mut err = self.cannot_act_on_uninitialized_variable(
+            let err = self.report_use_of_uninitialized(
+                mpi,
+                used_place,
+                moved_place,
+                desired_action,
                 span,
-                desired_action.as_noun(),
-                &self
-                    .describe_place_with_options(moved_place, IncludingDowncast(true))
-                    .unwrap_or_else(|| "_".to_owned()),
+                use_spans,
             );
-            err.span_label(span, format!("use of possibly-uninitialized {}", item_msg));
-
-            use_spans.var_span_label_path_only(
-                &mut err,
-                format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
-            );
-
             self.buffer_error(err);
         } else {
             if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
                 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
                     debug!(
-                        "report_use_of_moved_or_uninitialized place: error suppressed \
-                         mois={:?}",
+                        "report_use_of_moved_or_uninitialized place: error suppressed mois={:?}",
                         move_out_indices
                     );
                     return;
@@ -317,7 +309,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ));
 
                 // Check first whether the source is accessible (issue #87060)
-                if self.infcx.tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+                if self.infcx.tcx.sess.source_map().is_span_accessible(deref_target) {
                     err.span_note(deref_target, "deref defined here");
                 }
             }
@@ -326,6 +318,130 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         }
     }
 
+    fn report_use_of_uninitialized(
+        &self,
+        mpi: MovePathIndex,
+        used_place: PlaceRef<'tcx>,
+        moved_place: PlaceRef<'tcx>,
+        desired_action: InitializationRequiringAction,
+        span: Span,
+        use_spans: UseSpans<'tcx>,
+    ) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
+        // We need all statements in the body where the binding was assigned to to later find all
+        // the branching code paths where the binding *wasn't* assigned to.
+        let inits = &self.move_data.init_path_map[mpi];
+        let move_path = &self.move_data.move_paths[mpi];
+        let decl_span = self.body.local_decls[move_path.place.local].source_info.span;
+        let mut spans = vec![];
+        for init_idx in inits {
+            let init = &self.move_data.inits[*init_idx];
+            let span = init.span(&self.body);
+            if !span.is_dummy() {
+                spans.push(span);
+            }
+        }
+
+        let (name, desc) =
+            match self.describe_place_with_options(moved_place, IncludingDowncast(true)) {
+                Some(name) => (format!("`{name}`"), format!("`{name}` ")),
+                None => ("the variable".to_string(), String::new()),
+            };
+        let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
+            Some(name) => format!("`{name}`"),
+            None => "value".to_string(),
+        };
+
+        // We use the statements were the binding was initialized, and inspect the HIR to look
+        // for the branching codepaths that aren't covered, to point at them.
+        let hir_id = self.mir_hir_id();
+        let map = self.infcx.tcx.hir();
+        let body_id = map.body_owned_by(hir_id);
+        let body = map.body(body_id);
+
+        let mut visitor = ConditionVisitor { spans: &spans, name: &name, errors: vec![] };
+        visitor.visit_body(&body);
+
+        let isnt_initialized = if let InitializationRequiringAction::PartialAssignment
+        | InitializationRequiringAction::Assignment = desired_action
+        {
+            // The same error is emitted for bindings that are *sometimes* initialized and the ones
+            // that are *partially* initialized by assigning to a field of an uninitialized
+            // binding. We differentiate between them for more accurate wording here.
+            "isn't fully initialized"
+        } else if spans
+            .iter()
+            .filter(|i| {
+                // We filter these to avoid misleading wording in cases like the following,
+                // where `x` has an `init`, but it is in the same place we're looking at:
+                // ```
+                // let x;
+                // x += 1;
+                // ```
+                !i.contains(span)
+                    // We filter these to avoid incorrect main message on `match-cfg-fake-edges.rs`
+                        && !visitor
+                            .errors
+                            .iter()
+                            .map(|(sp, _)| *sp)
+                            .any(|sp| span < sp && !sp.contains(span))
+            })
+            .count()
+            == 0
+        {
+            "isn't initialized"
+        } else {
+            "is possibly-uninitialized"
+        };
+
+        let used = desired_action.as_general_verb_in_past_tense();
+        let mut err =
+            struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
+        use_spans.var_span_label_path_only(
+            &mut err,
+            format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
+        );
+
+        if let InitializationRequiringAction::PartialAssignment
+        | InitializationRequiringAction::Assignment = desired_action
+        {
+            err.help(
+                "partial initialization isn't supported, fully initialize the binding with a \
+                 default value and mutate it, or use `std::mem::MaybeUninit`",
+            );
+        }
+        err.span_label(span, format!("{path} {used} here but it {isnt_initialized}"));
+
+        let mut shown = false;
+        for (sp, label) in visitor.errors {
+            if sp < span && !sp.overlaps(span) {
+                // When we have a case like `match-cfg-fake-edges.rs`, we don't want to mention
+                // match arms coming after the primary span because they aren't relevant:
+                // ```
+                // let x;
+                // match y {
+                //     _ if { x = 2; true } => {}
+                //     _ if {
+                //         x; //~ ERROR
+                //         false
+                //     } => {}
+                //     _ => {} // We don't want to point to this.
+                // };
+                // ```
+                err.span_label(sp, &label);
+                shown = true;
+            }
+        }
+        if !shown {
+            for sp in &spans {
+                if *sp < span && !sp.overlaps(span) {
+                    err.span_label(*sp, "binding initialized here in some conditions");
+                }
+            }
+        }
+        err.span_label(decl_span, "binding declared here but left uninitialized");
+        err
+    }
+
     fn suggest_borrow_fn_like(
         &self,
         err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
@@ -1628,7 +1744,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             location: Location,
         ) -> impl Iterator<Item = Location> + Captures<'tcx> + 'a {
             if location.statement_index == 0 {
-                let predecessors = body.predecessors()[location.block].to_vec();
+                let predecessors = body.basic_blocks.predecessors()[location.block].to_vec();
                 Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb)))
             } else {
                 Either::Right(std::iter::once(Location {
@@ -2448,3 +2564,142 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
         }
     }
 }
+
+/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
+struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
+
+impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
+    fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
+        match s.kind {
+            hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
+                self.1 = true;
+            }
+            _ => {}
+        }
+    }
+}
+
+/// Given a set of spans representing statements initializing the relevant binding, visit all the
+/// function expressions looking for branching code paths that *do not* initialize the binding.
+struct ConditionVisitor<'b> {
+    spans: &'b [Span],
+    name: &'b str,
+    errors: Vec<(Span, String)>,
+}
+
+impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
+    fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
+        match ex.kind {
+            hir::ExprKind::If(cond, body, None) => {
+                // `if` expressions with no `else` that initialize the binding might be missing an
+                // `else` arm.
+                let mut v = ReferencedStatementsVisitor(self.spans, false);
+                v.visit_expr(body);
+                if v.1 {
+                    self.errors.push((
+                        cond.span,
+                        format!(
+                            "if this `if` condition is `false`, {} is not initialized",
+                            self.name,
+                        ),
+                    ));
+                    self.errors.push((
+                        ex.span.shrink_to_hi(),
+                        format!("an `else` arm might be missing here, initializing {}", self.name),
+                    ));
+                }
+            }
+            hir::ExprKind::If(cond, body, Some(other)) => {
+                // `if` expressions where the binding is only initialized in one of the two arms
+                // might be missing a binding initialization.
+                let mut a = ReferencedStatementsVisitor(self.spans, false);
+                a.visit_expr(body);
+                let mut b = ReferencedStatementsVisitor(self.spans, false);
+                b.visit_expr(other);
+                match (a.1, b.1) {
+                    (true, true) | (false, false) => {}
+                    (true, false) => {
+                        if other.span.is_desugaring(DesugaringKind::WhileLoop) {
+                            self.errors.push((
+                                cond.span,
+                                format!(
+                                    "if this condition isn't met and the `while` loop runs 0 \
+                                     times, {} is not initialized",
+                                    self.name
+                                ),
+                            ));
+                        } else {
+                            self.errors.push((
+                                body.span.shrink_to_hi().until(other.span),
+                                format!(
+                                    "if the `if` condition is `false` and this `else` arm is \
+                                     executed, {} is not initialized",
+                                    self.name
+                                ),
+                            ));
+                        }
+                    }
+                    (false, true) => {
+                        self.errors.push((
+                            cond.span,
+                            format!(
+                                "if this condition is `true`, {} is not initialized",
+                                self.name
+                            ),
+                        ));
+                    }
+                }
+            }
+            hir::ExprKind::Match(e, arms, loop_desugar) => {
+                // If the binding is initialized in one of the match arms, then the other match
+                // arms might be missing an initialization.
+                let results: Vec<bool> = arms
+                    .iter()
+                    .map(|arm| {
+                        let mut v = ReferencedStatementsVisitor(self.spans, false);
+                        v.visit_arm(arm);
+                        v.1
+                    })
+                    .collect();
+                if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
+                    for (arm, seen) in arms.iter().zip(results) {
+                        if !seen {
+                            if loop_desugar == hir::MatchSource::ForLoopDesugar {
+                                self.errors.push((
+                                    e.span,
+                                    format!(
+                                        "if the `for` loop runs 0 times, {} is not initialized ",
+                                        self.name
+                                    ),
+                                ));
+                            } else if let Some(guard) = &arm.guard {
+                                self.errors.push((
+                                    arm.pat.span.to(guard.body().span),
+                                    format!(
+                                        "if this pattern and condition are matched, {} is not \
+                                         initialized",
+                                        self.name
+                                    ),
+                                ));
+                            } else {
+                                self.errors.push((
+                                    arm.pat.span,
+                                    format!(
+                                        "if this pattern is matched, {} is not initialized",
+                                        self.name
+                                    ),
+                                ));
+                            }
+                        }
+                    }
+                }
+            }
+            // FIXME: should we also account for binops, particularly `&&` and `||`? `try` should
+            // also be accounted for. For now it is fine, as if we don't find *any* relevant
+            // branching code paths, we point at the places where the binding *is* initialized for
+            // *some* context.
+            _ => {}
+        }
+        walk_expr(self, ex);
+    }
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
index 49d9caae711..b3edc35dc36 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs
@@ -18,8 +18,8 @@ struct AllLocalUsesVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor {
-    fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) {
-        if *local == self.for_local {
+    fn visit_local(&mut self, local: Local, _context: PlaceContext, location: Location) {
+        if local == self.for_local {
             self.uses.insert(location);
         }
     }
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
index 06fca4db0cf..b5a3081e56a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -106,7 +106,7 @@ enum DefUseResult {
 }
 
 impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         let local_ty = self.body.local_decls[local].ty;
 
         let mut found_it = false;
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index fbc3a8cc088..9c7671eee38 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -597,16 +597,16 @@ impl UseSpans<'_> {
     }
 
     /// Describe the span associated with a use of a place.
-    pub(super) fn describe(&self) -> String {
+    pub(super) fn describe(&self) -> &str {
         match *self {
             UseSpans::ClosureUse { generator_kind, .. } => {
                 if generator_kind.is_some() {
-                    " in generator".to_string()
+                    " in generator"
                 } else {
-                    " in closure".to_string()
+                    " in closure"
                 }
             }
-            _ => String::new(),
+            _ => "",
         }
     }
 
@@ -812,12 +812,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             return FnSelfUse {
                 var_span: stmt.source_info.span,
                 fn_call_span: *fn_span,
-                fn_span: self
-                    .infcx
-                    .tcx
-                    .sess
-                    .source_map()
-                    .guess_head_span(self.infcx.tcx.def_span(method_did)),
+                fn_span: self.infcx.tcx.def_span(method_did),
                 kind,
             };
         }
@@ -980,14 +975,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     if self.fn_self_span_reported.insert(fn_span) {
                         err.span_note(
                             // Check whether the source is accessible
-                            if self
-                                .infcx
-                                .tcx
-                                .sess
-                                .source_map()
-                                .span_to_snippet(self_arg.span)
-                                .is_ok()
-                            {
+                            if self.infcx.tcx.sess.source_map().is_span_accessible(self_arg.span) {
                                 self_arg.span
                             } else {
                                 fn_call_span
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 49b24a05071..8134e122662 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -362,7 +362,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
                 let upvar_hir_id = captured_place.get_root_variable();
 
-                if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
+                if let Some(Node::Pat(pat)) = self.infcx.tcx.hir().find(upvar_hir_id)
                     && let hir::PatKind::Binding(
                         hir::BindingAnnotation::Unannotated,
                         _,
@@ -861,7 +861,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             let arg_pos = args
                 .iter()
                 .enumerate()
-                .filter(|(_, arg)| arg.span == self.body.span)
+                .filter(|(_, arg)| arg.hir_id == closure_id)
                 .map(|(pos, _)| pos)
                 .next();
             let def_id = hir.local_def_id(item_id);
@@ -903,9 +903,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 if let Some(span) = arg {
                     err.span_label(span, "change this to accept `FnMut` instead of `Fn`");
                     err.span_label(func.span, "expects `Fn` instead of `FnMut`");
-                    if self.infcx.tcx.sess.source_map().is_multiline(self.body.span) {
-                        err.span_label(self.body.span, "in this closure");
-                    }
+                    err.span_label(self.body.span, "in this closure");
                     look_at_return = false;
                 }
             }
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 0425c53d9dc..721fd3e1c0f 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -26,7 +26,7 @@ pub(super) fn generate_invalidates<'tcx>(
 
     if let Some(all_facts) = all_facts {
         let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
-        let dominators = body.dominators();
+        let dominators = body.basic_blocks.dominators();
         let mut ig = InvalidationGenerator {
             all_facts,
             borrow_set,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 7d6f37340c2..2ed35062da1 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -334,7 +334,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         };
     }
 
-    let dominators = body.dominators();
+    let dominators = body.basic_blocks.dominators();
 
     let mut mbcx = MirBorrowckCtxt {
         infcx,
@@ -907,6 +907,16 @@ impl InitializationRequiringAction {
             InitializationRequiringAction::PartialAssignment => "partially assigned",
         }
     }
+
+    fn as_general_verb_in_past_tense(self) -> &'static str {
+        match self {
+            InitializationRequiringAction::Borrow
+            | InitializationRequiringAction::MatchOn
+            | InitializationRequiringAction::Use => "used",
+            InitializationRequiringAction::Assignment => "assigned",
+            InitializationRequiringAction::PartialAssignment => "partially assigned",
+        }
+    }
 }
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index f5c9392948b..0cf04b369de 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -19,7 +19,9 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable,
+};
 use rustc_span::Span;
 
 use crate::{
@@ -493,8 +495,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     }
                 }
 
-                NllRegionVariableOrigin::RootEmptyRegion
-                | NllRegionVariableOrigin::Existential { .. } => {
+                NllRegionVariableOrigin::Existential { .. } => {
                     // For existential, regions, nothing to do.
                 }
             }
@@ -916,6 +917,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// The idea then is to lower the `T: 'X` constraint into multiple
     /// bounds -- e.g., if `'X` is the union of two free lifetimes,
     /// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
+    #[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
     fn try_promote_type_test(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -933,11 +935,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             return false;
         };
 
+        debug!("subject = {:?}", subject);
+
+        let r_scc = self.constraint_sccs.scc(*lower_bound);
+
+        debug!(
+            "lower_bound = {:?} r_scc={:?} universe={:?}",
+            lower_bound, r_scc, self.scc_universes[r_scc]
+        );
+
+        // If the type test requires that `T: 'a` where `'a` is a
+        // placeholder from another universe, that effectively requires
+        // `T: 'static`, so we have to propagate that requirement.
+        //
+        // It doesn't matter *what* universe because the promoted `T` will
+        // always be in the root universe.
+        if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
+            debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
+            let static_r = self.universal_regions.fr_static;
+            propagated_outlives_requirements.push(ClosureOutlivesRequirement {
+                subject,
+                outlived_free_region: static_r,
+                blame_span: locations.span(body),
+                category: ConstraintCategory::Boring,
+            });
+
+            // we can return here -- the code below might push add'l constraints
+            // but they would all be weaker than this one.
+            return true;
+        }
+
         // For each region outlived by lower_bound find a non-local,
         // universal region (it may be the same region) and add it to
         // `ClosureOutlivesRequirement`.
-        let r_scc = self.constraint_sccs.scc(*lower_bound);
         for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
+            debug!("universal_region_outlived_by ur={:?}", ur);
             // Check whether we can already prove that the "subject" outlives `ur`.
             // If so, we don't have to propagate this requirement to our caller.
             //
@@ -962,8 +994,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 continue;
             }
 
-            debug!("try_promote_type_test: ur={:?}", ur);
-
             let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
             debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
 
@@ -1000,6 +1030,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// will use it's *external name*, which will be a `RegionKind`
     /// variant that can be used in query responses such as
     /// `ReEarlyBound`.
+    #[instrument(level = "debug", skip(self, infcx))]
     fn try_promote_type_test_subject(
         &self,
         infcx: &InferCtxt<'_, 'tcx>,
@@ -1007,8 +1038,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> Option<ClosureOutlivesSubject<'tcx>> {
         let tcx = infcx.tcx;
 
-        debug!("try_promote_type_test_subject(ty = {:?})", ty);
-
         let ty = tcx.fold_regions(ty, |r, _depth| {
             let region_vid = self.to_region_vid(r);
 
@@ -1408,8 +1437,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     self.check_bound_universal_region(fr, placeholder, errors_buffer);
                 }
 
-                NllRegionVariableOrigin::RootEmptyRegion
-                | NllRegionVariableOrigin::Existential { .. } => {
+                NllRegionVariableOrigin::Existential { .. } => {
                     // nothing to check here
                 }
             }
@@ -1511,8 +1539,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     self.check_bound_universal_region(fr, placeholder, errors_buffer);
                 }
 
-                NllRegionVariableOrigin::RootEmptyRegion
-                | NllRegionVariableOrigin::Existential { .. } => {
+                NllRegionVariableOrigin::Existential { .. } => {
                     // nothing to check here
                 }
             }
@@ -1786,9 +1813,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 universe1.cannot_name(placeholder.universe)
             }
 
-            NllRegionVariableOrigin::RootEmptyRegion
-            | NllRegionVariableOrigin::FreeRegion
-            | NllRegionVariableOrigin::Existential { .. } => false,
+            NllRegionVariableOrigin::FreeRegion | NllRegionVariableOrigin::Existential { .. } => {
+                false
+            }
         }
     }
 
@@ -2150,8 +2177,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         let blame_source = match from_region_origin {
             NllRegionVariableOrigin::FreeRegion
             | NllRegionVariableOrigin::Existential { from_forall: false } => true,
-            NllRegionVariableOrigin::RootEmptyRegion
-            | NllRegionVariableOrigin::Placeholder(_)
+            NllRegionVariableOrigin::Placeholder(_)
             | NllRegionVariableOrigin::Existential { from_forall: true } => false,
         };
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index d182c0cf4e8..7c1fa28b8df 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,9 +1,20 @@
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::DefId;
 use rustc_hir::OpaqueTyOrigin;
+use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
-use rustc_trait_selection::opaque_types::InferCtxtExt;
+use rustc_infer::infer::TyCtxtInferExt as _;
+use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
+use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
+use rustc_middle::ty::visit::TypeVisitable;
+use rustc_middle::ty::{
+    self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt, TypeFoldable,
+};
+use rustc_span::Span;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::TraitEngineExt as _;
 
 use super::RegionInferenceContext;
 
@@ -171,3 +182,474 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         })
     }
 }
+
+pub trait InferCtxtExt<'tcx> {
+    fn infer_opaque_definition_from_instantiation(
+        &self,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        instantiated_ty: OpaqueHiddenType<'tcx>,
+        origin: OpaqueTyOrigin,
+    ) -> Ty<'tcx>;
+}
+
+impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
+    /// Given the fully resolved, instantiated type for an opaque
+    /// type, i.e., the value of an inference variable like C1 or C2
+    /// (*), computes the "definition type" for an opaque type
+    /// definition -- that is, the inferred value of `Foo1<'x>` or
+    /// `Foo2<'x>` that we would conceptually use in its definition:
+    /// ```ignore (illustrative)
+    /// type Foo1<'x> = impl Bar<'x> = AAA;  // <-- this type AAA
+    /// type Foo2<'x> = impl Bar<'x> = BBB;  // <-- or this type BBB
+    /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+    /// ```
+    /// Note that these values are defined in terms of a distinct set of
+    /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
+    /// purpose of this function is to do that translation.
+    ///
+    /// (*) C1 and C2 were introduced in the comments on
+    /// `register_member_constraints`. Read that comment for more context.
+    ///
+    /// # Parameters
+    ///
+    /// - `def_id`, the `impl Trait` type
+    /// - `substs`, the substs  used to instantiate this opaque type
+    /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
+    ///   `opaque_defn.concrete_ty`
+    #[instrument(level = "debug", skip(self))]
+    fn infer_opaque_definition_from_instantiation(
+        &self,
+        opaque_type_key: OpaqueTypeKey<'tcx>,
+        instantiated_ty: OpaqueHiddenType<'tcx>,
+        origin: OpaqueTyOrigin,
+    ) -> Ty<'tcx> {
+        if self.is_tainted_by_errors() {
+            return self.tcx.ty_error();
+        }
+
+        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+        // Use substs to build up a reverse map from regions to their
+        // identity mappings. This is necessary because of `impl
+        // Trait` lifetimes are computed by replacing existing
+        // lifetimes with 'static and remapping only those used in the
+        // `impl Trait` return type, resulting in the parameters
+        // shifting.
+        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
+        debug!(?id_substs);
+        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
+            substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
+        debug!("map = {:#?}", map);
+
+        // Convert the type from the function into a type valid outside
+        // the function, by replacing invalid regions with 'static,
+        // after producing an error for each of them.
+        let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
+            self.tcx,
+            def_id,
+            map,
+            instantiated_ty.ty,
+            instantiated_ty.span,
+        ));
+        debug!(?definition_ty);
+
+        if !check_opaque_type_parameter_valid(
+            self.tcx,
+            opaque_type_key,
+            origin,
+            instantiated_ty.span,
+        ) {
+            return self.tcx.ty_error();
+        }
+
+        // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
+        // on stable and we'd break that.
+        if let OpaqueTyOrigin::TyAlias = origin {
+            // This logic duplicates most of `check_opaque_meets_bounds`.
+            // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
+            let param_env = self.tcx.param_env(def_id);
+            let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
+            self.tcx.infer_ctxt().enter(move |infcx| {
+                // Require the hidden type to be well-formed with only the generics of the opaque type.
+                // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
+                // hidden type is well formed even without those bounds.
+                let predicate =
+                    ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
+                        .to_predicate(infcx.tcx);
+                let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+
+                // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
+                // the bounds that the function supplies.
+                match infcx.register_hidden_type(
+                    OpaqueTypeKey { def_id, substs: id_substs },
+                    ObligationCause::misc(instantiated_ty.span, body_id),
+                    param_env,
+                    definition_ty,
+                    origin,
+                ) {
+                    Ok(infer_ok) => {
+                        for obligation in infer_ok.obligations {
+                            fulfillment_cx.register_predicate_obligation(&infcx, obligation);
+                        }
+                    }
+                    Err(err) => {
+                        infcx
+                            .report_mismatched_types(
+                                &ObligationCause::misc(instantiated_ty.span, body_id),
+                                self.tcx.mk_opaque(def_id, id_substs),
+                                definition_ty,
+                                err,
+                            )
+                            .emit();
+                    }
+                }
+
+                fulfillment_cx.register_predicate_obligation(
+                    &infcx,
+                    Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
+                );
+
+                // Check that all obligations are satisfied by the implementation's
+                // version.
+                let errors = fulfillment_cx.select_all_or_error(&infcx);
+
+                let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
+
+                if errors.is_empty() {
+                    definition_ty
+                } else {
+                    infcx.report_fulfillment_errors(&errors, None, false);
+                    self.tcx.ty_error()
+                }
+            })
+        } else {
+            definition_ty
+        }
+    }
+}
+
+fn check_opaque_type_parameter_valid(
+    tcx: TyCtxt<'_>,
+    opaque_type_key: OpaqueTypeKey<'_>,
+    origin: OpaqueTyOrigin,
+    span: Span,
+) -> bool {
+    match origin {
+        // No need to check return position impl trait (RPIT)
+        // because for type and const parameters they are correct
+        // by construction: we convert
+        //
+        // fn foo<P0..Pn>() -> impl Trait
+        //
+        // into
+        //
+        // type Foo<P0...Pn>
+        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
+        //
+        // For lifetime parameters we convert
+        //
+        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+        //
+        // into
+        //
+        // type foo::<'p0..'pn>::Foo<'q0..'qm>
+        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+        //
+        // which would error here on all of the `'static` args.
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
+        // Check these
+        OpaqueTyOrigin::TyAlias => {}
+    }
+    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
+    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
+        let arg_is_param = match arg.unpack() {
+            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
+            GenericArgKind::Lifetime(lt) if lt.is_static() => {
+                tcx.sess
+                    .struct_span_err(span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
+                        "cannot use static lifetime; use a bound lifetime \
+                                    instead or remove the lifetime parameter from the \
+                                    opaque type",
+                    )
+                    .emit();
+                return false;
+            }
+            GenericArgKind::Lifetime(lt) => {
+                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+            }
+            GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
+        };
+
+        if arg_is_param {
+            seen_params.entry(arg).or_default().push(i);
+        } else {
+            // Prevent `fn foo() -> Foo<u32>` from being defining.
+            let opaque_param = opaque_generics.param_at(i, tcx);
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(
+                    tcx.def_span(opaque_param.def_id),
+                    &format!(
+                        "used non-generic {} `{}` for generic parameter",
+                        opaque_param.kind.descr(),
+                        arg,
+                    ),
+                )
+                .emit();
+            return false;
+        }
+    }
+
+    for (_, indices) in seen_params {
+        if indices.len() > 1 {
+            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
+            let spans: Vec<_> = indices
+                .into_iter()
+                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
+                .collect();
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(spans, &format!("{} used multiple times", descr))
+                .emit();
+            return false;
+        }
+    }
+    true
+}
+
+struct ReverseMapper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+
+    opaque_type_def_id: DefId,
+    map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+    map_missing_regions_to_empty: bool,
+
+    /// initially `Some`, set to `None` once error has been reported
+    hidden_ty: Option<Ty<'tcx>>,
+
+    /// Span of function being checked.
+    span: Span,
+}
+
+impl<'tcx> ReverseMapper<'tcx> {
+    fn new(
+        tcx: TyCtxt<'tcx>,
+        opaque_type_def_id: DefId,
+        map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
+        hidden_ty: Ty<'tcx>,
+        span: Span,
+    ) -> Self {
+        Self {
+            tcx,
+            opaque_type_def_id,
+            map,
+            map_missing_regions_to_empty: false,
+            hidden_ty: Some(hidden_ty),
+            span,
+        }
+    }
+
+    fn fold_kind_mapping_missing_regions_to_empty(
+        &mut self,
+        kind: GenericArg<'tcx>,
+    ) -> GenericArg<'tcx> {
+        assert!(!self.map_missing_regions_to_empty);
+        self.map_missing_regions_to_empty = true;
+        let kind = kind.fold_with(self);
+        self.map_missing_regions_to_empty = false;
+        kind
+    }
+
+    fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
+        assert!(!self.map_missing_regions_to_empty);
+        kind.fold_with(self)
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    #[instrument(skip(self), level = "debug")]
+    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+        match *r {
+            // Ignore bound regions and `'static` regions that appear in the
+            // type, we only need to remap regions that reference lifetimes
+            // from the function declaration.
+            // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
+            ty::ReLateBound(..) | ty::ReStatic => return r,
+
+            // If regions have been erased (by writeback), don't try to unerase
+            // them.
+            ty::ReErased => return r,
+
+            // The regions that we expect from borrow checking.
+            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
+
+            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
+                // All of the regions in the type should either have been
+                // erased by writeback, or mapped back to named regions by
+                // borrow checking.
+                bug!("unexpected region kind in opaque type: {:?}", r);
+            }
+        }
+
+        let generics = self.tcx().generics_of(self.opaque_type_def_id);
+        match self.map.get(&r.into()).map(|k| k.unpack()) {
+            Some(GenericArgKind::Lifetime(r1)) => r1,
+            Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
+            None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
+            None if generics.parent.is_some() => {
+                if let Some(hidden_ty) = self.hidden_ty.take() {
+                    unexpected_hidden_region_diagnostic(
+                        self.tcx,
+                        self.tcx.def_span(self.opaque_type_def_id),
+                        hidden_ty,
+                        r,
+                    )
+                    .emit();
+                }
+                self.tcx.lifetimes.re_root_empty
+            }
+            None => {
+                self.tcx
+                    .sess
+                    .struct_span_err(self.span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        self.span,
+                        format!(
+                            "lifetime `{}` is part of concrete type but not used in \
+                                 parameter list of the `impl Trait` type alias",
+                            r
+                        ),
+                    )
+                    .emit();
+
+                self.tcx().lifetimes.re_static
+            }
+        }
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        match *ty.kind() {
+            ty::Closure(def_id, substs) => {
+                // I am a horrible monster and I pray for death. When
+                // we encounter a closure here, it is always a closure
+                // from within the function that we are currently
+                // type-checking -- one that is now being encapsulated
+                // in an opaque type. Ideally, we would
+                // go through the types/lifetimes that it references
+                // and treat them just like we would any other type,
+                // which means we would error out if we find any
+                // reference to a type/region that is not in the
+                // "reverse map".
+                //
+                // **However,** in the case of closures, there is a
+                // somewhat subtle (read: hacky) consideration. The
+                // problem is that our closure types currently include
+                // all the lifetime parameters declared on the
+                // enclosing function, even if they are unused by the
+                // closure itself. We can't readily filter them out,
+                // so here we replace those values with `'empty`. This
+                // can't really make a difference to the rest of the
+                // compiler; those regions are ignored for the
+                // outlives relation, and hence don't affect trait
+                // selection or auto traits, and they are erased
+                // during codegen.
+
+                let generics = self.tcx.generics_of(def_id);
+                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+                    if index < generics.parent_count {
+                        // Accommodate missing regions in the parent kinds...
+                        self.fold_kind_mapping_missing_regions_to_empty(kind)
+                    } else {
+                        // ...but not elsewhere.
+                        self.fold_kind_normally(kind)
+                    }
+                }));
+
+                self.tcx.mk_closure(def_id, substs)
+            }
+
+            ty::Generator(def_id, substs, movability) => {
+                let generics = self.tcx.generics_of(def_id);
+                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
+                    if index < generics.parent_count {
+                        // Accommodate missing regions in the parent kinds...
+                        self.fold_kind_mapping_missing_regions_to_empty(kind)
+                    } else {
+                        // ...but not elsewhere.
+                        self.fold_kind_normally(kind)
+                    }
+                }));
+
+                self.tcx.mk_generator(def_id, substs, movability)
+            }
+
+            ty::Param(param) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ty.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list; replace with the parameter from the
+                    // opaque type.
+                    Some(GenericArgKind::Type(t1)) => t1,
+                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
+                    None => {
+                        debug!(?param, ?self.map);
+                        self.tcx
+                            .sess
+                            .struct_span_err(
+                                self.span,
+                                &format!(
+                                    "type parameter `{}` is part of concrete type but not \
+                                          used in parameter list for the `impl Trait` type alias",
+                                    ty
+                                ),
+                            )
+                            .emit();
+
+                        self.tcx().ty_error()
+                    }
+                }
+            }
+
+            _ => ty.super_fold_with(self),
+        }
+    }
+
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        trace!("checking const {:?}", ct);
+        // Find a const parameter
+        match ct.kind() {
+            ty::ConstKind::Param(..) => {
+                // Look it up in the substitution list.
+                match self.map.get(&ct.into()).map(|k| k.unpack()) {
+                    // Found it in the substitution list, replace with the parameter from the
+                    // opaque type.
+                    Some(GenericArgKind::Const(c1)) => c1,
+                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
+                    None => {
+                        self.tcx
+                            .sess
+                            .struct_span_err(
+                                self.span,
+                                &format!(
+                                    "const parameter `{}` is part of concrete type but not \
+                                          used in parameter list for the `impl Trait` type alias",
+                                    ct
+                                ),
+                            )
+                            .emit();
+
+                        self.tcx().const_error(ct.ty())
+                    }
+                }
+            }
+
+            _ => ct,
+        }
+    }
+}
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 5e33d9d25c2..3f9c0cecccc 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index b88f6e689cc..fda2cee43fb 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -157,7 +157,7 @@ impl LocalUseMapBuild<'_> {
 }
 
 impl Visitor<'_> for LocalUseMapBuild<'_> {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
         if self.locals_with_use_data[local] {
             match def_use::categorize(context) {
                 Some(DefUse::Def) => self.insert_def(local, location),
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
index ac8670a5138..d5c401ae1c6 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs
@@ -1,11 +1,11 @@
+use itertools::{Either, Itertools};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::mir::{Body, Local};
 use rustc_middle::ty::{RegionVid, TyCtxt};
-use std::rc::Rc;
-
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
+use std::rc::Rc;
 
 use crate::{
     constraints::OutlivesConstraintSet,
@@ -46,7 +46,8 @@ pub(super) fn generate<'mir, 'tcx>(
         &typeck.borrowck_context.universal_regions,
         &typeck.borrowck_context.constraints.outlives_constraints,
     );
-    let live_locals = compute_live_locals(typeck.tcx(), &free_regions, &body);
+    let (relevant_live_locals, boring_locals) =
+        compute_relevant_live_locals(typeck.tcx(), &free_regions, &body);
     let facts_enabled = use_polonius || AllFacts::enabled(typeck.tcx());
 
     let polonius_drop_used = if facts_enabled {
@@ -57,48 +58,44 @@ pub(super) fn generate<'mir, 'tcx>(
         None
     };
 
-    if !live_locals.is_empty() || facts_enabled {
-        trace::trace(
-            typeck,
-            body,
-            elements,
-            flow_inits,
-            move_data,
-            live_locals,
-            polonius_drop_used,
-        );
-    }
+    trace::trace(
+        typeck,
+        body,
+        elements,
+        flow_inits,
+        move_data,
+        relevant_live_locals,
+        boring_locals,
+        polonius_drop_used,
+    );
 }
 
-// The purpose of `compute_live_locals` is to define the subset of `Local`
+// The purpose of `compute_relevant_live_locals` is to define the subset of `Local`
 // variables for which we need to do a liveness computation. We only need
 // to compute whether a variable `X` is live if that variable contains
 // some region `R` in its type where `R` is not known to outlive a free
 // region (i.e., where `R` may be valid for just a subset of the fn body).
-fn compute_live_locals<'tcx>(
+fn compute_relevant_live_locals<'tcx>(
     tcx: TyCtxt<'tcx>,
     free_regions: &FxHashSet<RegionVid>,
     body: &Body<'tcx>,
-) -> Vec<Local> {
-    let live_locals: Vec<Local> = body
-        .local_decls
-        .iter_enumerated()
-        .filter_map(|(local, local_decl)| {
+) -> (Vec<Local>, Vec<Local>) {
+    let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) =
+        body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| {
             if tcx.all_free_regions_meet(&local_decl.ty, |r| {
                 free_regions.contains(&r.to_region_vid())
             }) {
-                None
+                Either::Left(local)
             } else {
-                Some(local)
+                Either::Right(local)
             }
-        })
-        .collect();
+        });
 
     debug!("{} total variables", body.local_decls.len());
-    debug!("{} variables need liveness", live_locals.len());
+    debug!("{} variables need liveness", relevant_live_locals.len());
     debug!("{} regions outlive free regions", free_regions.len());
 
-    live_locals
+    (relevant_live_locals, boring_locals)
 }
 
 /// Computes all regions that are (currently) known to outlive free
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 8070f357919..bc76a465e3c 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -54,7 +54,7 @@ impl UseFactsExtractor<'_, '_> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UseFactsExtractor<'a, 'tcx> {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
         match def_use::categorize(context) {
             Some(DefUse::Def) => self.insert_def(local, location),
             Some(DefUse::Use) => self.insert_use(local, location),
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 169de23facc..3795378b568 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -3,7 +3,7 @@ use rustc_index::bit_set::HybridBitSet;
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
-use rustc_middle::ty::{Ty, TypeFoldable};
+use rustc_middle::ty::{Ty, TypeVisitable};
 use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
 use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
@@ -41,12 +41,13 @@ pub(super) fn trace<'mir, 'tcx>(
     elements: &Rc<RegionValueElements>,
     flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
     move_data: &MoveData<'tcx>,
-    live_locals: Vec<Local>,
+    relevant_live_locals: Vec<Local>,
+    boring_locals: Vec<Local>,
     polonius_drop_used: Option<Vec<(Local, Location)>>,
 ) {
     debug!("trace()");
 
-    let local_use_map = &LocalUseMap::build(&live_locals, elements, body);
+    let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
 
     let cx = LivenessContext {
         typeck,
@@ -61,10 +62,12 @@ pub(super) fn trace<'mir, 'tcx>(
     let mut results = LivenessResults::new(cx);
 
     if let Some(drop_used) = polonius_drop_used {
-        results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect())
+        results.add_extra_drop_facts(drop_used, relevant_live_locals.iter().copied().collect())
     }
 
-    results.compute_for_all_locals(live_locals);
+    results.compute_for_all_locals(relevant_live_locals);
+
+    results.dropck_boring_locals(boring_locals);
 }
 
 /// Contextual state for the type-liveness generator.
@@ -133,8 +136,8 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         }
     }
 
-    fn compute_for_all_locals(&mut self, live_locals: Vec<Local>) {
-        for local in live_locals {
+    fn compute_for_all_locals(&mut self, relevant_live_locals: Vec<Local>) {
+        for local in relevant_live_locals {
             self.reset_local_state();
             self.add_defs_for(local);
             self.compute_use_live_points_for(local);
@@ -157,6 +160,24 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         }
     }
 
+    // Runs dropck for locals whose liveness isn't relevant. This is
+    // necessary to eagerly detect unbound recursion during drop glue computation.
+    fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
+        for local in boring_locals {
+            let local_ty = self.cx.body.local_decls[local].ty;
+            let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
+                let typeck = &mut self.cx.typeck;
+                move || LivenessContext::compute_drop_data(typeck, local_ty)
+            });
+
+            drop_data.dropck_result.report_overflows(
+                self.cx.typeck.infcx.tcx,
+                self.cx.body.local_decls[local].source_info.span,
+                local_ty,
+            );
+        }
+    }
+
     /// Add extra drop facts needed for Polonius.
     ///
     /// Add facts for all locals with free regions, since regions may outlive
@@ -164,12 +185,12 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
     fn add_extra_drop_facts(
         &mut self,
         drop_used: Vec<(Local, Location)>,
-        live_locals: FxHashSet<Local>,
+        relevant_live_locals: FxHashSet<Local>,
     ) {
         let locations = IntervalSet::new(self.cx.elements.num_points());
 
         for (local, location) in drop_used {
-            if !live_locals.contains(&local) {
+            if !relevant_live_locals.contains(&local) {
                 let local_ty = self.cx.body.local_decls[local].ty;
                 if local_ty.has_free_regions() {
                     self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
@@ -237,7 +258,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
 
                 let block = self.cx.elements.to_location(block_start).block;
                 self.stack.extend(
-                    self.cx.body.predecessors()[block]
+                    self.cx.body.basic_blocks.predecessors()[block]
                         .iter()
                         .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
                         .map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
@@ -333,7 +354,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
         }
 
         let body = self.cx.body;
-        for &pred_block in body.predecessors()[block].iter() {
+        for &pred_block in body.basic_blocks.predecessors()[block].iter() {
             debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
 
             // Check whether the variable is (at least partially)
@@ -456,7 +477,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     /// points `live_at`.
     fn add_use_live_facts_for(
         &mut self,
-        value: impl TypeFoldable<'tcx>,
+        value: impl TypeVisitable<'tcx>,
         live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("add_use_live_facts_for(value={:?})", value);
@@ -521,7 +542,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
     fn make_all_regions_live(
         elements: &RegionValueElements,
         typeck: &mut TypeChecker<'_, 'tcx>,
-        value: impl TypeFoldable<'tcx>,
+        value: impl TypeVisitable<'tcx>,
         live_at: &IntervalSet<PointIndex>,
     ) {
         debug!("make_all_regions_live(value={:?})", value);
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 5ee1f5a8e8e..d71a4983a92 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -27,8 +27,8 @@ use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::*;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
     self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
     OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
@@ -333,9 +333,9 @@ struct TypeVerifier<'a, 'b, 'tcx> {
 }
 
 impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
-    fn visit_span(&mut self, span: &Span) {
+    fn visit_span(&mut self, span: Span) {
         if !span.is_dummy() {
-            self.last_span = *span;
+            self.last_span = span;
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 89d84fcf09c..2a7713bc4df 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -503,7 +503,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
         let root_empty = self
             .infcx
-            .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion)
+            .next_nll_region_var(NllRegionVariableOrigin::Existential { from_forall: true })
             .to_region_vid();
 
         UniversalRegions {
diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
index 1093167fa82..8833753b12c 100644
--- a/compiler/rustc_borrowck/src/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -91,8 +91,8 @@ impl<'visit, 'cx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'tc
         self.super_statement(statement, location);
     }
 
-    fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
-        if place_context.is_place_assignment() && self.temporary_used_locals.contains(local) {
+    fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
+        if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) {
             // Propagate the Local assigned at this Location as a used mutable local variable
             for moi in &self.mbcx.move_data.loc_map[location] {
                 let mpi = &self.mbcx.move_data.moves[*moi].path;
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 1c507678489..9cd72ed0c67 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -2,8 +2,8 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, Generics, ItemKind, MetaItem, VariantData};
+use rustc_ast::{self as ast, Generics, ItemKind, MetaItem, VariantData};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -80,7 +80,7 @@ pub fn expand_deriving_clone(
             name: sym::clone,
             generics: Bounds::empty(),
             explicit_self: true,
-            args: Vec::new(),
+            nonself_args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
             unify_fieldless_variants: false,
@@ -98,22 +98,31 @@ fn cs_clone_simple(
     trait_span: Span,
     substr: &Substructure<'_>,
     is_union: bool,
-) -> P<Expr> {
+) -> BlockOrExpr {
     let mut stmts = Vec::new();
+    let mut seen_type_names = FxHashSet::default();
     let mut process_variant = |variant: &VariantData| {
         for field in variant.fields() {
-            // let _: AssertParamIsClone<FieldTy>;
-            super::assert_ty_bounds(
-                cx,
-                &mut stmts,
-                field.ty.clone(),
-                field.span,
-                &[sym::clone, sym::AssertParamIsClone],
-            );
+            // This basic redundancy checking only prevents duplication of
+            // assertions like `AssertParamIsClone<Foo>` where the type is a
+            // simple name. That's enough to get a lot of cases, though.
+            if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+                // Already produced an assertion for this type.
+            } else {
+                // let _: AssertParamIsClone<FieldTy>;
+                super::assert_ty_bounds(
+                    cx,
+                    &mut stmts,
+                    field.ty.clone(),
+                    field.span,
+                    &[sym::clone, sym::AssertParamIsClone],
+                );
+            }
         }
     };
 
     if is_union {
+        // Just a single assertion for unions, that the union impls `Copy`.
         // let _: AssertParamIsCopy<Self>;
         let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
         super::assert_ty_bounds(
@@ -139,8 +148,7 @@ fn cs_clone_simple(
             ),
         }
     }
-    stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span))));
-    cx.expr_block(cx.block(trait_span, stmts))
+    BlockOrExpr::new_mixed(stmts, cx.expr_deref(trait_span, cx.expr_self(trait_span)))
 }
 
 fn cs_clone(
@@ -148,12 +156,12 @@ fn cs_clone(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-) -> P<Expr> {
+) -> BlockOrExpr {
     let ctor_path;
     let all_fields;
     let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
-    let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo<'_>| {
-        let args = vec![cx.expr_addr_of(field.span, field.self_.clone())];
+    let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| {
+        let args = vec![cx.expr_addr_of(field.span, field.self_expr.clone())];
         cx.expr_call_global(field.span, fn_path.clone(), args)
     };
 
@@ -177,7 +185,7 @@ fn cs_clone(
         }
     }
 
-    match *vdata {
+    let expr = match *vdata {
         VariantData::Struct(..) => {
             let fields = all_fields
                 .iter()
@@ -201,5 +209,6 @@ fn cs_clone(
             cx.expr_call(trait_span, path, subcalls)
         }
         VariantData::Unit(..) => cx.expr_path(ctor_path),
-    }
+    };
+    BlockOrExpr::new_expr(expr)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index cb2ad283a19..4e798bf6acb 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -2,8 +2,8 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, MetaItem};
+use rustc_ast::{self as ast, MetaItem};
+use rustc_data_structures::fx::FxHashSet;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -32,7 +32,7 @@ pub fn expand_deriving_eq(
             name: sym::assert_receiver_is_total_eq,
             generics: Bounds::empty(),
             explicit_self: true,
-            args: vec![],
+            nonself_args: vec![],
             ret_ty: Unit,
             attributes: attrs,
             unify_fieldless_variants: true,
@@ -52,18 +52,26 @@ fn cs_total_eq_assert(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
-) -> P<Expr> {
+) -> BlockOrExpr {
     let mut stmts = Vec::new();
+    let mut seen_type_names = FxHashSet::default();
     let mut process_variant = |variant: &ast::VariantData| {
         for field in variant.fields() {
-            // let _: AssertParamIsEq<FieldTy>;
-            super::assert_ty_bounds(
-                cx,
-                &mut stmts,
-                field.ty.clone(),
-                field.span,
-                &[sym::cmp, sym::AssertParamIsEq],
-            );
+            // This basic redundancy checking only prevents duplication of
+            // assertions like `AssertParamIsEq<Foo>` where the type is a
+            // simple name. That's enough to get a lot of cases, though.
+            if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+                // Already produced an assertion for this type.
+            } else {
+                // let _: AssertParamIsEq<FieldTy>;
+                super::assert_ty_bounds(
+                    cx,
+                    &mut stmts,
+                    field.ty.clone(),
+                    field.span,
+                    &[sym::cmp, sym::AssertParamIsEq],
+                );
+            }
         }
     };
 
@@ -78,5 +86,5 @@ fn cs_total_eq_assert(
         }
         _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
     }
-    cx.expr_block(cx.block(trait_span, stmts))
+    BlockOrExpr::new_stmts(stmts)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index c7850cd4b4c..859e995356e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, MetaItem};
+use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -28,7 +27,7 @@ pub fn expand_deriving_ord(
             name: sym::cmp,
             generics: Bounds::empty(),
             explicit_self: true,
-            args: vec![(self_ref(), sym::other)],
+            nonself_args: vec![(self_ref(), sym::other)],
             ret_ty: Path(path_std!(cmp::Ordering)),
             attributes: attrs,
             unify_fieldless_variants: true,
@@ -40,72 +39,54 @@ pub fn expand_deriving_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn ordering_collapsed(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    self_arg_tags: &[Ident],
-) -> P<ast::Expr> {
-    let lft = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[0]));
-    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
-    let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
-    cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
-}
-
-pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
+pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
-    let equals_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
-
+    let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
 
     // Builds:
     //
-    // match ::std::cmp::Ord::cmp(&self_field1, &other_field1) {
-    // ::std::cmp::Ordering::Equal =>
-    // match ::std::cmp::Ord::cmp(&self_field2, &other_field2) {
-    // ::std::cmp::Ordering::Equal => {
-    // ...
+    // match ::core::cmp::Ord::cmp(&self.x, &other.x) {
+    //     ::std::cmp::Ordering::Equal =>
+    //         ::core::cmp::Ord::cmp(&self.y, &other.y),
+    //     cmp => cmp,
     // }
-    // cmp => cmp
-    // },
-    // cmp => cmp
-    // }
-    //
-    cs_fold(
+    let expr = cs_fold(
         // foldr nests the if-elses correctly, leaving the first field
         // as the outermost one, and the last as the innermost.
         false,
-        |cx, span, old, self_f, other_fs| {
-            // match new {
-            //     ::std::cmp::Ordering::Equal => old,
-            //     cmp => cmp
-            // }
-
-            let new = {
-                let [other_f] = other_fs else {
-                    cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`");
-                };
-
-                let args =
-                    vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
-
-                cx.expr_call_global(span, cmp_path.clone(), args)
-            };
-
-            let eq_arm = cx.arm(span, cx.pat_path(span, equals_path.clone()), old);
-            let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
-
-            cx.expr_match(span, new, vec![eq_arm, neq_arm])
-        },
-        cx.expr_path(equals_path.clone()),
-        Box::new(|cx, span, tag_tuple| {
-            if tag_tuple.len() != 2 {
-                cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
-            } else {
-                ordering_collapsed(cx, span, tag_tuple)
-            }
-        }),
         cx,
         span,
         substr,
-    )
+        |cx, fold| match fold {
+            CsFold::Single(field) => {
+                let [other_expr] = &field.other_selflike_exprs[..] else {
+                        cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
+                    };
+                let args = vec![
+                    cx.expr_addr_of(field.span, field.self_expr.clone()),
+                    cx.expr_addr_of(field.span, other_expr.clone()),
+                ];
+                cx.expr_call_global(field.span, cmp_path.clone(), args)
+            }
+            CsFold::Combine(span, expr1, expr2) => {
+                let eq_arm = cx.arm(span, cx.pat_path(span, equal_path.clone()), expr1);
+                let neq_arm =
+                    cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
+                cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+            }
+            CsFold::Fieldless => cx.expr_path(equal_path.clone()),
+            CsFold::EnumNonMatching(span, tag_tuple) => {
+                if tag_tuple.len() != 2 {
+                    cx.span_bug(span, "not exactly 2 arguments in `derive(Ord)`")
+                } else {
+                    let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
+                    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
+                    let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
+                    cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
+                }
+            }
+        },
+    );
+    BlockOrExpr::new_expr(expr)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index ca5ca29eb82..724c639984c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_local, path_std};
 
-use rustc_ast::ptr::P;
-use rustc_ast::{BinOpKind, Expr, MetaItem};
+use rustc_ast::{BinOpKind, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -15,8 +14,6 @@ pub fn expand_deriving_partial_eq(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    // structures are equal if all fields are equal, and non equal, if
-    // any fields are not equal or if the enum variants are different
     fn cs_op(
         cx: &mut ExtCtxt<'_>,
         span: Span,
@@ -24,41 +21,31 @@ pub fn expand_deriving_partial_eq(
         op: BinOpKind,
         combiner: BinOpKind,
         base: bool,
-    ) -> P<Expr> {
-        let op = |cx: &mut ExtCtxt<'_>, span: Span, self_f: P<Expr>, other_fs: &[P<Expr>]| {
-            let [other_f] = other_fs else {
-                cx.span_bug(span, "not exactly 2 arguments in `derive(PartialEq)`");
-            };
-
-            cx.expr_binary(span, op, self_f, other_f.clone())
-        };
-
-        cs_fold1(
+    ) -> BlockOrExpr {
+        let expr = cs_fold(
             true, // use foldl
-            |cx, span, subexpr, self_f, other_fs| {
-                let eq = op(cx, span, self_f, other_fs);
-                cx.expr_binary(span, combiner, subexpr, eq)
-            },
-            |cx, args| {
-                match args {
-                    Some((span, self_f, other_fs)) => {
-                        // Special-case the base case to generate cleaner code.
-                        op(cx, span, self_f, other_fs)
-                    }
-                    None => cx.expr_bool(span, base),
-                }
-            },
-            Box::new(|cx, span, _| cx.expr_bool(span, !base)),
             cx,
             span,
             substr,
-        )
+            |cx, fold| match fold {
+                CsFold::Single(field) => {
+                    let [other_expr] = &field.other_selflike_exprs[..] else {
+                        cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
+                    };
+                    cx.expr_binary(field.span, op, field.self_expr.clone(), other_expr.clone())
+                }
+                CsFold::Combine(span, expr1, expr2) => cx.expr_binary(span, combiner, expr1, expr2),
+                CsFold::Fieldless => cx.expr_bool(span, base),
+                CsFold::EnumNonMatching(span, _tag_tuple) => cx.expr_bool(span, !base),
+            },
+        );
+        BlockOrExpr::new_expr(expr)
     }
 
-    fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
+    fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         cs_op(cx, span, substr, BinOpKind::Eq, BinOpKind::And, true)
     }
-    fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
+    fn cs_ne(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         cs_op(cx, span, substr, BinOpKind::Ne, BinOpKind::Or, false)
     }
 
@@ -70,7 +57,7 @@ pub fn expand_deriving_partial_eq(
                 name: $name,
                 generics: Bounds::empty(),
                 explicit_self: true,
-                args: vec![(self_ref(), sym::other)],
+                nonself_args: vec![(self_ref(), sym::other)],
                 ret_ty: Path(path_local!(bool)),
                 attributes: attrs,
                 unify_fieldless_variants: true,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 07db82fee93..3f9843922da 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{path_std, pathvec_std};
 
-use rustc_ast::ptr::P;
-use rustc_ast::{Expr, MetaItem};
+use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -26,7 +25,7 @@ pub fn expand_deriving_partial_ord(
         name: sym::partial_cmp,
         generics: Bounds::empty(),
         explicit_self: true,
-        args: vec![(self_ref(), sym::other)],
+        nonself_args: vec![(self_ref(), sym::other)],
         ret_ty,
         attributes: attrs,
         unify_fieldless_variants: true,
@@ -48,67 +47,56 @@ pub fn expand_deriving_partial_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
+pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
-    let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
-    let ordering_expr = cx.expr_path(ordering.clone());
-    let equals_expr = cx.expr_some(span, ordering_expr);
-
+    let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let partial_cmp_path = cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
 
     // Builds:
     //
-    // match ::std::cmp::PartialOrd::partial_cmp(&self_field1, &other_field1) {
-    // ::std::option::Option::Some(::std::cmp::Ordering::Equal) =>
-    // match ::std::cmp::PartialOrd::partial_cmp(&self_field2, &other_field2) {
-    // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => {
-    // ...
-    // }
-    // cmp => cmp
-    // },
-    // cmp => cmp
+    // match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
+    //     ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+    //         ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
+    //     cmp => cmp,
     // }
-    //
-    cs_fold(
+    let expr = cs_fold(
         // foldr nests the if-elses correctly, leaving the first field
         // as the outermost one, and the last as the innermost.
         false,
-        |cx, span, old, self_f, other_fs| {
-            // match new {
-            //     Some(::std::cmp::Ordering::Equal) => old,
-            //     cmp => cmp
-            // }
-
-            let new = {
-                let [other_f] = other_fs else {
-                    cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`");
-                };
-
-                let args =
-                    vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())];
-
-                cx.expr_call_global(span, partial_cmp_path.clone(), args)
-            };
-
-            let eq_arm = cx.arm(span, cx.pat_some(span, cx.pat_path(span, ordering.clone())), old);
-            let neq_arm = cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
-
-            cx.expr_match(span, new, vec![eq_arm, neq_arm])
-        },
-        equals_expr,
-        Box::new(|cx, span, tag_tuple| {
-            if tag_tuple.len() != 2 {
-                cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
-            } else {
-                let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
-                let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
-                let fn_partial_cmp_path =
-                    cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
-                cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
-            }
-        }),
         cx,
         span,
         substr,
-    )
+        |cx, fold| match fold {
+            CsFold::Single(field) => {
+                let [other_expr] = &field.other_selflike_exprs[..] else {
+                        cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
+                    };
+                let args = vec![
+                    cx.expr_addr_of(field.span, field.self_expr.clone()),
+                    cx.expr_addr_of(field.span, other_expr.clone()),
+                ];
+                cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
+            }
+            CsFold::Combine(span, expr1, expr2) => {
+                let eq_arm =
+                    cx.arm(span, cx.pat_some(span, cx.pat_path(span, equal_path.clone())), expr1);
+                let neq_arm =
+                    cx.arm(span, cx.pat_ident(span, test_id), cx.expr_ident(span, test_id));
+                cx.expr_match(span, expr2, vec![eq_arm, neq_arm])
+            }
+            CsFold::Fieldless => cx.expr_some(span, cx.expr_path(equal_path.clone())),
+            CsFold::EnumNonMatching(span, tag_tuple) => {
+                if tag_tuple.len() != 2 {
+                    cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
+                } else {
+                    let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
+                    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
+                    let fn_partial_cmp_path =
+                        cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
+                    cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
+                }
+            }
+        },
+    );
+    BlockOrExpr::new_expr(expr)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 1411c60c0bf..b99198054de 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, MetaItem};
+use rustc_ast::{self as ast, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -29,7 +28,7 @@ pub fn expand_deriving_debug(
             name: sym::fmt,
             generics: Bounds::empty(),
             explicit_self: true,
-            args: vec![(fmtr, sym::f)],
+            nonself_args: vec![(fmtr, sym::f)],
             ret_ty: Path(path_std!(fmt::Result)),
             attributes: Vec::new(),
             unify_fieldless_variants: false,
@@ -42,7 +41,7 @@ pub fn expand_deriving_debug(
     trait_def.expand(cx, mitem, item, push)
 }
 
-fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
+fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let (ident, vdata, fields) = match substr.fields {
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
         EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
@@ -54,7 +53,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
     let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
-    let fmt = substr.nonself_args[0].clone();
+    let fmt = substr.nonselflike_args[0].clone();
 
     // Struct and tuples are similar enough that we use the same code for both,
     // with some extra pieces for structs due to the field names.
@@ -74,7 +73,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
     if fields.is_empty() {
         // Special case for no fields.
         let fn_path_write_str = cx.std_path(&[sym::fmt, sym::Formatter, sym::write_str]);
-        cx.expr_call_global(span, fn_path_write_str, vec![fmt, name])
+        let expr = cx.expr_call_global(span, fn_path_write_str, vec![fmt, name]);
+        BlockOrExpr::new_expr(expr)
     } else if fields.len() <= CUTOFF {
         // Few enough fields that we can use a specific-length method.
         let debug = if is_struct {
@@ -96,11 +96,12 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
                 args.push(name);
             }
             // Use double indirection to make sure this works for unsized types
-            let field = cx.expr_addr_of(field.span, field.self_.clone());
+            let field = cx.expr_addr_of(field.span, field.self_expr.clone());
             let field = cx.expr_addr_of(field.span, field);
             args.push(field);
         }
-        cx.expr_call_global(span, fn_path_debug, args)
+        let expr = cx.expr_call_global(span, fn_path_debug, args);
+        BlockOrExpr::new_expr(expr)
     } else {
         // Enough fields that we must use the any-length method.
         let mut name_exprs = Vec::with_capacity(fields.len());
@@ -115,7 +116,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
             }
 
             // Use double indirection to make sure this works for unsized types
-            let value_ref = cx.expr_addr_of(field.span, field.self_.clone());
+            let value_ref = cx.expr_addr_of(field.span, field.self_expr.clone());
             value_exprs.push(cx.expr_addr_of(field.span, value_ref));
         }
 
@@ -176,8 +177,6 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
             stmts.push(names_let.unwrap());
         }
         stmts.push(values_let);
-        stmts.push(cx.stmt_expr(expr));
-
-        cx.expr_block(cx.block(span, stmts))
+        BlockOrExpr::new_mixed(stmts, expr)
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 16154fb4d03..d688143a2a5 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -36,7 +36,10 @@ pub fn expand_deriving_rustc_decodable(
                 )],
             },
             explicit_self: false,
-            args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::d)],
+            nonself_args: vec![(
+                Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
+                sym::d,
+            )],
             ret_ty: Path(Path::new_(
                 pathvec_std!(result::Result),
                 vec![
@@ -62,8 +65,8 @@ fn decodable_substructure(
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
-) -> P<Expr> {
-    let decoder = substr.nonself_args[0].clone();
+) -> BlockOrExpr {
+    let decoder = substr.nonselflike_args[0].clone();
     let recurse = vec![
         Ident::new(krate, trait_span),
         Ident::new(sym::Decodable, trait_span),
@@ -74,7 +77,7 @@ fn decodable_substructure(
     let blkarg = Ident::new(sym::_d, trait_span);
     let blkdecoder = cx.expr_ident(trait_span, blkarg);
 
-    match *substr.fields {
+    let expr = match *substr.fields {
         StaticStruct(_, ref summary) => {
             let nfields = match *summary {
                 Unnamed(ref fields, _) => fields.len(),
@@ -173,7 +176,8 @@ fn decodable_substructure(
             )
         }
         _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
-    }
+    };
+    BlockOrExpr::new_expr(expr)
 }
 
 /// Creates a decoder for a single enum variant/struct:
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index d41b25343b0..5177690917f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -1,11 +1,10 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 
-use rustc_ast::ptr::P;
+use rustc_ast as ast;
 use rustc_ast::walk_list;
 use rustc_ast::EnumDef;
 use rustc_ast::VariantData;
-use rustc_ast::{Expr, MetaItem};
 use rustc_errors::Applicability;
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use rustc_span::symbol::Ident;
@@ -16,7 +15,7 @@ use smallvec::SmallVec;
 pub fn expand_deriving_default(
     cx: &mut ExtCtxt<'_>,
     span: Span,
-    mitem: &MetaItem,
+    mitem: &ast::MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
@@ -35,7 +34,7 @@ pub fn expand_deriving_default(
             name: kw::Default,
             generics: Bounds::empty(),
             explicit_self: false,
-            args: Vec::new(),
+            nonself_args: Vec::new(),
             ret_ty: Self_,
             attributes: attrs,
             unify_fieldless_variants: false,
@@ -59,12 +58,12 @@ fn default_struct_substructure(
     trait_span: Span,
     substr: &Substructure<'_>,
     summary: &StaticFields,
-) -> P<Expr> {
+) -> BlockOrExpr {
     // Note that `kw::Default` is "default" and `sym::Default` is "Default"!
     let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
 
-    match summary {
+    let expr = match summary {
         Unnamed(ref fields, is_tuple) => {
             if !is_tuple {
                 cx.expr_ident(trait_span, substr.type_ident)
@@ -80,31 +79,27 @@ fn default_struct_substructure(
                 .collect();
             cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
         }
-    }
+    };
+    BlockOrExpr::new_expr(expr)
 }
 
 fn default_enum_substructure(
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     enum_def: &EnumDef,
-) -> P<Expr> {
-    let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) else {
-        return DummyResult::raw_expr(trait_span, true);
+) -> BlockOrExpr {
+    let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span)
+        && let Ok(_) = validate_default_attribute(cx, default_variant)
+    {
+        // We now know there is exactly one unit variant with exactly one `#[default]` attribute.
+        cx.expr_path(cx.path(
+            default_variant.span,
+            vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
+        ))
+    } else {
+        DummyResult::raw_expr(trait_span, true)
     };
-
-    // At this point, we know that there is exactly one variant with a `#[default]` attribute. The
-    // attribute hasn't yet been validated.
-
-    if let Err(()) = validate_default_attribute(cx, default_variant) {
-        return DummyResult::raw_expr(trait_span, true);
-    }
-
-    // We now know there is exactly one unit variant with exactly one `#[default]` attribute.
-
-    cx.expr_path(cx.path(
-        default_variant.span,
-        vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
-    ))
+    BlockOrExpr::new_expr(expr)
 }
 
 fn extract_default_variant<'a>(
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 7dc0584618d..49dbe51f762 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -89,8 +89,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::pathvec_std;
 
-use rustc_ast::ptr::P;
-use rustc_ast::{Expr, ExprKind, MetaItem, Mutability};
+use rustc_ast::{ExprKind, MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
@@ -121,7 +120,10 @@ pub fn expand_deriving_rustc_encodable(
                 )],
             },
             explicit_self: true,
-            args: vec![(Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut), sym::s)],
+            nonself_args: vec![(
+                Ref(Box::new(Path(Path::new_local(typaram))), Mutability::Mut),
+                sym::s,
+            )],
             ret_ty: Path(Path::new_(
                 pathvec_std!(result::Result),
                 vec![
@@ -147,8 +149,8 @@ fn encodable_substructure(
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
-) -> P<Expr> {
-    let encoder = substr.nonself_args[0].clone();
+) -> BlockOrExpr {
+    let encoder = substr.nonselflike_args[0].clone();
     // throw an underscore in front to suppress unused variable warnings
     let blkarg = Ident::new(sym::_e, trait_span);
     let blkencoder = cx.expr_ident(trait_span, blkarg);
@@ -166,12 +168,12 @@ fn encodable_substructure(
             let fn_emit_struct_field_path =
                 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
             let mut stmts = Vec::new();
-            for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
+            for (i, &FieldInfo { name, ref self_expr, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
                     Some(id) => id.name,
                     None => Symbol::intern(&format!("_field{}", i)),
                 };
-                let self_ref = cx.expr_addr_of(span, self_.clone());
+                let self_ref = cx.expr_addr_of(span, self_expr.clone());
                 let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                 let lambda = cx.lambda1(span, enc, blkarg);
                 let call = cx.expr_call_global(
@@ -208,7 +210,7 @@ fn encodable_substructure(
             let fn_emit_struct_path =
                 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
 
-            cx.expr_call_global(
+            let expr = cx.expr_call_global(
                 trait_span,
                 fn_emit_struct_path,
                 vec![
@@ -217,7 +219,8 @@ fn encodable_substructure(
                     cx.expr_usize(trait_span, fields.len()),
                     blk,
                 ],
-            )
+            );
+            BlockOrExpr::new_expr(expr)
         }
 
         EnumMatching(idx, _, variant, ref fields) => {
@@ -234,8 +237,8 @@ fn encodable_substructure(
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
-                for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
-                    let self_ref = cx.expr_addr_of(span, self_.clone());
+                for (i, &FieldInfo { ref self_expr, span, .. }) in fields.iter().enumerate() {
+                    let self_ref = cx.expr_addr_of(span, self_expr.clone());
                     let enc =
                         cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                     let lambda = cx.lambda1(span, enc, blkarg);
@@ -279,12 +282,12 @@ fn encodable_substructure(
             let blk = cx.lambda1(trait_span, call, blkarg);
             let fn_emit_enum_path: Vec<_> =
                 cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
-            let ret = cx.expr_call_global(
+            let expr = cx.expr_call_global(
                 trait_span,
                 fn_emit_enum_path,
                 vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
             );
-            cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
+            BlockOrExpr::new_mixed(vec![me], expr)
         }
 
         _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index ff431c8de5d..74e18bffc2e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -66,7 +66,7 @@
 //!
 //! # "`cs`" functions
 //!
-//! The `cs_...` functions ("combine substructure) are designed to
+//! The `cs_...` functions ("combine substructure") are designed to
 //! make life easier by providing some pre-made recipes for common
 //! threads; mostly calling the function being derived on all the
 //! arguments and then combining them back together in some way (or
@@ -227,8 +227,8 @@ pub struct MethodDef<'a> {
     /// Is there is a `&self` argument? If not, it is a static function.
     pub explicit_self: bool,
 
-    /// Arguments other than the self argument
-    pub args: Vec<(Ty, Symbol)>,
+    /// Arguments other than the self argument.
+    pub nonself_args: Vec<(Ty, Symbol)>,
 
     /// Returns type
     pub ret_ty: Ty,
@@ -245,25 +245,24 @@ pub struct MethodDef<'a> {
 pub struct Substructure<'a> {
     /// ident of self
     pub type_ident: Ident,
-    /// verbatim access to any non-self arguments
-    pub nonself_args: &'a [P<Expr>],
+    /// Verbatim access to any non-selflike arguments, i.e. arguments that
+    /// don't have type `&Self`.
+    pub nonselflike_args: &'a [P<Expr>],
     pub fields: &'a SubstructureFields<'a>,
 }
 
 /// Summary of the relevant parts of a struct/enum field.
-pub struct FieldInfo<'a> {
+pub struct FieldInfo {
     pub span: Span,
     /// None for tuple structs/normal enum variants, Some for normal
     /// structs/struct enum variants.
     pub name: Option<Ident>,
     /// The expression corresponding to this field of `self`
     /// (specifically, a reference to it).
-    pub self_: P<Expr>,
+    pub self_expr: P<Expr>,
     /// The expressions corresponding to references to this field in
-    /// the other `Self` arguments.
-    pub other: Vec<P<Expr>>,
-    /// The attributes on the field
-    pub attrs: &'a [ast::Attribute],
+    /// the other selflike arguments.
+    pub other_selflike_exprs: Vec<P<Expr>>,
 }
 
 /// Fields for a static method
@@ -276,11 +275,11 @@ pub enum StaticFields {
 
 /// A summary of the possible sets of fields.
 pub enum SubstructureFields<'a> {
-    Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
+    Struct(&'a ast::VariantData, Vec<FieldInfo>),
     /// Matching variants of the enum: variant index, variant count, ast::Variant,
     /// fields: the field name is only non-`None` in the case of a struct
     /// variant.
-    EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
+    EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
 
     /// Non-matching variants of the enum, but with all state hidden from the
     /// consequent code. The field is a list of `Ident`s bound to the variant
@@ -296,12 +295,7 @@ pub enum SubstructureFields<'a> {
 /// Combine the values of all the fields together. The last argument is
 /// all the fields of all the structures.
 pub type CombineSubstructureFunc<'a> =
-    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> P<Expr> + 'a>;
-
-/// Deal with non-matching enum variants. The slice is the identifiers holding
-/// the variant index value for each of the `Self` arguments.
-pub type EnumNonMatchCollapsedFunc<'a> =
-    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &[Ident]) -> P<Expr> + 'a>;
+    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
 
 pub fn combine_substructure(
     f: CombineSubstructureFunc<'_>,
@@ -314,6 +308,48 @@ struct TypeParameter {
     ty: P<ast::Ty>,
 }
 
+// The code snippets built up for derived code are sometimes used as blocks
+// (e.g. in a function body) and sometimes used as expressions (e.g. in a match
+// arm). This structure avoids committing to either form until necessary,
+// avoiding the insertion of any unnecessary blocks.
+//
+// The statements come before the expression.
+pub struct BlockOrExpr(Vec<ast::Stmt>, Option<P<Expr>>);
+
+impl BlockOrExpr {
+    pub fn new_stmts(stmts: Vec<ast::Stmt>) -> BlockOrExpr {
+        BlockOrExpr(stmts, None)
+    }
+
+    pub fn new_expr(expr: P<Expr>) -> BlockOrExpr {
+        BlockOrExpr(vec![], Some(expr))
+    }
+
+    pub fn new_mixed(stmts: Vec<ast::Stmt>, expr: P<Expr>) -> BlockOrExpr {
+        BlockOrExpr(stmts, Some(expr))
+    }
+
+    // Converts it into a block.
+    fn into_block(mut self, cx: &ExtCtxt<'_>, span: Span) -> P<ast::Block> {
+        if let Some(expr) = self.1 {
+            self.0.push(cx.stmt_expr(expr));
+        }
+        cx.block(span, self.0)
+    }
+
+    // Converts it into an expression.
+    fn into_expr(self, cx: &ExtCtxt<'_>, span: Span) -> P<Expr> {
+        if self.0.is_empty() {
+            match self.1 {
+                None => cx.expr_block(cx.block(span, vec![])),
+                Some(expr) => expr,
+            }
+        } else {
+            cx.expr_block(self.into_block(cx, span))
+        }
+    }
+}
+
 /// This method helps to extract all the type parameters referenced from a
 /// type. For a type parameter `<T>`, it looks for either a `TyPath` that
 /// is not global and starts with `T`, or a `TyQPath`.
@@ -429,6 +465,7 @@ impl<'a> TraitDef<'a> {
                         generics,
                         from_scratch,
                         use_temporaries,
+                        is_packed,
                     ),
                     ast::ItemKind::Enum(ref enum_def, ref generics) => {
                         // We ignore `use_temporaries` here, because
@@ -448,6 +485,7 @@ impl<'a> TraitDef<'a> {
                                 generics,
                                 from_scratch,
                                 use_temporaries,
+                                is_packed,
                             )
                         } else {
                             cx.span_err(mitem.span, "this trait cannot be derived for unions");
@@ -729,6 +767,7 @@ impl<'a> TraitDef<'a> {
         generics: &Generics,
         from_scratch: bool,
         use_temporaries: bool,
+        is_packed: bool,
     ) -> P<ast::Item> {
         let field_tys: Vec<P<ast::Ty>> =
             struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@@ -737,8 +776,8 @@ impl<'a> TraitDef<'a> {
             .methods
             .iter()
             .map(|method_def| {
-                let (explicit_self, self_args, nonself_args, tys) =
-                    method_def.split_self_nonself_args(cx, self, type_ident, generics);
+                let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
+                    method_def.extract_arg_details(cx, self, type_ident, generics);
 
                 let body = if from_scratch || method_def.is_static() {
                     method_def.expand_static_struct_method_body(
@@ -746,7 +785,7 @@ impl<'a> TraitDef<'a> {
                         self,
                         struct_def,
                         type_ident,
-                        &nonself_args,
+                        &nonselflike_args,
                     )
                 } else {
                     method_def.expand_struct_method_body(
@@ -754,13 +793,22 @@ impl<'a> TraitDef<'a> {
                         self,
                         struct_def,
                         type_ident,
-                        &self_args,
-                        &nonself_args,
+                        &selflike_args,
+                        &nonselflike_args,
                         use_temporaries,
+                        is_packed,
                     )
                 };
 
-                method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body)
+                method_def.create_method(
+                    cx,
+                    self,
+                    type_ident,
+                    generics,
+                    explicit_self,
+                    nonself_arg_tys,
+                    body,
+                )
             })
             .collect();
 
@@ -785,8 +833,8 @@ impl<'a> TraitDef<'a> {
             .methods
             .iter()
             .map(|method_def| {
-                let (explicit_self, self_args, nonself_args, tys) =
-                    method_def.split_self_nonself_args(cx, self, type_ident, generics);
+                let (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys) =
+                    method_def.extract_arg_details(cx, self, type_ident, generics);
 
                 let body = if from_scratch || method_def.is_static() {
                     method_def.expand_static_enum_method_body(
@@ -794,7 +842,7 @@ impl<'a> TraitDef<'a> {
                         self,
                         enum_def,
                         type_ident,
-                        &nonself_args,
+                        &nonselflike_args,
                     )
                 } else {
                     method_def.expand_enum_method_body(
@@ -802,12 +850,20 @@ impl<'a> TraitDef<'a> {
                         self,
                         enum_def,
                         type_ident,
-                        self_args,
-                        &nonself_args,
+                        selflike_args,
+                        &nonselflike_args,
                     )
                 };
 
-                method_def.create_method(cx, self, type_ident, generics, explicit_self, tys, body)
+                method_def.create_method(
+                    cx,
+                    self,
+                    type_ident,
+                    generics,
+                    explicit_self,
+                    nonself_arg_tys,
+                    body,
+                )
             })
             .collect();
 
@@ -821,11 +877,11 @@ impl<'a> MethodDef<'a> {
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
-        nonself_args: &[P<Expr>],
+        nonselflike_args: &[P<Expr>],
         fields: &SubstructureFields<'_>,
-    ) -> P<Expr> {
+    ) -> BlockOrExpr {
         let span = trait_.span;
-        let substructure = Substructure { type_ident, nonself_args, fields };
+        let substructure = Substructure { type_ident, nonselflike_args, fields };
         let mut f = self.combine_substructure.borrow_mut();
         let f: &mut CombineSubstructureFunc<'_> = &mut *f;
         f(cx, span, &substructure)
@@ -845,49 +901,51 @@ impl<'a> MethodDef<'a> {
         !self.explicit_self
     }
 
-    fn split_self_nonself_args(
+    // The return value includes:
+    // - explicit_self: The `&self` arg, if present.
+    // - selflike_args: Expressions for `&self` (if present) and also any other
+    //   args with the same type (e.g. the `other` arg in `PartialEq::eq`).
+    // - nonselflike_args: Expressions for all the remaining args.
+    // - nonself_arg_tys: Additional information about all the args other than
+    //   `&self`.
+    fn extract_arg_details(
         &self,
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         generics: &Generics,
     ) -> (Option<ast::ExplicitSelf>, Vec<P<Expr>>, Vec<P<Expr>>, Vec<(Ident, P<ast::Ty>)>) {
-        let mut self_args = Vec::new();
-        let mut nonself_args = Vec::new();
-        let mut arg_tys = Vec::new();
+        let mut selflike_args = Vec::new();
+        let mut nonselflike_args = Vec::new();
+        let mut nonself_arg_tys = Vec::new();
         let span = trait_.span;
 
-        let ast_explicit_self = if self.explicit_self {
+        let explicit_self = if self.explicit_self {
             let (self_expr, explicit_self) = ty::get_explicit_self(cx, span);
-            self_args.push(self_expr);
+            selflike_args.push(self_expr);
             Some(explicit_self)
         } else {
             None
         };
 
-        for (ty, name) in self.args.iter() {
+        for (ty, name) in self.nonself_args.iter() {
             let ast_ty = ty.to_ty(cx, span, type_ident, generics);
             let ident = Ident::new(*name, span);
-            arg_tys.push((ident, ast_ty));
+            nonself_arg_tys.push((ident, ast_ty));
 
             let arg_expr = cx.expr_ident(span, ident);
 
-            match *ty {
-                // for static methods, just treat any Self
-                // arguments as a normal arg
-                Self_ if !self.is_static() => {
-                    self_args.push(arg_expr);
-                }
-                Ref(ref ty, _) if matches!(**ty, Self_) && !self.is_static() => {
-                    self_args.push(cx.expr_deref(span, arg_expr))
-                }
-                _ => {
-                    nonself_args.push(arg_expr);
+            match ty {
+                // Selflike (`&Self`) arguments only occur in non-static methods.
+                Ref(box Self_, _) if !self.is_static() => {
+                    selflike_args.push(cx.expr_deref(span, arg_expr))
                 }
+                Self_ => cx.span_bug(span, "`Self` in non-return position"),
+                _ => nonselflike_args.push(arg_expr),
             }
         }
 
-        (ast_explicit_self, self_args, nonself_args, arg_tys)
+        (explicit_self, selflike_args, nonselflike_args, nonself_arg_tys)
     }
 
     fn create_method(
@@ -897,27 +955,28 @@ impl<'a> MethodDef<'a> {
         type_ident: Ident,
         generics: &Generics,
         explicit_self: Option<ast::ExplicitSelf>,
-        arg_types: Vec<(Ident, P<ast::Ty>)>,
-        body: P<Expr>,
+        nonself_arg_tys: Vec<(Ident, P<ast::Ty>)>,
+        body: BlockOrExpr,
     ) -> P<ast::AssocItem> {
         let span = trait_.span;
         // Create the generics that aren't for `Self`.
         let fn_generics = self.generics.to_generics(cx, span, type_ident, generics);
 
         let args = {
-            let self_args = explicit_self.map(|explicit_self| {
+            let self_arg = explicit_self.map(|explicit_self| {
                 let ident = Ident::with_dummy_span(kw::SelfLower).with_span_pos(span);
                 ast::Param::from_self(ast::AttrVec::default(), explicit_self, ident)
             });
-            let nonself_args = arg_types.into_iter().map(|(name, ty)| cx.param(span, name, ty));
-            self_args.into_iter().chain(nonself_args).collect()
+            let nonself_args =
+                nonself_arg_tys.into_iter().map(|(name, ty)| cx.param(span, name, ty));
+            self_arg.into_iter().chain(nonself_args).collect()
         };
 
         let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
 
         let method_ident = Ident::new(self.name, span);
         let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
-        let body_block = cx.block_expr(body);
+        let body_block = body.into_block(cx, span);
 
         let trait_lo_sp = span.shrink_to_lo();
 
@@ -945,6 +1004,7 @@ impl<'a> MethodDef<'a> {
         })
     }
 
+    /// The normal case uses field access.
     /// ```
     /// #[derive(PartialEq)]
     /// # struct Dummy;
@@ -953,33 +1013,21 @@ impl<'a> MethodDef<'a> {
     /// // equivalent to:
     /// impl PartialEq for A {
     ///     fn eq(&self, other: &A) -> bool {
-    ///         match *self {
-    ///             A {x: ref __self_0_0, y: ref __self_0_1} => {
-    ///                 match *other {
-    ///                     A {x: ref __self_1_0, y: ref __self_1_1} => {
-    ///                         __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
-    ///                     }
-    ///                 }
-    ///             }
-    ///         }
+    ///         self.x == other.x && self.y == other.y
     ///     }
     /// }
     /// ```
-    /// or if A is repr(packed) - note fields are matched by-value
-    /// instead of by-reference.
+    /// But if the struct is `repr(packed)`, we can't use something like
+    /// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`)
+    /// because that might cause an unaligned ref. So we use let-destructuring
+    /// instead.
     /// ```
     /// # struct A { x: i32, y: i32 }
     /// impl PartialEq for A {
     ///     fn eq(&self, other: &A) -> bool {
-    ///         match *self {
-    ///             A {x: __self_0_0, y: __self_0_1} => {
-    ///                 match other {
-    ///                     A {x: __self_1_0, y: __self_1_1} => {
-    ///                         __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
-    ///                     }
-    ///                 }
-    ///             }
-    ///         }
+    ///         let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
+    ///         let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other;
+    ///         *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1
     ///     }
     /// }
     /// ```
@@ -989,70 +1037,54 @@ impl<'a> MethodDef<'a> {
         trait_: &TraitDef<'b>,
         struct_def: &'b VariantData,
         type_ident: Ident,
-        self_args: &[P<Expr>],
-        nonself_args: &[P<Expr>],
+        selflike_args: &[P<Expr>],
+        nonselflike_args: &[P<Expr>],
         use_temporaries: bool,
-    ) -> P<Expr> {
-        let mut raw_fields = Vec::new(); // Vec<[fields of self], [fields of next Self arg], [etc]>
+        is_packed: bool,
+    ) -> BlockOrExpr {
         let span = trait_.span;
-        let mut patterns = Vec::new();
-        for i in 0..self_args.len() {
-            // We could use `type_ident` instead of `Self`, but in the case of a type parameter
-            // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343
+        assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
+
+        let mk_body = |cx, selflike_fields| {
+            self.call_substructure_method(
+                cx,
+                trait_,
+                type_ident,
+                nonselflike_args,
+                &Struct(struct_def, selflike_fields),
+            )
+        };
+
+        if !is_packed {
+            let selflike_fields =
+                trait_.create_struct_field_access_fields(cx, selflike_args, struct_def);
+            mk_body(cx, selflike_fields)
+        } else {
+            let prefixes: Vec<_> =
+                (0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
+            let selflike_fields =
+                trait_.create_struct_pattern_fields(cx, struct_def, &prefixes, use_temporaries);
+            let mut body = mk_body(cx, selflike_fields);
+
             let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
-            let (pat, ident_expr) = trait_.create_struct_pattern(
+            let patterns = trait_.create_struct_patterns(
                 cx,
                 struct_path,
                 struct_def,
-                &format!("__self_{}", i),
+                &prefixes,
                 ast::Mutability::Not,
                 use_temporaries,
             );
-            patterns.push(pat);
-            raw_fields.push(ident_expr);
-        }
 
-        // transpose raw_fields
-        let fields = if !raw_fields.is_empty() {
-            let mut raw_fields = raw_fields.into_iter().map(|v| v.into_iter());
-            let first_field = raw_fields.next().unwrap();
-            let mut other_fields: Vec<vec::IntoIter<_>> = raw_fields.collect();
-            first_field
-                .map(|(span, opt_id, field, attrs)| FieldInfo {
-                    span: span.with_ctxt(trait_.span.ctxt()),
-                    name: opt_id,
-                    self_: field,
-                    other: other_fields
-                        .iter_mut()
-                        .map(|l| {
-                            let (.., ex, _) = l.next().unwrap();
-                            ex
-                        })
-                        .collect(),
-                    attrs,
+            // Do the let-destructuring.
+            let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
+                .map(|(selflike_arg_expr, pat)| {
+                    cx.stmt_let_pat(span, pat, selflike_arg_expr.clone())
                 })
-                .collect()
-        } else {
-            cx.span_bug(span, "no `self` parameter for method in generic `derive`")
-        };
-
-        // body of the inner most destructuring match
-        let mut body = self.call_substructure_method(
-            cx,
-            trait_,
-            type_ident,
-            nonself_args,
-            &Struct(struct_def, fields),
-        );
-
-        // make a series of nested matches, to destructure the
-        // structs. This is actually right-to-left, but it shouldn't
-        // matter.
-        for (arg_expr, pat) in iter::zip(self_args, patterns) {
-            body = cx.expr_match(span, arg_expr.clone(), vec![cx.arm(span, pat.clone(), body)])
+                .collect();
+            stmts.extend(std::mem::take(&mut body.0));
+            BlockOrExpr(stmts, body.1)
         }
-
-        body
     }
 
     fn expand_static_struct_method_body(
@@ -1061,15 +1093,15 @@ impl<'a> MethodDef<'a> {
         trait_: &TraitDef<'_>,
         struct_def: &VariantData,
         type_ident: Ident,
-        nonself_args: &[P<Expr>],
-    ) -> P<Expr> {
+        nonselflike_args: &[P<Expr>],
+    ) -> BlockOrExpr {
         let summary = trait_.summarise_struct(cx, struct_def);
 
         self.call_substructure_method(
             cx,
             trait_,
             type_ident,
-            nonself_args,
+            nonselflike_args,
             &StaticStruct(struct_def, summary),
         )
     }
@@ -1103,7 +1135,7 @@ impl<'a> MethodDef<'a> {
     ///     }
     /// }
     /// ```
-    /// Creates a match for a tuple of all `self_args`, where either all
+    /// Creates a match for a tuple of all `selflike_args`, where either all
     /// variants match, or it falls into a catch-all for when one variant
     /// does not match.
     ///
@@ -1116,33 +1148,33 @@ impl<'a> MethodDef<'a> {
     /// a simple equality check (for PartialEq).
     ///
     /// The catch-all handler is provided access the variant index values
-    /// for each of the self-args, carried in precomputed variables.
+    /// for each of the selflike_args, carried in precomputed variables.
     fn expand_enum_method_body<'b>(
         &self,
         cx: &mut ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         enum_def: &'b EnumDef,
         type_ident: Ident,
-        mut self_args: Vec<P<Expr>>,
-        nonself_args: &[P<Expr>],
-    ) -> P<Expr> {
+        mut selflike_args: Vec<P<Expr>>,
+        nonselflike_args: &[P<Expr>],
+    ) -> BlockOrExpr {
         let span = trait_.span;
         let variants = &enum_def.variants;
 
-        let self_arg_names = iter::once("__self".to_string())
+        let prefixes = iter::once("__self".to_string())
             .chain(
-                self_args
+                selflike_args
                     .iter()
                     .enumerate()
                     .skip(1)
-                    .map(|(arg_count, _self_arg)| format!("__arg_{}", arg_count)),
+                    .map(|(arg_count, _selflike_arg)| format!("__arg_{}", arg_count)),
             )
             .collect::<Vec<String>>();
 
         // The `vi_idents` will be bound, solely in the catch-all, to
-        // a series of let statements mapping each self_arg to an int
+        // a series of let statements mapping each selflike_arg to an int
         // value corresponding to its discriminant.
-        let vi_idents = self_arg_names
+        let vi_idents = prefixes
             .iter()
             .map(|name| {
                 let vi_suffix = format!("{}_vi", name);
@@ -1161,100 +1193,64 @@ impl<'a> MethodDef<'a> {
         // (Variant1, Variant1, ...) => Body1
         // (Variant2, Variant2, ...) => Body2
         // ...
-        // where each tuple has length = self_args.len()
+        // where each tuple has length = selflike_args.len()
+
         let mut match_arms: Vec<ast::Arm> = variants
             .iter()
             .enumerate()
             .filter(|&(_, v)| !(self.unify_fieldless_variants && v.data.fields().is_empty()))
             .map(|(index, variant)| {
-                let mk_self_pat = |cx: &mut ExtCtxt<'_>, self_arg_name: &str| {
-                    let (p, idents) = trait_.create_enum_variant_pattern(
-                        cx,
-                        type_ident,
-                        variant,
-                        self_arg_name,
-                        ast::Mutability::Not,
-                    );
-                    (cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)), idents)
-                };
-
                 // A single arm has form (&VariantK, &VariantK, ...) => BodyK
                 // (see "Final wrinkle" note below for why.)
-                let mut subpats = Vec::with_capacity(self_arg_names.len());
-                let mut self_pats_idents = Vec::with_capacity(self_arg_names.len() - 1);
-                let first_self_pat_idents = {
-                    let (p, idents) = mk_self_pat(cx, &self_arg_names[0]);
-                    subpats.push(p);
-                    idents
-                };
-                for self_arg_name in &self_arg_names[1..] {
-                    let (p, idents) = mk_self_pat(cx, &self_arg_name);
-                    subpats.push(p);
-                    self_pats_idents.push(idents);
-                }
+
+                let use_temporaries = false; // enums can't be repr(packed)
+                let fields = trait_.create_struct_pattern_fields(
+                    cx,
+                    &variant.data,
+                    &prefixes,
+                    use_temporaries,
+                );
+
+                let sp = variant.span.with_ctxt(trait_.span.ctxt());
+                let variant_path = cx.path(sp, vec![type_ident, variant.ident]);
+                let mut subpats: Vec<_> = trait_
+                    .create_struct_patterns(
+                        cx,
+                        variant_path,
+                        &variant.data,
+                        &prefixes,
+                        ast::Mutability::Not,
+                        use_temporaries,
+                    )
+                    .into_iter()
+                    .map(|p| cx.pat(span, PatKind::Ref(p, ast::Mutability::Not)))
+                    .collect();
 
                 // Here is the pat = `(&VariantK, &VariantK, ...)`
-                let single_pat = cx.pat_tuple(span, subpats);
+                let single_pat = if subpats.len() == 1 {
+                    subpats.pop().unwrap()
+                } else {
+                    cx.pat_tuple(span, subpats)
+                };
 
                 // For the BodyK, we need to delegate to our caller,
                 // passing it an EnumMatching to indicate which case
                 // we are in.
-
-                // All of the Self args have the same variant in these
-                // cases.  So we transpose the info in self_pats_idents
-                // to gather the getter expressions together, in the
-                // form that EnumMatching expects.
-
-                // The transposition is driven by walking across the
-                // arg fields of the variant for the first self pat.
-                let field_tuples = first_self_pat_idents
-                    .into_iter()
-                    .enumerate()
-                    // For each arg field of self, pull out its getter expr ...
-                    .map(|(field_index, (span, opt_ident, self_getter_expr, attrs))| {
-                        // ... but FieldInfo also wants getter expr
-                        // for matching other arguments of Self type;
-                        // so walk across the *other* self_pats_idents
-                        // and pull out getter for same field in each
-                        // of them (using `field_index` tracked above).
-                        // That is the heart of the transposition.
-                        let others = self_pats_idents
-                            .iter()
-                            .map(|fields| {
-                                let (_, _opt_ident, ref other_getter_expr, _) = fields[field_index];
-
-                                // All Self args have same variant, so
-                                // opt_idents are the same.  (Assert
-                                // here to make it self-evident that
-                                // it is okay to ignore `_opt_ident`.)
-                                assert!(opt_ident == _opt_ident);
-
-                                other_getter_expr.clone()
-                            })
-                            .collect::<Vec<P<Expr>>>();
-
-                        FieldInfo {
-                            span,
-                            name: opt_ident,
-                            self_: self_getter_expr,
-                            other: others,
-                            attrs,
-                        }
-                    })
-                    .collect::<Vec<FieldInfo<'_>>>();
-
+                //
                 // Now, for some given VariantK, we have built up
                 // expressions for referencing every field of every
                 // Self arg, assuming all are instances of VariantK.
                 // Build up code associated with such a case.
-                let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
-                let arm_expr = self.call_substructure_method(
-                    cx,
-                    trait_,
-                    type_ident,
-                    nonself_args,
-                    &substructure,
-                );
+                let substructure = EnumMatching(index, variants.len(), variant, fields);
+                let arm_expr = self
+                    .call_substructure_method(
+                        cx,
+                        trait_,
+                        type_ident,
+                        nonselflike_args,
+                        &substructure,
+                    )
+                    .into_expr(cx, span);
 
                 cx.arm(span, single_pat, arm_expr)
             })
@@ -1266,15 +1262,18 @@ impl<'a> MethodDef<'a> {
                 // The index and actual variant aren't meaningful in this case,
                 // so just use whatever
                 let substructure = EnumMatching(0, variants.len(), v, Vec::new());
-                Some(self.call_substructure_method(
-                    cx,
-                    trait_,
-                    type_ident,
-                    nonself_args,
-                    &substructure,
-                ))
+                Some(
+                    self.call_substructure_method(
+                        cx,
+                        trait_,
+                        type_ident,
+                        nonselflike_args,
+                        &substructure,
+                    )
+                    .into_expr(cx, span),
+                )
             }
-            _ if variants.len() > 1 && self_args.len() > 1 => {
+            _ if variants.len() > 1 && selflike_args.len() > 1 => {
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
@@ -1301,8 +1300,8 @@ impl<'a> MethodDef<'a> {
         //   catch-all `_` match, it would trigger the
         //   unreachable-pattern error.
         //
-        if variants.len() > 1 && self_args.len() > 1 {
-            // Build a series of let statements mapping each self_arg
+        if variants.len() > 1 && selflike_args.len() > 1 {
+            // Build a series of let statements mapping each selflike_arg
             // to its discriminant value.
             //
             // i.e., for `enum E<T> { A, B(1), C(T, T) }`, and a deriving
@@ -1317,10 +1316,14 @@ impl<'a> MethodDef<'a> {
             // We also build an expression which checks whether all discriminants are equal:
             // `__self_vi == __arg_1_vi && __self_vi == __arg_2_vi && ...`
             let mut discriminant_test = cx.expr_bool(span, true);
-            for (i, (&ident, self_arg)) in iter::zip(&vi_idents, &self_args).enumerate() {
-                let self_addr = cx.expr_addr_of(span, self_arg.clone());
-                let variant_value =
-                    deriving::call_intrinsic(cx, span, sym::discriminant_value, vec![self_addr]);
+            for (i, (&ident, selflike_arg)) in iter::zip(&vi_idents, &selflike_args).enumerate() {
+                let selflike_addr = cx.expr_addr_of(span, selflike_arg.clone());
+                let variant_value = deriving::call_intrinsic(
+                    cx,
+                    span,
+                    sym::discriminant_value,
+                    vec![selflike_addr],
+                );
                 let let_stmt = cx.stmt_let(span, false, ident, variant_value);
                 index_let_stmts.push(let_stmt);
 
@@ -1336,21 +1339,23 @@ impl<'a> MethodDef<'a> {
                 }
             }
 
-            let arm_expr = self.call_substructure_method(
-                cx,
-                trait_,
-                type_ident,
-                nonself_args,
-                &catch_all_substructure,
-            );
+            let arm_expr = self
+                .call_substructure_method(
+                    cx,
+                    trait_,
+                    type_ident,
+                    nonselflike_args,
+                    &catch_all_substructure,
+                )
+                .into_expr(cx, span);
 
-            // Final wrinkle: the self_args are expressions that deref
+            // Final wrinkle: the selflike_args are expressions that deref
             // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
-            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
+            selflike_args.map_in_place(|selflike_arg| cx.expr_addr_of(span, selflike_arg));
+            let match_arg = cx.expr(span, ast::ExprKind::Tup(selflike_args));
 
             // Lastly we create an expression which branches on all discriminants being equal
             //  if discriminant_test {
@@ -1366,68 +1371,25 @@ impl<'a> MethodDef<'a> {
             //  }
             let all_match = cx.expr_match(span, match_arg, match_arms);
             let arm_expr = cx.expr_if(span, discriminant_test, all_match, Some(arm_expr));
-            index_let_stmts.push(cx.stmt_expr(arm_expr));
-            cx.expr_block(cx.block(span, index_let_stmts))
+            BlockOrExpr(index_let_stmts, Some(arm_expr))
         } else if variants.is_empty() {
-            // As an additional wrinkle, For a zero-variant enum A,
-            // currently the compiler
-            // will accept `fn (a: &Self) { match   *a   { } }`
-            // but rejects `fn (a: &Self) { match (&*a,) { } }`
-            // as well as  `fn (a: &Self) { match ( *a,) { } }`
-            //
-            // This means that the strategy of building up a tuple of
-            // all Self arguments fails when Self is a zero variant
-            // enum: rustc rejects the expanded program, even though
-            // the actual code tends to be impossible to execute (at
-            // least safely), according to the type system.
-            //
-            // The most expedient fix for this is to just let the
-            // code fall through to the catch-all.  But even this is
-            // error-prone, since the catch-all as defined above would
-            // generate code like this:
-            //
-            //     _ => { let __self0 = match *self { };
-            //            let __self1 = match *__arg_0 { };
-            //            <catch-all-expr> }
-            //
-            // Which is yields bindings for variables which type
-            // inference cannot resolve to unique types.
-            //
-            // One option to the above might be to add explicit type
-            // annotations.  But the *only* reason to go down that path
-            // would be to try to make the expanded output consistent
-            // with the case when the number of enum variants >= 1.
-            //
-            // That just isn't worth it.  In fact, trying to generate
-            // sensible code for *any* deriving on a zero-variant enum
-            // does not make sense.  But at the same time, for now, we
-            // do not want to cause a compile failure just because the
-            // user happened to attach a deriving to their
-            // zero-variant enum.
-            //
-            // Instead, just generate a failing expression for the
-            // zero variant case, skipping matches and also skipping
-            // delegating back to the end user code entirely.
-            //
-            // (See also #4499 and #12609; note that some of the
-            // discussions there influence what choice we make here;
-            // e.g., if we feature-gate `match x { ... }` when x refers
-            // to an uninhabited type (e.g., a zero-variant enum or a
-            // type holding such an enum), but do not feature-gate
-            // zero-variant enums themselves, then attempting to
-            // derive Debug on such a type could here generate code
-            // that needs the feature gate enabled.)
-
-            deriving::call_unreachable(cx, span)
+            // There is no sensible code to be generated for *any* deriving on
+            // a zero-variant enum. So we just generate a failing expression
+            // for the zero variant case.
+            BlockOrExpr(vec![], Some(deriving::call_unreachable(cx, span)))
         } else {
-            // Final wrinkle: the self_args are expressions that deref
+            // Final wrinkle: the selflike_args are expressions that deref
             // down to desired places, but we cannot actually deref
             // them when they are fed as r-values into a tuple
             // expression; here add a layer of borrowing, turning
             // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
-            self_args.map_in_place(|self_arg| cx.expr_addr_of(span, self_arg));
-            let match_arg = cx.expr(span, ast::ExprKind::Tup(self_args));
-            cx.expr_match(span, match_arg, match_arms)
+            selflike_args.map_in_place(|selflike_arg| cx.expr_addr_of(span, selflike_arg));
+            let match_arg = if selflike_args.len() == 1 {
+                selflike_args.pop().unwrap()
+            } else {
+                cx.expr(span, ast::ExprKind::Tup(selflike_args))
+            };
+            BlockOrExpr(vec![], Some(cx.expr_match(span, match_arg, match_arms)))
         }
     }
 
@@ -1437,8 +1399,8 @@ impl<'a> MethodDef<'a> {
         trait_: &TraitDef<'_>,
         enum_def: &EnumDef,
         type_ident: Ident,
-        nonself_args: &[P<Expr>],
-    ) -> P<Expr> {
+        nonselflike_args: &[P<Expr>],
+    ) -> BlockOrExpr {
         let summary = enum_def
             .variants
             .iter()
@@ -1452,7 +1414,7 @@ impl<'a> MethodDef<'a> {
             cx,
             trait_,
             type_ident,
-            nonself_args,
+            nonselflike_args,
             &StaticEnum(enum_def, summary),
         )
     }
@@ -1485,200 +1447,210 @@ impl<'a> TraitDef<'a> {
         }
     }
 
-    fn create_subpatterns(
+    fn create_struct_patterns(
         &self,
         cx: &mut ExtCtxt<'_>,
-        field_paths: Vec<Ident>,
+        struct_path: ast::Path,
+        struct_def: &'a VariantData,
+        prefixes: &[String],
         mutbl: ast::Mutability,
         use_temporaries: bool,
     ) -> Vec<P<ast::Pat>> {
-        field_paths
+        prefixes
             .iter()
-            .map(|path| {
-                let binding_mode = if use_temporaries {
-                    ast::BindingMode::ByValue(ast::Mutability::Not)
-                } else {
-                    ast::BindingMode::ByRef(mutbl)
-                };
-                cx.pat(path.span, PatKind::Ident(binding_mode, *path, None))
+            .map(|prefix| {
+                let pieces_iter =
+                    struct_def.fields().iter().enumerate().map(|(i, struct_field)| {
+                        let sp = struct_field.span.with_ctxt(self.span.ctxt());
+                        let binding_mode = if use_temporaries {
+                            ast::BindingMode::ByValue(ast::Mutability::Not)
+                        } else {
+                            ast::BindingMode::ByRef(mutbl)
+                        };
+                        let ident = self.mk_pattern_ident(prefix, i);
+                        let path = ident.with_span_pos(sp);
+                        (
+                            sp,
+                            struct_field.ident,
+                            cx.pat(path.span, PatKind::Ident(binding_mode, path, None)),
+                        )
+                    });
+
+                let struct_path = struct_path.clone();
+                match *struct_def {
+                    VariantData::Struct(..) => {
+                        let field_pats = pieces_iter
+                            .map(|(sp, ident, pat)| {
+                                if ident.is_none() {
+                                    cx.span_bug(
+                                        sp,
+                                        "a braced struct with unnamed fields in `derive`",
+                                    );
+                                }
+                                ast::PatField {
+                                    ident: ident.unwrap(),
+                                    is_shorthand: false,
+                                    attrs: ast::AttrVec::new(),
+                                    id: ast::DUMMY_NODE_ID,
+                                    span: pat.span.with_ctxt(self.span.ctxt()),
+                                    pat,
+                                    is_placeholder: false,
+                                }
+                            })
+                            .collect();
+                        cx.pat_struct(self.span, struct_path, field_pats)
+                    }
+                    VariantData::Tuple(..) => {
+                        let subpats = pieces_iter.map(|(_, _, subpat)| subpat).collect();
+                        cx.pat_tuple_struct(self.span, struct_path, subpats)
+                    }
+                    VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
+                }
             })
             .collect()
     }
 
-    fn create_struct_pattern(
+    fn create_fields<F>(&self, struct_def: &'a VariantData, mk_exprs: F) -> Vec<FieldInfo>
+    where
+        F: Fn(usize, &ast::FieldDef, Span) -> Vec<P<ast::Expr>>,
+    {
+        struct_def
+            .fields()
+            .iter()
+            .enumerate()
+            .map(|(i, struct_field)| {
+                // For this field, get an expr for each selflike_arg. E.g. for
+                // `PartialEq::eq`, one for each of `&self` and `other`.
+                let sp = struct_field.span.with_ctxt(self.span.ctxt());
+                let mut exprs: Vec<_> = mk_exprs(i, struct_field, sp);
+                let self_expr = exprs.remove(0);
+                let other_selflike_exprs = exprs;
+                FieldInfo {
+                    span: sp.with_ctxt(self.span.ctxt()),
+                    name: struct_field.ident,
+                    self_expr,
+                    other_selflike_exprs,
+                }
+            })
+            .collect()
+    }
+
+    fn mk_pattern_ident(&self, prefix: &str, i: usize) -> Ident {
+        Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span)
+    }
+
+    fn create_struct_pattern_fields(
         &self,
         cx: &mut ExtCtxt<'_>,
-        struct_path: ast::Path,
         struct_def: &'a VariantData,
-        prefix: &str,
-        mutbl: ast::Mutability,
+        prefixes: &[String],
         use_temporaries: bool,
-    ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
-        let mut paths = Vec::new();
-        let mut ident_exprs = Vec::new();
-        for (i, struct_field) in struct_def.fields().iter().enumerate() {
-            let sp = struct_field.span.with_ctxt(self.span.ctxt());
-            let ident = Ident::from_str_and_span(&format!("{}_{}", prefix, i), self.span);
-            paths.push(ident.with_span_pos(sp));
-            let val = cx.expr_path(cx.path_ident(sp, ident));
-            let val = if use_temporaries { val } else { cx.expr_deref(sp, val) };
-            let val = cx.expr(sp, ast::ExprKind::Paren(val));
-
-            ident_exprs.push((sp, struct_field.ident, val, &struct_field.attrs[..]));
-        }
-
-        let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries);
-        let pattern = match *struct_def {
-            VariantData::Struct(..) => {
-                let field_pats = iter::zip(subpats, &ident_exprs)
-                    .map(|(pat, &(sp, ident, ..))| {
-                        if ident.is_none() {
-                            cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
-                        }
-                        ast::PatField {
-                            ident: ident.unwrap(),
-                            is_shorthand: false,
-                            attrs: ast::AttrVec::new(),
-                            id: ast::DUMMY_NODE_ID,
-                            span: pat.span.with_ctxt(self.span.ctxt()),
-                            pat,
-                            is_placeholder: false,
-                        }
-                    })
-                    .collect();
-                cx.pat_struct(self.span, struct_path, field_pats)
-            }
-            VariantData::Tuple(..) => cx.pat_tuple_struct(self.span, struct_path, subpats),
-            VariantData::Unit(..) => cx.pat_path(self.span, struct_path),
-        };
-
-        (pattern, ident_exprs)
+    ) -> Vec<FieldInfo> {
+        self.create_fields(struct_def, |i, _struct_field, sp| {
+            prefixes
+                .iter()
+                .map(|prefix| {
+                    let ident = self.mk_pattern_ident(prefix, i);
+                    let expr = cx.expr_path(cx.path_ident(sp, ident));
+                    if use_temporaries { expr } else { cx.expr_deref(sp, expr) }
+                })
+                .collect()
+        })
     }
 
-    fn create_enum_variant_pattern(
+    fn create_struct_field_access_fields(
         &self,
         cx: &mut ExtCtxt<'_>,
-        enum_ident: Ident,
-        variant: &'a ast::Variant,
-        prefix: &str,
-        mutbl: ast::Mutability,
-    ) -> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
-        let sp = variant.span.with_ctxt(self.span.ctxt());
-        let variant_path = cx.path(sp, vec![enum_ident, variant.ident]);
-        let use_temporaries = false; // enums can't be repr(packed)
-        self.create_struct_pattern(cx, variant_path, &variant.data, prefix, mutbl, use_temporaries)
-    }
-}
-
-// helpful premade recipes
-
-fn cs_fold_fields<'a, F>(
-    use_foldl: bool,
-    mut f: F,
-    base: P<Expr>,
-    cx: &mut ExtCtxt<'_>,
-    all_fields: &[FieldInfo<'a>],
-) -> P<Expr>
-where
-    F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
-{
-    if use_foldl {
-        all_fields
-            .iter()
-            .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
-    } else {
-        all_fields
-            .iter()
-            .rev()
-            .fold(base, |old, field| f(cx, field.span, old, field.self_.clone(), &field.other))
-    }
-}
-
-fn cs_fold_enumnonmatch(
-    mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
-    cx: &mut ExtCtxt<'_>,
-    trait_span: Span,
-    substructure: &Substructure<'_>,
-) -> P<Expr> {
-    match *substructure.fields {
-        EnumNonMatchingCollapsed(tuple) => enum_nonmatch_f(cx, trait_span, tuple),
-        _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed"),
+        selflike_args: &[P<Expr>],
+        struct_def: &'a VariantData,
+    ) -> Vec<FieldInfo> {
+        self.create_fields(struct_def, |i, struct_field, sp| {
+            selflike_args
+                .iter()
+                .map(|mut selflike_arg| {
+                    // We don't the need the deref, if there is one.
+                    if let ast::ExprKind::Unary(ast::UnOp::Deref, inner) = &selflike_arg.kind {
+                        selflike_arg = inner;
+                    }
+                    // Note: we must use `struct_field.span` rather than `span` in the
+                    // `unwrap_or_else` case otherwise the hygiene is wrong and we get
+                    // "field `0` of struct `Point` is private" errors on tuple
+                    // structs.
+                    cx.expr(
+                        sp,
+                        ast::ExprKind::Field(
+                            selflike_arg.clone(),
+                            struct_field.ident.unwrap_or_else(|| {
+                                Ident::from_str_and_span(&i.to_string(), struct_field.span)
+                            }),
+                        ),
+                    )
+                })
+                .collect()
+        })
     }
 }
 
-fn cs_fold_static(cx: &mut ExtCtxt<'_>, trait_span: Span) -> P<Expr> {
-    cx.span_bug(trait_span, "static function in `derive`")
+/// The function passed to `cs_fold` is called repeatedly with a value of this
+/// type. It describes one part of the code generation. The result is always an
+/// expression.
+pub enum CsFold<'a> {
+    /// The basic case: a field expression for one or more selflike args. E.g.
+    /// for `PartialEq::eq` this is something like `self.x == other.x`.
+    Single(&'a FieldInfo),
+
+    /// The combination of two field expressions. E.g. for `PartialEq::eq` this
+    /// is something like `<field1 equality> && <field2 equality>`.
+    Combine(Span, P<Expr>, P<Expr>),
+
+    // The fallback case for a struct or enum variant with no fields.
+    Fieldless,
+
+    /// The fallback case for non-matching enum variants. The slice is the
+    /// identifiers holding the variant index value for each of the `Self`
+    /// arguments.
+    EnumNonMatching(Span, &'a [Ident]),
 }
 
-/// Fold the fields. `use_foldl` controls whether this is done
-/// left-to-right (`true`) or right-to-left (`false`).
+/// Folds over fields, combining the expressions for each field in a sequence.
+/// Statics may not be folded over.
 pub fn cs_fold<F>(
     use_foldl: bool,
-    f: F,
-    base: P<Expr>,
-    enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
     cx: &mut ExtCtxt<'_>,
     trait_span: Span,
     substructure: &Substructure<'_>,
+    mut f: F,
 ) -> P<Expr>
 where
-    F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
+    F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
 {
     match *substructure.fields {
         EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
-            cs_fold_fields(use_foldl, f, base, cx, all_fields)
-        }
-        EnumNonMatchingCollapsed(..) => {
-            cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
-        }
-        StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
-    }
-}
+            if all_fields.is_empty() {
+                return f(cx, CsFold::Fieldless);
+            }
 
-/// Function to fold over fields, with three cases, to generate more efficient and concise code.
-/// When the `substructure` has grouped fields, there are two cases:
-/// Zero fields: call the base case function with `None` (like the usual base case of `cs_fold`).
-/// One or more fields: call the base case function on the first value (which depends on
-/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
-/// fields.
-/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
-/// is returned. Statics may not be folded over.
-/// See `cs_op` in `partial_ord.rs` for a model example.
-pub fn cs_fold1<F, B>(
-    use_foldl: bool,
-    f: F,
-    mut b: B,
-    enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
-    cx: &mut ExtCtxt<'_>,
-    trait_span: Span,
-    substructure: &Substructure<'_>,
-) -> P<Expr>
-where
-    F: FnMut(&mut ExtCtxt<'_>, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
-    B: FnMut(&mut ExtCtxt<'_>, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>,
-{
-    match *substructure.fields {
-        EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => {
-            let (base, rest) = match (all_fields.is_empty(), use_foldl) {
-                (false, true) => {
-                    let (first, rest) = all_fields.split_first().unwrap();
-                    let args = (first.span, first.self_.clone(), &first.other[..]);
-                    (b(cx, Some(args)), rest)
-                }
-                (false, false) => {
-                    let (last, rest) = all_fields.split_last().unwrap();
-                    let args = (last.span, last.self_.clone(), &last.other[..]);
-                    (b(cx, Some(args)), rest)
-                }
-                (true, _) => (b(cx, None), &all_fields[..]),
+            let (base_field, rest) = if use_foldl {
+                all_fields.split_first().unwrap()
+            } else {
+                all_fields.split_last().unwrap()
             };
 
-            cs_fold_fields(use_foldl, f, base, cx, rest)
-        }
-        EnumNonMatchingCollapsed(..) => {
-            cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
+            let base_expr = f(cx, CsFold::Single(base_field));
+
+            let op = |old, field: &FieldInfo| {
+                let new = f(cx, CsFold::Single(field));
+                f(cx, CsFold::Combine(field.span, old, new))
+            };
+
+            if use_foldl {
+                rest.iter().fold(base_expr, op)
+            } else {
+                rest.iter().rfold(base_expr, op)
+            }
         }
-        StaticEnum(..) | StaticStruct(..) => cs_fold_static(cx, trait_span),
+        EnumNonMatchingCollapsed(tuple) => f(cx, CsFold::EnumNonMatching(trait_span, tuple)),
+        StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
     }
 }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 9790449c4b3..2213cd6d37d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -2,8 +2,7 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::{self, path_std, pathvec_std};
 
-use rustc_ast::ptr::P;
-use rustc_ast::{Expr, MetaItem, Mutability};
+use rustc_ast::{MetaItem, Mutability};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -31,7 +30,7 @@ pub fn expand_deriving_hash(
             name: sym::hash,
             generics: Bounds { bounds: vec![(typaram, vec![path_std!(hash::Hasher)])] },
             explicit_self: true,
-            args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
+            nonself_args: vec![(Ref(Box::new(Path(arg)), Mutability::Mut), sym::state)],
             ret_ty: Unit,
             attributes: vec![],
             unify_fieldless_variants: true,
@@ -45,8 +44,12 @@ pub fn expand_deriving_hash(
     hash_trait_def.expand(cx, mitem, item, push);
 }
 
-fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
-    let [state_expr] = substr.nonself_args else {
+fn hash_substructure(
+    cx: &mut ExtCtxt<'_>,
+    trait_span: Span,
+    substr: &Substructure<'_>,
+) -> BlockOrExpr {
+    let [state_expr] = substr.nonselflike_args else {
         cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
     };
     let call_hash = |span, thing_expr| {
@@ -79,8 +82,9 @@ fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructu
     };
 
     stmts.extend(
-        fields.iter().map(|FieldInfo { ref self_, span, .. }| call_hash(*span, self_.clone())),
+        fields
+            .iter()
+            .map(|FieldInfo { ref self_expr, span, .. }| call_hash(*span, self_expr.clone())),
     );
-
-    cx.expr_block(cx.block(trait_span, stmts))
+    BlockOrExpr::new_stmts(stmts)
 }
diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
index cf8fada5320..2ecc8b8238b 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
@@ -6,7 +6,6 @@
 // Regression test for issue #91827.
 
 #![feature(const_ptr_offset_from)]
-#![feature(const_slice_from_raw_parts)]
 #![feature(extern_types)]
 
 use std::ptr::addr_of;
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
index ce1c6c99b40..77f437974c2 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
@@ -19,7 +19,7 @@ index 092b7cf..158cf71 100644
  #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
  impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
 -#[cfg(target_has_atomic_load_store = "128")]
--#[unstable(feature = "integer_atomics", issue = "32976")]
+-#[unstable(feature = "integer_atomics", issue = "99069")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
 
  #[cfg(target_has_atomic_load_store = "ptr")]
@@ -29,7 +29,7 @@ index 092b7cf..158cf71 100644
  #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
  impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
 -#[cfg(target_has_atomic_load_store = "128")]
--#[unstable(feature = "integer_atomics", issue = "32976")]
+-#[unstable(feature = "integer_atomics", issue = "99069")]
 -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
 
  #[cfg(target_has_atomic_load_store = "8")]
@@ -46,14 +46,14 @@ index d9de37e..8293fce 100644
 -atomic_int! {
 -    cfg(target_has_atomic = "128"),
 -    cfg(target_has_atomic_equal_alignment = "128"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
--    unstable(feature = "integer_atomics", issue = "32976"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
 -    cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
 -    "i128",
 -    "#![feature(integer_atomics)]\n\n",
@@ -66,14 +66,14 @@ index d9de37e..8293fce 100644
 -atomic_int! {
 -    cfg(target_has_atomic = "128"),
 -    cfg(target_has_atomic_equal_alignment = "128"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
--    unstable(feature = "integer_atomics", issue = "32976"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
 -    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
--    unstable(feature = "integer_atomics", issue = "32976"),
+-    unstable(feature = "integer_atomics", issue = "99069"),
 -    cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
 -    "u128",
 -    "#![feature(integer_atomics)]\n\n",
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index fbe830b2b10..f71d749df62 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -635,29 +635,6 @@ fn codegen_stmt<'tcx>(
                             let (ptr, _extra) = operand.load_scalar_pair(fx);
                             lval.write_cvalue(fx, CValue::by_val(ptr, dest_layout))
                         }
-                    } else if let ty::Adt(adt_def, _substs) = from_ty.kind() {
-                        // enum -> discriminant value
-                        assert!(adt_def.is_enum());
-                        match to_ty.kind() {
-                            ty::Uint(_) | ty::Int(_) => {}
-                            _ => unreachable!("cast adt {} -> {}", from_ty, to_ty),
-                        }
-                        let to_clif_ty = fx.clif_type(to_ty).unwrap();
-
-                        let discriminant = crate::discriminant::codegen_get_discriminant(
-                            fx,
-                            operand,
-                            fx.layout_of(operand.layout().ty.discriminant_ty(fx.tcx)),
-                        )
-                        .load_scalar(fx);
-
-                        let res = crate::cast::clif_intcast(
-                            fx,
-                            discriminant,
-                            to_clif_ty,
-                            to_ty.is_signed(),
-                        );
-                        lval.write_cvalue(fx, CValue::by_val(res, dest_layout));
                     } else {
                         let to_clif_ty = fx.clif_type(to_ty).unwrap();
                         let from = operand.load_scalar(fx);
@@ -686,6 +663,7 @@ fn codegen_stmt<'tcx>(
                                 substs,
                                 ty::ClosureKind::FnOnce,
                             )
+                            .expect("failed to normalize and resolve closure during codegen")
                             .polymorphize(fx.tcx);
                             let func_ref = fx.get_function_ref(instance);
                             let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index ef72e6efb94..48972321a9f 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -167,6 +167,7 @@ pub(crate) fn codegen_const_value<'tcx>(
     }
 
     match const_val {
+        ConstValue::ZeroSized => unreachable!(), // we already handles ZST above
         ConstValue::Scalar(x) => match x {
             Scalar::Int(int) => {
                 if fx.clif_type(layout.ty).is_some() {
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 05457ce15e9..50d8fc30d7d 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -66,7 +66,11 @@ fn emit_module(
     let work_product = if backend_config.disable_incr_cache {
         None
     } else {
-        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(tcx.sess, &name, &tmp_file)
+        rustc_incremental::copy_cgu_workproduct_to_incr_comp_cache_dir(
+            tcx.sess,
+            &name,
+            &[("o", &tmp_file)],
+        )
     };
 
     ModuleCodegenResult(
@@ -82,7 +86,10 @@ fn reuse_workproduct_for_cgu(
 ) -> CompiledModule {
     let work_product = cgu.previous_work_product(tcx);
     let obj_out = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
-    let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &work_product.saved_file);
+    let source_file = rustc_incremental::in_incr_comp_dir_sess(
+        &tcx.sess,
+        &work_product.saved_files.get("o").expect("no saved object file in work product"),
+    );
     if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
         tcx.sess.err(&format!(
             "unable to copy {} to {}: {}",
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 9d2e12f9898..be2d3108c5f 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -79,7 +79,7 @@ mod prelude {
     pub(crate) use rustc_middle::ty::layout::{self, LayoutOf, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
         self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
-        TypeFoldable, UintTy,
+        TypeFoldable, TypeVisitable, UintTy,
     };
     pub(crate) use rustc_target::abi::{Abi, Scalar, Size, VariantIdx};
 
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index 76419b103d0..c1041125ecc 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -1,6 +1,6 @@
 use gccjit::{FunctionType, RValue};
 use rustc_codegen_ssa::traits::BaseTypeMethods;
-use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeVisitable};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
 
 use crate::abi::FnAbiGccExt;
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
index ce341406eaf..fc391f53f18 100644
--- a/compiler/rustc_codegen_gcc/src/common.rs
+++ b/compiler/rustc_codegen_gcc/src/common.rs
@@ -9,10 +9,8 @@ use rustc_codegen_ssa::traits::{
     StaticMethods,
 };
 use rustc_middle::mir::Mutability;
-use rustc_middle::ty::ScalarInt;
 use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
-use rustc_span::Symbol;
 use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
 
 use crate::consts::const_alloc_to_gcc;
@@ -125,12 +123,15 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         self.context.new_rvalue_from_double(typ, val)
     }
 
-    fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
-        let s_str = s.as_str();
-        let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
-            self.global_string(s_str)
-        });
-        let len = s_str.len();
+    fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) {
+        let str_global = *self
+            .const_str_cache
+            .borrow_mut()
+            .raw_entry_mut()
+            .from_key(s)
+            .or_insert_with(|| (s.to_owned(), self.global_string(s)))
+            .1;
+        let len = s.len();
         let cs = self.const_ptrcast(str_global.get_address(None),
             self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
         );
@@ -157,13 +158,13 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
         None
     }
 
+    fn zst_to_backend(&self, _ty: Type<'gcc>) -> RValue<'gcc> {
+        self.const_undef(self.type_ix(0))
+    }
+
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
-            Scalar::Int(ScalarInt::ZST) => {
-                assert_eq!(0, layout.size(self).bytes());
-                self.const_undef(self.type_ix(0))
-            }
             Scalar::Int(int) => {
                 let data = int.assert_bits(layout.size(self));
 
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 44f36cfa4ca..478f6d893dd 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::mono::CodegenUnit;
 use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
 use rustc_session::Session;
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
 use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
 
@@ -101,7 +101,7 @@ pub struct CodegenCx<'gcc, 'tcx> {
     pub global_lvalues: RefCell<FxHashMap<RValue<'gcc>, LValue<'gcc>>>,
 
     /// Cache of constant strings,
-    pub const_str_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+    pub const_str_cache: RefCell<FxHashMap<String, LValue<'gcc>>>,
 
     /// Cache of globals.
     pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 5bfdeb8b93a..399830de84c 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -6,7 +6,14 @@
  * TODO(antoyo): remove the patches.
  */
 
-#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)]
+#![feature(
+    rustc_private,
+    decl_macro,
+    associated_type_bounds,
+    never_type,
+    trusted_len,
+    hash_raw_entry
+)]
 #![allow(broken_intra_doc_links)]
 #![recursion_limit="256"]
 #![warn(rust_2018_idioms)]
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index e21d40b6c37..9468a1ef4bb 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -1,7 +1,7 @@
 use rustc_codegen_ssa::traits::PreDefineMethods;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::mono::{Linkage, Visibility};
-use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeVisitable};
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
 use rustc_span::def_id::DefId;
 
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 569ee2925b1..524d10fb5e2 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -3,7 +3,7 @@ use std::fmt::Write;
 use gccjit::{Struct, Type};
 use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
 use rustc_middle::bug;
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8c1e865762c..4a4cccb490d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -28,7 +28,7 @@ use std::ffi::CStr;
 use std::iter;
 use std::ops::Deref;
 use std::ptr;
-use tracing::debug;
+use tracing::{debug, instrument};
 
 // All Builders must have an llfn associated with them
 #[must_use]
@@ -464,15 +464,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
     }
 
+    #[instrument(level = "trace", skip(self))]
     fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
-        debug!("PlaceRef::load: {:?}", place);
-
         assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
 
         if place.layout.is_zst() {
             return OperandRef::new_zst(self, place.layout);
         }
 
+        #[instrument(level = "trace", skip(bx))]
         fn scalar_load_metadata<'a, 'll, 'tcx>(
             bx: &mut Builder<'a, 'll, 'tcx>,
             load: &'ll Value,
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index ac423a22703..72155d874a2 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
 use tracing::debug;
 
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
-use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeVisitable};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index d37aadeb523..77cbbf4c6ca 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -13,8 +13,6 @@ use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::ScalarInt;
-use rustc_span::symbol::Symbol;
 use rustc_target::abi::{self, AddressSpace, HasDataLayout, Pointer, Size};
 
 use libc::{c_char, c_uint};
@@ -180,22 +178,27 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe { llvm::LLVMConstReal(t, val) }
     }
 
-    fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
-        let s_str = s.as_str();
-        let str_global = *self.const_str_cache.borrow_mut().entry(s).or_insert_with(|| {
-            let sc = self.const_bytes(s_str.as_bytes());
-            let sym = self.generate_local_symbol_name("str");
-            let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
-                bug!("symbol `{}` is already defined", sym);
-            });
-            unsafe {
-                llvm::LLVMSetInitializer(g, sc);
-                llvm::LLVMSetGlobalConstant(g, True);
-                llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
-            }
-            g
-        });
-        let len = s_str.len();
+    fn const_str(&self, s: &str) -> (&'ll Value, &'ll Value) {
+        let str_global = *self
+            .const_str_cache
+            .borrow_mut()
+            .raw_entry_mut()
+            .from_key(s)
+            .or_insert_with(|| {
+                let sc = self.const_bytes(s.as_bytes());
+                let sym = self.generate_local_symbol_name("str");
+                let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", sym);
+                });
+                unsafe {
+                    llvm::LLVMSetInitializer(g, sc);
+                    llvm::LLVMSetGlobalConstant(g, True);
+                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
+                }
+                (s.to_owned(), g)
+            })
+            .1;
+        let len = s.len();
         let cs = consts::ptrcast(
             str_global,
             self.type_ptr_to(self.layout_of(self.tcx.types.str_).llvm_type(self)),
@@ -219,13 +222,13 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         })
     }
 
+    fn zst_to_backend(&self, _llty: &'ll Type) -> &'ll Value {
+        self.const_undef(self.type_ix(0))
+    }
+
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value {
         let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
         match cv {
-            Scalar::Int(ScalarInt::ZST) => {
-                assert_eq!(0, layout.size(self).bytes());
-                self.const_undef(self.type_ix(0))
-            }
             Scalar::Int(int) => {
                 let data = int.assert_bits(layout.size(self));
                 let llval = self.const_uint_big(self.type_ix(bitsize), data);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index c007728095f..55e4a4a7255 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -26,7 +26,6 @@ use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
 use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
 use rustc_target::abi::{
     call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
 };
@@ -56,7 +55,7 @@ pub struct CodegenCx<'ll, 'tcx> {
     pub vtables:
         RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), &'ll Value>>,
     /// Cache of constant strings,
-    pub const_str_cache: RefCell<FxHashMap<Symbol, &'ll Value>>,
+    pub const_str_cache: RefCell<FxHashMap<String, &'ll Value>>,
 
     /// Reverse-direction for const ptrs cast from globals.
     ///
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 87fbb737ea8..8fc8118849b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -93,8 +93,9 @@ impl<'tcx> UniqueTypeId<'tcx> {
     /// Right now this takes the form of a hex-encoded opaque hash value.
     pub fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String {
         let mut hasher = StableHasher::new();
-        let mut hcx = tcx.create_stable_hashing_context();
-        hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher));
+        tcx.with_stable_hashing_context(|mut hcx| {
+            hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher))
+        });
         hasher.finish::<Fingerprint>().to_hex()
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 71699b5cf38..730048d061b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -27,7 +27,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeVisitable};
 use rustc_session::config::{self, DebugInfo};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
@@ -103,14 +103,14 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
             // for macOS to understand. For more info see #11352
             // This can be overridden using --llvm-opts -dwarf-version,N.
             // Android has the same issue (#22398)
-            if let Some(version) = sess.target.dwarf_version {
-                llvm::LLVMRustAddModuleFlag(
-                    self.llmod,
-                    llvm::LLVMModFlagBehavior::Warning,
-                    "Dwarf Version\0".as_ptr().cast(),
-                    version,
-                )
-            }
+            let dwarf_version =
+                sess.opts.debugging_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
+            llvm::LLVMRustAddModuleFlag(
+                self.llmod,
+                llvm::LLVMModFlagBehavior::Warning,
+                "Dwarf Version\0".as_ptr().cast(),
+                dwarf_version,
+            );
 
             // Indicate that we want CodeView debug information on MSVC
             if sess.target.is_like_msvc {
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 6713a756735..a7dd8e16d28 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -5,6 +5,7 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(hash_raw_entry)]
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(extern_types)]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index d92d9d96fe2..5ebc2d6139f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1619,7 +1619,7 @@ extern "C" {
         B: &Builder<'a>,
         Val: &'a Value,
         DestTy: &'a Type,
-        IsSized: bool,
+        IsSigned: bool,
     ) -> &'a Value;
 
     // Comparisons
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index a3053742aad..6e94284852f 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 pub use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::mir::mono::{Linkage, Visibility};
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
-use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeVisitable};
 use rustc_session::config::CrateType;
 use rustc_target::spec::RelocModel;
 use tracing::debug;
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 86280523631..9f0e6c80b19 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
 use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 553486ae8ec..1cb8d342381 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -1,13 +1,12 @@
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_session::cstore::DllImport;
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
 
 use std::io;
 use std::path::{Path, PathBuf};
 
 pub(super) fn find_library(
-    name: Symbol,
+    name: &str,
     verbatim: bool,
     search_paths: &[PathBuf],
     sess: &Session,
diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs
index 6c29692bd3b..9b0ba34135c 100644
--- a/compiler/rustc_codegen_ssa/src/back/command.rs
+++ b/compiler/rustc_codegen_ssa/src/back/command.rs
@@ -7,7 +7,6 @@ use std::io;
 use std::mem;
 use std::process::{self, Output};
 
-use rustc_span::symbol::Symbol;
 use rustc_target::spec::LldFlavor;
 
 #[derive(Clone)]
@@ -47,11 +46,6 @@ impl Command {
         self
     }
 
-    pub fn sym_arg(&mut self, arg: Symbol) -> &mut Command {
-        self.arg(arg.as_str());
-        self
-    }
-
     pub fn args<I>(&mut self, args: I) -> &mut Command
     where
         I: IntoIterator<Item: AsRef<OsStr>>,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 72aa790c363..1628d580b88 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -151,11 +151,23 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
             return;
         }
 
-        let remove_temps_from_module = |module: &CompiledModule| {
-            if let Some(ref obj) = module.object {
-                ensure_removed(sess.diagnostic(), obj);
-            }
-        };
+        let maybe_remove_temps_from_module =
+            |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
+                if !preserve_objects {
+                    if let Some(ref obj) = module.object {
+                        ensure_removed(sess.diagnostic(), obj);
+                    }
+                }
+
+                if !preserve_dwarf_objects {
+                    if let Some(ref dwo_obj) = module.dwarf_object {
+                        ensure_removed(sess.diagnostic(), dwo_obj);
+                    }
+                }
+            };
+
+        let remove_temps_from_module =
+            |module: &CompiledModule| maybe_remove_temps_from_module(false, false, module);
 
         // Otherwise, always remove the metadata and allocator module temporaries.
         if let Some(ref metadata_module) = codegen_results.metadata_module {
@@ -177,15 +189,7 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
         debug!(?preserve_objects, ?preserve_dwarf_objects);
 
         for module in &codegen_results.modules {
-            if !preserve_objects {
-                remove_temps_from_module(module);
-            }
-
-            if !preserve_dwarf_objects {
-                if let Some(ref obj) = module.dwarf_object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-            }
+            maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module);
         }
     });
 
@@ -354,7 +358,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
         }
         if let Some(name) = lib.name {
             let location =
-                find_library(name, lib.verbatim.unwrap_or(false), &lib_search_paths, sess);
+                find_library(name.as_str(), lib.verbatim.unwrap_or(false), &lib_search_paths, sess);
             ab.add_archive(&location, |_| false).unwrap_or_else(|e| {
                 sess.fatal(&format!(
                     "failed to add native library {}: {}",
@@ -649,6 +653,7 @@ fn link_dwarf_object<'a>(
             sess.struct_err("linking dwarf objects with thorin failed")
                 .note(&format!("{:?}", e))
                 .emit();
+            sess.abort_if_errors();
         }
     }
 }
@@ -1117,7 +1122,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
         let path = find_sanitizer_runtime(&sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
         linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
-        linker.link_dylib(Symbol::intern(&filename), false, true);
+        linker.link_dylib(&filename, false, true);
     } else {
         let filename = format!("librustc{}_rt.{}.a", channel, name);
         let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
@@ -2199,6 +2204,7 @@ fn add_local_native_libraries(
         let Some(name) = lib.name else {
             continue;
         };
+        let name = name.as_str();
 
         // Skip if this library is the same as the last.
         last = if (lib.name, lib.kind, lib.verbatim) == last {
@@ -2362,6 +2368,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                         let Some(name) = lib.name else {
                             continue;
                         };
+                        let name = name.as_str();
                         if !relevant_lib(sess, lib) {
                             continue;
                         }
@@ -2519,7 +2526,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
         }
         let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
         cmd.link_rust_dylib(
-            Symbol::intern(&unlib(&sess.target, filestem)),
+            &unlib(&sess.target, filestem),
             parent.unwrap_or_else(|| Path::new("")),
         );
     }
@@ -2551,6 +2558,7 @@ fn add_upstream_native_libraries(
             let Some(name) = lib.name else {
                 continue;
             };
+            let name = name.as_str();
             if !relevant_lib(sess, &lib) {
                 continue;
             }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index b5b63942e2c..955ee245b28 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -16,7 +16,6 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
 
 use cc::windows_registry;
@@ -163,13 +162,13 @@ pub fn get_linker<'a>(
 pub trait Linker {
     fn cmd(&mut self) -> &mut Command;
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
-    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool);
-    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
-    fn link_framework(&mut self, framework: Symbol, as_needed: bool);
-    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool);
+    fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool);
+    fn link_rust_dylib(&mut self, lib: &str, path: &Path);
+    fn link_framework(&mut self, framework: &str, as_needed: bool);
+    fn link_staticlib(&mut self, lib: &str, verbatim: bool);
     fn link_rlib(&mut self, lib: &Path);
     fn link_whole_rlib(&mut self, lib: &Path);
-    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]);
+    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]);
     fn include_path(&mut self, path: &Path);
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
@@ -423,8 +422,8 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) {
-        if self.sess.target.os == "illumos" && lib.as_str() == "c" {
+    fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) {
+        if self.sess.target.os == "illumos" && lib == "c" {
             // libc will be added via late_link_args on illumos so that it will
             // appear last in the library search order.
             // FIXME: This should be replaced by a more complete and generic
@@ -454,7 +453,7 @@ impl<'a> Linker for GccLinker<'a> {
             }
         }
     }
-    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
+    fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
         self.hint_static();
         self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib));
     }
@@ -484,20 +483,20 @@ impl<'a> Linker for GccLinker<'a> {
         self.linker_arg("-znorelro");
     }
 
-    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
+    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
         self.hint_dynamic();
         self.cmd.arg(format!("-l{}", lib));
     }
 
-    fn link_framework(&mut self, framework: Symbol, as_needed: bool) {
+    fn link_framework(&mut self, framework: &str, as_needed: bool) {
         self.hint_dynamic();
         if !as_needed {
             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
             // flag but we have no way to detect that here.
-            // self.cmd.arg("-needed_framework").sym_arg(framework);
+            // self.cmd.arg("-needed_framework").arg(framework);
             self.sess.warn("`as-needed` modifier not implemented yet for ld64");
         }
-        self.cmd.arg("-framework").sym_arg(framework);
+        self.cmd.arg("-framework").arg(framework);
     }
 
     // Here we explicitly ask that the entire archive is included into the
@@ -506,7 +505,7 @@ impl<'a> Linker for GccLinker<'a> {
     // don't otherwise explicitly reference them. This can occur for
     // libraries which are just providing bindings, libraries with generic
     // functions, etc.
-    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target;
         if !target.is_like_osx {
@@ -836,11 +835,11 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg("/OPT:NOREF,NOICF");
     }
 
-    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
+    fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
-    fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) {
+    fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
         // When producing a dll, the MSVC linker may not actually emit a
         // `foo.lib` file if the dll doesn't actually export any symbols, so we
         // check to see if the file is there and just omit linking to it if it's
@@ -851,7 +850,7 @@ impl<'a> Linker for MsvcLinker<'a> {
         }
     }
 
-    fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) {
+    fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
         self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
 
@@ -890,11 +889,11 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn framework_path(&mut self, _path: &Path) {
         bug!("frameworks are not supported on windows")
     }
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         bug!("frameworks are not supported on windows")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
         self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
     }
     fn link_whole_rlib(&mut self, path: &Path) {
@@ -1047,8 +1046,8 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg("-L").arg(path);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
-        self.cmd.arg("-l").sym_arg(lib);
+    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
+        self.cmd.arg("-l").arg(lib);
     }
 
     fn output_filename(&mut self, path: &Path) {
@@ -1059,12 +1058,12 @@ impl<'a> Linker for EmLinker<'a> {
         self.cmd.arg(path);
     }
 
-    fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) {
+    fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
         // Emscripten always links statically
         self.link_staticlib(lib, verbatim);
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
         // not supported?
         self.link_staticlib(lib, verbatim);
     }
@@ -1074,7 +1073,7 @@ impl<'a> Linker for EmLinker<'a> {
         self.link_rlib(lib);
     }
 
-    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
+    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
         self.link_dylib(lib, false, true);
     }
 
@@ -1098,7 +1097,7 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("frameworks are not supported on Emscripten")
     }
 
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         bug!("frameworks are not supported on Emscripten")
     }
 
@@ -1237,12 +1236,12 @@ impl<'a> Linker for WasmLd<'a> {
         }
     }
 
-    fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) {
-        self.cmd.arg("-l").sym_arg(lib);
+    fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
+        self.cmd.arg("-l").arg(lib);
     }
 
-    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
-        self.cmd.arg("-l").sym_arg(lib);
+    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
+        self.cmd.arg("-l").arg(lib);
     }
 
     fn link_rlib(&mut self, lib: &Path) {
@@ -1271,16 +1270,16 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn no_relro(&mut self) {}
 
-    fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
-        self.cmd.arg("-l").sym_arg(lib);
+    fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+        self.cmd.arg("-l").arg(lib);
     }
 
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
-        self.cmd.arg("-l").sym_arg(lib);
+    fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
+        self.cmd.arg("-l").arg(lib);
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
@@ -1360,10 +1359,10 @@ pub struct L4Bender<'a> {
 }
 
 impl<'a> Linker for L4Bender<'a> {
-    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
         bug!("dylibs are not supported on L4Re");
     }
-    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
+    fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
         self.hint_static();
         self.cmd.arg(format!("-PC{}", lib));
     }
@@ -1404,15 +1403,15 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
 
-    fn link_rust_dylib(&mut self, _: Symbol, _: &Path) {
+    fn link_rust_dylib(&mut self, _: &str, _: &Path) {
         panic!("Rust dylibs not supported");
     }
 
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         bug!("frameworks not supported on L4Re");
     }
 
-    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
         self.hint_static();
         self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
         self.cmd.arg("--no-whole-archive");
@@ -1617,19 +1616,19 @@ impl<'a> Linker for PtxLinker<'a> {
         self.cmd.arg("-o").arg(path);
     }
 
-    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
         panic!("external dylibs not supported")
     }
 
-    fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
+    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
+    fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1637,7 +1636,7 @@ impl<'a> Linker for PtxLinker<'a> {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
@@ -1717,19 +1716,19 @@ impl<'a> Linker for BpfLinker<'a> {
         self.cmd.arg("-o").arg(path);
     }
 
-    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+    fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
         panic!("external dylibs not supported")
     }
 
-    fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) {
+    fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
         panic!("external dylibs not supported")
     }
 
-    fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) {
+    fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
         panic!("staticlibs not supported")
     }
 
-    fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+    fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
         panic!("staticlibs not supported")
     }
 
@@ -1737,7 +1736,7 @@ impl<'a> Linker for BpfLinker<'a> {
         panic!("frameworks not supported")
     }
 
-    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+    fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
         panic!("frameworks not supported")
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 632f07c5c2d..f4a5cac872e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -494,12 +494,18 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
     let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
 
     for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
-        if let Some(path) = &module.object {
-            if let Some((id, product)) =
-                copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, path)
-            {
-                work_products.insert(id, product);
-            }
+        let mut files = Vec::new();
+        if let Some(object_file_path) = &module.object {
+            files.push(("o", object_file_path.as_path()));
+        }
+        if let Some(dwarf_object_file_path) = &module.dwarf_object {
+            files.push(("dwo", dwarf_object_file_path.as_path()));
+        }
+
+        if let Some((id, product)) =
+            copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice())
+        {
+            work_products.insert(id, product);
         }
     }
 
@@ -856,29 +862,50 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
     assert!(module_config.emit_obj != EmitObj::None);
 
     let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
-    let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
-    let source_file = in_incr_comp_dir(&incr_comp_session_dir, &module.source.saved_file);
-    debug!(
-        "copying pre-existing module `{}` from {:?} to {}",
-        module.name,
-        source_file,
-        obj_out.display()
+
+    let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
+        let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path);
+        debug!(
+            "copying pre-existing module `{}` from {:?} to {}",
+            module.name,
+            source_file,
+            output_path.display()
+        );
+        match link_or_copy(&source_file, &output_path) {
+            Ok(_) => Some(output_path),
+            Err(err) => {
+                let diag_handler = cgcx.create_diag_handler();
+                diag_handler.err(&format!(
+                    "unable to copy {} to {}: {}",
+                    source_file.display(),
+                    output_path.display(),
+                    err
+                ));
+                None
+            }
+        }
+    };
+
+    let object = load_from_incr_comp_dir(
+        cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)),
+        &module.source.saved_files.get("o").expect("no saved object file in work product"),
     );
-    if let Err(err) = link_or_copy(&source_file, &obj_out) {
-        let diag_handler = cgcx.create_diag_handler();
-        diag_handler.err(&format!(
-            "unable to copy {} to {}: {}",
-            source_file.display(),
-            obj_out.display(),
-            err
-        ));
-    }
+    let dwarf_object =
+        module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
+            let dwarf_obj_out = cgcx
+                .output_filenames
+                .split_dwarf_path(cgcx.split_debuginfo, cgcx.split_dwarf_kind, Some(&module.name))
+                .expect(
+                    "saved dwarf object in work product but `split_dwarf_path` returned `None`",
+                );
+            load_from_incr_comp_dir(dwarf_obj_out, &saved_dwarf_object_file)
+        });
 
     WorkItemResult::Compiled(CompiledModule {
         name: module.name,
         kind: ModuleKind::Regular,
-        object: Some(obj_out),
-        dwarf_object: None,
+        object,
+        dwarf_object,
         bytecode: None,
     })
 }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 8755d91818d..8cd5a0fc247 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -701,16 +701,20 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                 // If we cannot evaluate the constant to a known type, we fall back
                 // to emitting a stable hash value of the constant. This isn't very pretty
                 // but we get a deterministic, virtually unique value for the constant.
-                let hcx = &mut tcx.create_stable_hashing_context();
-                let mut hasher = StableHasher::new();
-                let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
-                hcx.while_hashing_spans(false, |hcx| ct.to_valtree().hash_stable(hcx, &mut hasher));
+                //
                 // Let's only emit 64 bits of the hash value. That should be plenty for
                 // avoiding collisions and will make the emitted type names shorter.
-                // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
-                // would lead to endianness problems.
-                let hash: u128 = hasher.finish();
-                let hash_short = (hash.to_le() as u64).to_le();
+                let hash_short = tcx.with_stable_hashing_context(|mut hcx| {
+                    let mut hasher = StableHasher::new();
+                    let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
+                    hcx.while_hashing_spans(false, |hcx| {
+                        ct.to_valtree().hash_stable(hcx, &mut hasher)
+                    });
+                    // Note: Don't use `StableHashResult` impl of `u64` here directly, since that
+                    // would lead to endianness problems.
+                    let hash: u128 = hasher.finish();
+                    (hash.to_le() as u64).to_le()
+                });
 
                 if cpp_like_debuginfo(tcx) {
                     write!(output, "CONST${:x}", hash_short)
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 80dab115fac..24da48ead63 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -15,7 +15,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     fx: &FunctionCx<'a, 'tcx, Bx>,
 ) -> BitSet<mir::Local> {
     let mir = fx.mir;
-    let dominators = mir.dominators();
+    let dominators = mir.basic_blocks.dominators();
     let locals = mir
         .local_decls
         .iter()
@@ -143,13 +143,13 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx,
             // now that we have moved to the "slice of projections" representation.
             if let mir::ProjectionElem::Index(local) = elem {
                 self.visit_local(
-                    &local,
+                    local,
                     PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                     location,
                 );
             }
         } else {
-            self.visit_local(&place_ref.local, context, location);
+            self.visit_local(place_ref.local, context, location);
         }
     }
 }
@@ -185,7 +185,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
         self.process_place(&place.as_ref(), context, location);
     }
 
-    fn visit_local(&mut self, &local: &mir::Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) {
         match context {
             PlaceContext::MutatingUse(MutatingUseContext::Call)
             | PlaceContext::MutatingUse(MutatingUseContext::Yield) => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 0503d723240..b8e3cb32ef6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::{self, SwitchTargets};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
-use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
 use rustc_symbol_mangling::typeid_for_fnabi;
@@ -489,8 +489,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 (LangItem::PanicBoundsCheck, vec![index, len, location])
             }
             _ => {
-                let msg_str = Symbol::intern(msg.description());
-                let msg = bx.const_str(msg_str);
+                let msg = bx.const_str(msg.description());
                 // It's `pub fn panic(expr: &str)`, with the wide reference being passed
                 // as two arguments, and `#[track_caller]` adds an implicit third argument.
                 (LangItem::Panic, vec![msg.0, msg.1, location])
@@ -571,7 +570,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     })
                 });
-                let msg = bx.const_str(Symbol::intern(&msg_str));
+                let msg = bx.const_str(&msg_str);
                 let location = self.get_caller_location(bx, source_info).immediate();
 
                 // Obtain the panic entry point.
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 7f14b95317b..645afae30d8 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -513,9 +513,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         };
 
                         let ty = substs.type_at(0);
-                        if int_type_width_signed(ty, bx.tcx()).is_some()
-                            || (ty.is_unsafe_ptr() && op == "xchg")
-                        {
+                        if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
                             let mut ptr = args[0].immediate();
                             let mut val = args[1].immediate();
                             if ty.is_unsafe_ptr() {
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 0c958de64fa..ec3f7a2156a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -2,7 +2,7 @@ use crate::traits::*;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
-use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TypeFoldable, TypeVisitable};
 use rustc_symbol_mangling::typeid_for_fnabi;
 use rustc_target::abi::call::{FnAbi, PassMode};
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 2e655ae94cc..c612634fce2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -84,6 +84,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
                 let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout));
                 OperandValue::Immediate(llval)
             }
+            ConstValue::ZeroSized => {
+                let llval = bx.zst_to_backend(bx.immediate_backend_type(layout));
+                OperandValue::Immediate(llval)
+            }
             ConstValue::Slice { data, start, end } => {
                 let Abi::ScalarPair(a_scalar, _) = layout.abi else {
                     bug!("from_const: invalid ScalarPair layout: {:#?}", layout);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 5b88635982f..58cee0c8bb0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -204,6 +204,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     }
 
     /// Obtain the actual discriminant of a value.
+    #[instrument(level = "trace", skip(bx))]
     pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         self,
         bx: &mut Bx,
@@ -420,12 +421,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
 }
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    #[instrument(level = "trace", skip(self, bx))]
     pub fn codegen_place(
         &mut self,
         bx: &mut Bx,
         place_ref: mir::PlaceRef<'tcx>,
     ) -> PlaceRef<'tcx, Bx::Value> {
-        debug!("codegen_place(place_ref={:?})", place_ref);
         let cx = self.cx;
         let tcx = self.cx.tcx();
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 81c1897694c..55ab8b08d4a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -12,17 +12,15 @@ use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
 use rustc_span::source_map::{Span, DUMMY_SP};
-use rustc_target::abi::{Abi, Int, Variants};
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    #[instrument(level = "trace", skip(self, bx))]
     pub fn codegen_rvalue(
         &mut self,
         mut bx: Bx,
         dest: PlaceRef<'tcx, Bx::Value>,
         rvalue: &mir::Rvalue<'tcx>,
     ) -> Bx {
-        debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})", dest.llval, rvalue);
-
         match *rvalue {
             mir::Rvalue::Use(ref operand) => {
                 let cg_operand = self.codegen_operand(&mut bx, operand);
@@ -125,7 +123,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     // Do not generate stores and GEPis for zero-sized fields.
                     if !op.layout.is_zst() {
                         let field_index = active_field_index.unwrap_or(i);
-                        let field = dest.project_field(&mut bx, field_index);
+                        let field = if let mir::AggregateKind::Array(_) = **kind {
+                            let llindex = bx.cx().const_usize(field_index as u64);
+                            dest.project_index(&mut bx, llindex)
+                        } else {
+                            dest.project_field(&mut bx, field_index)
+                        };
                         op.val.store(&mut bx, field);
                     }
                 }
@@ -213,6 +216,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     substs,
                                     ty::ClosureKind::FnOnce,
                                 )
+                                .expect("failed to normalize and resolve closure during codegen")
                                 .polymorphize(bx.cx().tcx());
                                 OperandValue::Immediate(bx.cx().get_fn_addr(instance))
                             }
@@ -284,74 +288,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             CastTy::from_ty(operand.layout.ty).expect("bad input type for cast");
                         let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast");
                         let ll_t_in = bx.cx().immediate_backend_type(operand.layout);
-                        match operand.layout.variants {
-                            Variants::Single { index } => {
-                                if let Some(discr) =
-                                    operand.layout.ty.discriminant_for_variant(bx.tcx(), index)
-                                {
-                                    let discr_layout = bx.cx().layout_of(discr.ty);
-                                    let discr_t = bx.cx().immediate_backend_type(discr_layout);
-                                    let discr_val = bx.cx().const_uint_big(discr_t, discr.val);
-                                    let discr_val =
-                                        bx.intcast(discr_val, ll_t_out, discr.ty.is_signed());
-
-                                    return (
-                                        bx,
-                                        OperandRef {
-                                            val: OperandValue::Immediate(discr_val),
-                                            layout: cast,
-                                        },
-                                    );
-                                }
-                            }
-                            Variants::Multiple { .. } => {}
-                        }
                         let llval = operand.immediate();
 
-                        let mut signed = false;
-                        if let Abi::Scalar(scalar) = operand.layout.abi {
-                            if let Int(_, s) = scalar.primitive() {
-                                // We use `i1` for bytes that are always `0` or `1`,
-                                // e.g., `#[repr(i8)] enum E { A, B }`, but we can't
-                                // let LLVM interpret the `i1` as signed, because
-                                // then `i1 1` (i.e., E::B) is effectively `i8 -1`.
-                                signed = !scalar.is_bool() && s;
-
-                                if !scalar.is_always_valid(bx.cx())
-                                    && scalar.valid_range(bx.cx()).end
-                                        >= scalar.valid_range(bx.cx()).start
-                                {
-                                    // We want `table[e as usize ± k]` to not
-                                    // have bound checks, and this is the most
-                                    // convenient place to put the `assume`s.
-                                    if scalar.valid_range(bx.cx()).start > 0 {
-                                        let enum_value_lower_bound = bx.cx().const_uint_big(
-                                            ll_t_in,
-                                            scalar.valid_range(bx.cx()).start,
-                                        );
-                                        let cmp_start = bx.icmp(
-                                            IntPredicate::IntUGE,
-                                            llval,
-                                            enum_value_lower_bound,
-                                        );
-                                        bx.assume(cmp_start);
-                                    }
-
-                                    let enum_value_upper_bound = bx
-                                        .cx()
-                                        .const_uint_big(ll_t_in, scalar.valid_range(bx.cx()).end);
-                                    let cmp_end = bx.icmp(
-                                        IntPredicate::IntULE,
-                                        llval,
-                                        enum_value_upper_bound,
-                                    );
-                                    bx.assume(cmp_end);
-                                }
-                            }
-                        }
-
                         let newval = match (r_t_in, r_t_out) {
-                            (CastTy::Int(_), CastTy::Int(_)) => bx.intcast(llval, ll_t_out, signed),
+                            (CastTy::Int(i), CastTy::Int(_)) => {
+                                bx.intcast(llval, ll_t_out, i.is_signed())
+                            }
                             (CastTy::Float, CastTy::Float) => {
                                 let srcsz = bx.cx().float_width(ll_t_in);
                                 let dstsz = bx.cx().float_width(ll_t_out);
@@ -363,8 +305,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     llval
                                 }
                             }
-                            (CastTy::Int(_), CastTy::Float) => {
-                                if signed {
+                            (CastTy::Int(i), CastTy::Float) => {
+                                if i.is_signed() {
                                     bx.sitofp(llval, ll_t_out)
                                 } else {
                                     bx.uitofp(llval, ll_t_out)
@@ -373,8 +315,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Ptr(_)) => {
                                 bx.pointercast(llval, ll_t_out)
                             }
-                            (CastTy::Int(_), CastTy::Ptr(_)) => {
-                                let usize_llval = bx.intcast(llval, bx.cx().type_isize(), signed);
+                            (CastTy::Int(i), CastTy::Ptr(_)) => {
+                                let usize_llval =
+                                    bx.intcast(llval, bx.cx().type_isize(), i.is_signed());
                                 bx.inttoptr(usize_llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(IntTy::I)) => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index d9ebfc3e871..f452f29883f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -6,9 +6,8 @@ use crate::traits::BuilderMethods;
 use crate::traits::*;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+    #[instrument(level = "debug", skip(self, bx))]
     pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>) -> Bx {
-        debug!("codegen_statement(statement={:?})", statement);
-
         self.set_debug_loc(&mut bx, statement.source_info);
         match statement.kind {
             mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs
index c3519a24d53..8a91d4735ba 100644
--- a/compiler/rustc_codegen_ssa/src/traits/consts.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs
@@ -2,7 +2,6 @@ use super::BackendTypes;
 use crate::mir::place::PlaceRef;
 use rustc_middle::mir::interpret::{ConstAllocation, Scalar};
 use rustc_middle::ty::layout::TyAndLayout;
-use rustc_span::Symbol;
 use rustc_target::abi::{self, Size};
 
 pub trait ConstMethods<'tcx>: BackendTypes {
@@ -21,7 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_u8(&self, i: u8) -> Self::Value;
     fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
 
-    fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value);
+    fn const_str(&self, s: &str) -> (Self::Value, Self::Value);
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
 
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
@@ -30,6 +29,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value;
 
     fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value;
+    fn zst_to_backend(&self, llty: Self::Type) -> Self::Value;
     fn from_const_alloc(
         &self,
         layout: TyAndLayout<'tcx>,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 0dac4f8978e..b18976302b4 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -2,7 +2,7 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr};
 use crate::interpret::eval_nullary_intrinsic;
 use crate::interpret::{
     intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, CtfeValidationMode, GlobalId,
-    Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar,
+    Immediate, InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
     ScalarMaybeUninit, StackPopCleanup,
 };
 
@@ -157,7 +157,7 @@ pub(super) fn op_to_const<'tcx>(
                     "this MPlaceTy must come from a validated constant, thus we can assume the \
                 alignment is correct",
                 );
-                ConstValue::Scalar(Scalar::ZST)
+                ConstValue::ZeroSized
             }
         }
     };
@@ -189,6 +189,7 @@ pub(super) fn op_to_const<'tcx>(
                 let len: usize = len.try_into().unwrap();
                 ConstValue::Slice { data, start, end: start + len }
             }
+            Immediate::Uninit => to_const_value(&op.assert_mem_place()),
         },
     }
 }
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index ac529bf152f..29ab1d18771 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir::AssertMessage;
 use rustc_session::Limit;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::{Align, Size};
-use rustc_target::spec::abi::Abi;
+use rustc_target::spec::abi::Abi as CallAbi;
 
 use crate::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
@@ -263,7 +263,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        _abi: Abi,
+        _abi: CallAbi,
         args: &[OpTy<'tcx>],
         _dest: &PlaceTy<'tcx>,
         _ret: Option<mir::BasicBlock>,
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index f8b390aaf50..2288a4e7b6c 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -272,7 +272,7 @@ pub fn valtree_to_const_value<'tcx>(
     match ty.kind() {
         ty::FnDef(..) => {
             assert!(valtree.unwrap_branch().is_empty());
-            ConstValue::Scalar(Scalar::ZST)
+            ConstValue::ZeroSized
         }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => match valtree {
             ty::ValTree::Leaf(scalar_int) => ConstValue::Scalar(Scalar::Int(scalar_int)),
@@ -344,11 +344,7 @@ fn valtree_into_mplace<'tcx>(
 
     match ty.kind() {
         ty::FnDef(_, _) => {
-            ecx.write_immediate(
-                Immediate::Scalar(ScalarMaybeUninit::Scalar(Scalar::ZST)),
-                &place.into(),
-            )
-            .unwrap();
+            ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap();
         }
         ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
             let scalar_int = valtree.unwrap_leaf();
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
new file mode 100644
index 00000000000..a463fe7b970
--- /dev/null
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -0,0 +1,89 @@
+use rustc_hir::ConstContext;
+use rustc_macros::SessionDiagnostic;
+use rustc_span::Span;
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::unstable_in_stable)]
+pub(crate) struct UnstableInStable {
+    pub gate: String,
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        const_eval::unstable_sugg,
+        code = "#[rustc_const_unstable(feature = \"...\", issue = \"...\")]\n",
+        applicability = "has-placeholders"
+    )]
+    #[suggestion(
+        const_eval::bypass_sugg,
+        code = "#[rustc_allow_const_fn_unstable({gate})]\n",
+        applicability = "has-placeholders"
+    )]
+    pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::thread_local_access, code = "E0625")]
+pub(crate) struct NonConstOpErr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::static_access, code = "E0013")]
+#[help]
+pub(crate) struct StaticAccessErr {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+    #[note(const_eval::teach_note)]
+    #[help(const_eval::teach_help)]
+    pub teach: Option<()>,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::raw_ptr_to_int)]
+#[note]
+#[note(const_eval::note2)]
+pub(crate) struct RawPtrToIntErr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::raw_ptr_comparison)]
+#[note]
+pub(crate) struct RawPtrComparisonErr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::panic_non_str)]
+pub(crate) struct PanicNonStrErr {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::mut_deref, code = "E0658")]
+pub(crate) struct MutDerefErr {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::transient_mut_borrow, code = "E0658")]
+pub(crate) struct TransientMutBorrowErr {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(const_eval::transient_mut_borrow_raw, code = "E0658")]
+pub(crate) struct TransientMutBorrowErrRaw {
+    #[primary_span]
+    pub span: Span,
+    pub kind: ConstContext,
+}
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 076415b2d1b..5d598b65c72 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -8,7 +8,7 @@ use rustc_middle::mir::CastKind;
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
-use rustc_target::abi::{Integer, Variants};
+use rustc_target::abi::Integer;
 use rustc_type_ir::sty::TyKind::*;
 
 use super::{
@@ -100,7 +100,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                             def_id,
                             substs,
                             ty::ClosureKind::FnOnce,
-                        );
+                        )
+                        .ok_or_else(|| err_inval!(TooGeneric))?;
                         let fn_ptr = self.create_fn_alloc_ptr(FnVal::Instance(instance));
                         self.write_pointer(fn_ptr, dest)?;
                     }
@@ -127,12 +128,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Float(FloatTy::F64) => {
                 return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, cast_ty).into());
             }
-            // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
-            // are represented as integers.
+            // The rest is integer/pointer-"like", including fn ptr casts
             _ => assert!(
                 src.layout.ty.is_bool()
                     || src.layout.ty.is_char()
-                    || src.layout.ty.is_enum()
                     || src.layout.ty.is_integral()
                     || src.layout.ty.is_any_ptr(),
                 "Unexpected cast from type {:?}",
@@ -142,25 +141,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         // # First handle non-scalar source values.
 
-        // Handle cast from a ZST enum (0 or 1 variants).
-        match src.layout.variants {
-            Variants::Single { index } => {
-                if src.layout.abi.is_uninhabited() {
-                    // This is dead code, because an uninhabited enum is UB to
-                    // instantiate.
-                    throw_ub!(Unreachable);
-                }
-                if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) {
-                    assert!(src.layout.is_zst());
-                    let discr_layout = self.layout_of(discr.ty)?;
-
-                    let scalar = Scalar::from_uint(discr.val, discr_layout.layout.size());
-                    return Ok(self.cast_from_int_like(scalar, discr_layout, cast_ty)?.into());
-                }
-            }
-            Variants::Multiple { .. } => {}
-        }
-
         // Handle casting any ptr to raw ptr (might be a fat ptr).
         if src.layout.ty.is_any_ptr() && cast_ty.is_unsafe_ptr() {
             let dest_layout = self.layout_of(cast_ty)?;
@@ -173,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 assert_eq!(dest_layout.size, self.pointer_size());
                 assert!(src.layout.ty.is_unsafe_ptr());
                 return match **src {
-                    Immediate::ScalarPair(data, _) => Ok(data.into()),
+                    Immediate::ScalarPair(data, _) => Ok(data.check_init()?.into()),
                     Immediate::Scalar(..) => span_bug!(
                         self.cur_span(),
                         "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
@@ -181,6 +161,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         src.layout.ty,
                         cast_ty
                     ),
+                    Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
                 };
             }
         }
@@ -202,7 +183,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let ptr = self.scalar_to_ptr(scalar)?;
         match ptr.into_pointer_or_addr() {
             Ok(ptr) => M::expose_ptr(self, ptr)?,
-            Err(_) => {} // do nothing, exposing an invalid pointer has no meaning
+            Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
         };
         Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
     }
@@ -378,7 +359,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let src_field = self.operand_field(src, i)?;
                     let dst_field = self.place_field(dest, i)?;
                     if src_field.layout.ty == cast_ty_field.ty {
-                        self.copy_op(&src_field, &dst_field)?;
+                        self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?;
                     } else {
                         self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
                     }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 66c73624501..2e47cf89210 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::layout::{
 use rustc_middle::ty::{
     self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
 };
-use rustc_mir_dataflow::storage::always_live_locals;
+use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Limit;
 use rustc_span::{Pos, Span};
@@ -112,6 +112,8 @@ pub struct Frame<'mir, 'tcx, Tag: Provenance = AllocId, Extra = ()> {
     /// The locals are stored as `Option<Value>`s.
     /// `None` represents a local that is currently dead, while a live local
     /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
+    ///
+    /// Do *not* access this directly; always go through the machine hook!
     pub locals: IndexVec<mir::Local, LocalState<'tcx, Tag>>,
 
     /// The span of the `tracing` crate is stored here.
@@ -179,10 +181,6 @@ pub struct LocalState<'tcx, Tag: Provenance = AllocId> {
 pub enum LocalValue<Tag: Provenance = AllocId> {
     /// This local is not currently alive, and cannot be used at all.
     Dead,
-    /// This local is alive but not yet allocated. It cannot be read from or have its address taken,
-    /// and will be allocated on the first write. This is to support unsized locals, where we cannot
-    /// know their size in advance.
-    Unallocated,
     /// A normal, live local.
     /// Mostly for convenience, we re-use the `Operand` type here.
     /// This is an optimization over just always having a pointer here;
@@ -196,12 +194,10 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
     ///
     /// Note: This may only be invoked from the `Machine::access_local` hook and not from
     /// anywhere else. You may be invalidating machine invariants if you do!
-    pub fn access(&self) -> InterpResult<'tcx, Operand<Tag>> {
-        match self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal),
-            LocalValue::Unallocated => {
-                bug!("The type checker should prevent reading from a never-written local")
-            }
+    #[inline]
+    pub fn access(&self) -> InterpResult<'tcx, &Operand<Tag>> {
+        match &self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
             LocalValue::Live(val) => Ok(val),
         }
     }
@@ -211,15 +207,11 @@ impl<'tcx, Tag: Provenance + 'static> LocalState<'tcx, Tag> {
     ///
     /// Note: This may only be invoked from the `Machine::access_local_mut` hook and not from
     /// anywhere else. You may be invalidating machine invariants if you do!
-    pub fn access_mut(
-        &mut self,
-    ) -> InterpResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> {
-        match self.value {
-            LocalValue::Dead => throw_ub!(DeadLocal),
-            LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)),
-            ref mut local @ (LocalValue::Live(Operand::Immediate(_)) | LocalValue::Unallocated) => {
-                Ok(Ok(local))
-            }
+    #[inline]
+    pub fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand<Tag>> {
+        match &mut self.value {
+            LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"?
+            LocalValue::Live(val) => Ok(val),
         }
     }
 }
@@ -710,16 +702,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             })?;
         }
 
-        // Locals are initially unallocated.
-        let dummy = LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) };
+        // Most locals are initially dead.
+        let dummy = LocalState { value: LocalValue::Dead, layout: Cell::new(None) };
         let mut locals = IndexVec::from_elem(dummy, &body.local_decls);
 
-        // Now mark those locals as dead that we do not want to initialize
-        // Mark locals that use `Storage*` annotations as dead on function entry.
-        let always_live = always_live_locals(self.body());
+        // Now mark those locals as live that have no `Storage*` annotations.
+        let always_live = always_storage_live_locals(self.body());
         for local in locals.indices() {
-            if !always_live.contains(local) {
-                locals[local].value = LocalValue::Dead;
+            if always_live.contains(local) {
+                locals[local].value = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
             }
         }
         // done
@@ -791,7 +782,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if unwinding { "during unwinding" } else { "returning from function" }
         );
 
-        // Sanity check `unwinding`.
+        // Check `unwinding`.
         assert_eq!(
             unwinding,
             match self.frame().loc {
@@ -799,51 +790,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 Err(_) => true,
             }
         );
-
         if unwinding && self.frame_idx() == 0 {
             throw_ub_format!("unwinding past the topmost frame of the stack");
         }
 
-        let frame =
-            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
-
-        if !unwinding {
-            let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
-            self.copy_op_transmute(&op, &frame.return_place)?;
-            trace!("{:?}", self.dump_place(*frame.return_place));
-        }
-
-        let return_to_block = frame.return_to_block;
-
-        // Now where do we jump next?
+        // Copy return value. Must of course happen *before* we deallocate the locals.
+        let copy_ret_result = if !unwinding {
+            let op = self
+                .local_to_op(self.frame(), mir::RETURN_PLACE, None)
+                .expect("return place should always be live");
+            let dest = self.frame().return_place;
+            let err = self.copy_op(&op, &dest, /*allow_transmute*/ true);
+            trace!("return value: {:?}", self.dump_place(*dest));
+            // We delay actually short-circuiting on this error until *after* the stack frame is
+            // popped, since we want this error to be attributed to the caller, whose type defines
+            // this transmute.
+            err
+        } else {
+            Ok(())
+        };
 
+        // Cleanup: deallocate locals.
         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
-        // In that case, we return early. We also avoid validation in that case,
-        // because this is CTFE and the final value will be thoroughly validated anyway.
+        // We do this while the frame is still on the stack, so errors point to the callee.
+        let return_to_block = self.frame().return_to_block;
         let cleanup = match return_to_block {
             StackPopCleanup::Goto { .. } => true,
             StackPopCleanup::Root { cleanup, .. } => cleanup,
         };
+        if cleanup {
+            // We need to take the locals out, since we need to mutate while iterating.
+            let locals = mem::take(&mut self.frame_mut().locals);
+            for local in &locals {
+                self.deallocate_local(local.value)?;
+            }
+        }
+
+        // All right, now it is time to actually pop the frame.
+        // Note that its locals are gone already, but that's fine.
+        let frame =
+            self.stack_mut().pop().expect("tried to pop a stack frame, but there were none");
+        // Report error from return value copy, if any.
+        copy_ret_result?;
 
+        // If we are not doing cleanup, also skip everything else.
         if !cleanup {
             assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
             assert!(!unwinding, "tried to skip cleanup during unwinding");
-            // Leak the locals, skip validation, skip machine hook.
+            // Skip machine hook.
             return Ok(());
         }
-
-        trace!("locals: {:#?}", frame.locals);
-
-        // Cleanup: deallocate all locals that are backed by an allocation.
-        for local in &frame.locals {
-            self.deallocate_local(local.value)?;
-        }
-
         if M::after_stack_pop(self, frame, unwinding)? == StackPopJump::NoJump {
             // The hook already did everything.
-            // We want to skip the `info!` below, hence early return.
             return Ok(());
         }
+
         // Normal return, figure out where to jump.
         if unwinding {
             // Follow the unwind edge.
@@ -874,7 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
         trace!("{:?} is now live", local);
 
-        let local_val = LocalValue::Unallocated;
+        let local_val = LocalValue::Live(Operand::Immediate(Immediate::Uninit));
         // StorageLive expects the local to be dead, and marks it live.
         let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
         if !matches!(old, LocalValue::Dead) {
@@ -977,12 +978,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
 
                 match self.ecx.stack()[frame].locals[local].value {
                     LocalValue::Dead => write!(fmt, " is dead")?,
-                    LocalValue::Unallocated => write!(fmt, " is unallocated")?,
+                    LocalValue::Live(Operand::Immediate(Immediate::Uninit)) => {
+                        write!(fmt, " is uninitialized")?
+                    }
                     LocalValue::Live(Operand::Indirect(mplace)) => {
                         write!(
                             fmt,
-                            " by align({}){} ref {:?}:",
-                            mplace.align.bytes(),
+                            " by {} ref {:?}:",
                             match mplace.meta {
                                 MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta),
                                 MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(),
@@ -1011,13 +1013,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
                 write!(fmt, ": {:?}", self.ecx.dump_allocs(allocs.into_iter().flatten().collect()))
             }
             Place::Ptr(mplace) => match mplace.ptr.provenance.and_then(Provenance::get_alloc_id) {
-                Some(alloc_id) => write!(
-                    fmt,
-                    "by align({}) ref {:?}: {:?}",
-                    mplace.align.bytes(),
-                    mplace.ptr,
-                    self.ecx.dump_alloc(alloc_id)
-                ),
+                Some(alloc_id) => {
+                    write!(fmt, "by ref {:?}: {:?}", mplace.ptr, self.ecx.dump_alloc(alloc_id))
+                }
                 ptr => write!(fmt, " integral by ref: {:?}", ptr),
             },
         }
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index c1d42c9ae7c..9dfdafcb38e 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -168,8 +168,51 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         mplace: &MPlaceTy<'tcx>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
-        // ZSTs cannot contain pointers, so we can skip them.
-        if mplace.layout.is_zst() {
+        // We want to walk the aggregate to look for references to intern. While doing that we
+        // also need to take special care of interior mutability.
+        //
+        // As an optimization, however, if the allocation does not contain any references: we don't
+        // need to do the walk. It can be costly for big arrays for example (e.g. issue #93215).
+        let is_walk_needed = |mplace: &MPlaceTy<'tcx>| -> InterpResult<'tcx, bool> {
+            // ZSTs cannot contain pointers, we can avoid the interning walk.
+            if mplace.layout.is_zst() {
+                return Ok(false);
+            }
+
+            // Now, check whether this allocation could contain references.
+            //
+            // Note, this check may sometimes not be cheap, so we only do it when the walk we'd like
+            // to avoid could be expensive: on the potentially larger types, arrays and slices,
+            // rather than on all aggregates unconditionally.
+            if matches!(mplace.layout.ty.kind(), ty::Array(..) | ty::Slice(..)) {
+                let Some((size, align)) = self.ecx.size_and_align_of_mplace(&mplace)? else {
+                    // We do the walk if we can't determine the size of the mplace: we may be
+                    // dealing with extern types here in the future.
+                    return Ok(true);
+                };
+
+                // If there are no relocations in this allocation, it does not contain references
+                // that point to another allocation, and we can avoid the interning walk.
+                if let Some(alloc) = self.ecx.get_ptr_alloc(mplace.ptr, size, align)? {
+                    if !alloc.has_relocations() {
+                        return Ok(false);
+                    }
+                } else {
+                    // We're encountering a ZST here, and can avoid the walk as well.
+                    return Ok(false);
+                }
+            }
+
+            // In the general case, we do the walk.
+            Ok(true)
+        };
+
+        // If this allocation contains no references to intern, we avoid the potentially costly
+        // walk.
+        //
+        // We can do this before the checks for interior mutability below, because only references
+        // are relevant in that situation, and we're checking if there are any here.
+        if !is_walk_needed(mplace)? {
             return Ok(());
         }
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index e51c51cf45e..93b64d9d37a 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -174,7 +174,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let val =
                     self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
                 let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
-                self.copy_op(&val, dest)?;
+                self.copy_op(&val, dest, /*allow_transmute*/ false)?;
             }
 
             sym::ctpop
@@ -217,7 +217,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     sym::mul_with_overflow => BinOp::Mul,
                     _ => bug!(),
                 };
-                self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
+                self.binop_with_overflow(
+                    bin_op, /*force_overflow_checks*/ true, &lhs, &rhs, dest,
+                )?;
             }
             sym::saturating_add | sym::saturating_sub => {
                 let l = self.read_immediate(&args[0])?;
@@ -392,7 +394,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             sym::transmute => {
-                self.copy_op_transmute(&args[0], dest)?;
+                self.copy_op(&args[0], dest, /*allow_transmute*/ true)?;
             }
             sym::assert_inhabited | sym::assert_zero_valid | sym::assert_uninit_valid => {
                 let ty = instance.substs.type_at(0);
@@ -459,7 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let place = self.mplace_index(&dest, i)?;
                     let value =
                         if i == index { *elem } else { self.mplace_index(&input, i)?.into() };
-                    self.copy_op(&value, &place.into())?;
+                    self.copy_op(&value, &place.into(), /*allow_transmute*/ false)?;
                 }
             }
             sym::simd_extract => {
@@ -471,11 +473,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     index,
                     input_len
                 );
-                self.copy_op(&self.mplace_index(&input, index)?.into(), dest)?;
+                self.copy_op(
+                    &self.mplace_index(&input, index)?.into(),
+                    dest,
+                    /*allow_transmute*/ false,
+                )?;
             }
             sym::likely | sym::unlikely | sym::black_box => {
                 // These just return their argument
-                self.copy_op(&args[0], dest)?;
+                self.copy_op(&args[0], dest, /*allow_transmute*/ false)?;
             }
             sym::assume => {
                 let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?;
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index c18ac84171d..7f8eea94aee 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -10,12 +10,11 @@ use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_target::abi::Size;
-use rustc_target::spec::abi::Abi;
+use rustc_target::spec::abi::Abi as CallAbi;
 
 use super::{
     AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
-    LocalValue, MemPlace, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
-    StackPopUnwind,
+    MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -139,11 +138,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether to enforce integers and floats not having provenance.
     fn enforce_number_no_provenance(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
-    /// Whether function calls should be [ABI](Abi)-checked.
+    /// Whether function calls should be [ABI](CallAbi)-checked.
     fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
         true
     }
 
+    /// Whether CheckedBinOp MIR statements should actually check for overflow.
+    fn checked_binop_checks_overflow(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+
     /// Entry point for obtaining the MIR of anything that should get evaluated.
     /// So not just functions and shims, but also const/static initializers, anonymous
     /// constants, ...
@@ -167,7 +169,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn find_mir_or_eval_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        abi: Abi,
+        abi: CallAbi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         destination: &PlaceTy<'tcx, Self::PointerTag>,
         target: Option<mir::BasicBlock>,
@@ -179,7 +181,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn call_extra_fn(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         fn_val: Self::ExtraFnVal,
-        abi: Abi,
+        abi: CallAbi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         destination: &PlaceTy<'tcx, Self::PointerTag>,
         target: Option<mir::BasicBlock>,
@@ -223,11 +225,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
     #[inline]
-    fn access_local(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+    fn access_local<'a>(
+        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
         local: mir::Local,
-    ) -> InterpResult<'tcx, Operand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a Operand<Self::PointerTag>>
+    where
+        'tcx: 'mir,
+    {
         frame.locals[local].access()
     }
 
@@ -239,7 +243,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: mir::Local,
-    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
+    ) -> InterpResult<'tcx, &'a mut Operand<Self::PointerTag>>
     where
         'tcx: 'mir,
     {
@@ -415,12 +419,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
     }
 
     /// Called immediately after a stack frame got popped, but before jumping back to the caller.
+    /// The `locals` have already been destroyed!
     fn after_stack_pop(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _frame: Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
-        _unwinding: bool,
+        unwinding: bool,
     ) -> InterpResult<'tcx, StackPopJump> {
         // By default, we do not support unwinding from panics
+        assert!(!unwinding);
         Ok(StackPopJump::Normal)
     }
 }
@@ -469,10 +475,15 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     }
 
     #[inline(always)]
+    fn checked_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
+        true
+    }
+
+    #[inline(always)]
     fn call_extra_fn(
         _ecx: &mut InterpCx<$mir, $tcx, Self>,
         fn_val: !,
-        _abi: Abi,
+        _abi: CallAbi,
         _args: &[OpTy<$tcx>],
         _destination: &PlaceTy<$tcx, Self::PointerTag>,
         _target: Option<mir::BasicBlock>,
@@ -513,7 +524,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         _ecx: &InterpCx<$mir, $tcx, Self>,
         addr: u64,
     ) -> Pointer<Option<AllocId>> {
-        Pointer::new(None, Size::from_bytes(addr))
+        Pointer::from_addr(addr)
     }
 
     #[inline(always)]
@@ -523,7 +534,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     ) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
         // Allow these casts, but make the pointer not dereferenceable.
         // (I.e., they behave like transmutation.)
-        Ok(Pointer::new(None, Size::from_bytes(addr)))
+        Ok(Pointer::from_addr(addr))
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index d5e68dbd5b7..509fe576893 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx> {
         let (alloc_id, offset, tag) = self.ptr_get_alloc_id(ptr)?;
-        trace!("deallocating: {}", alloc_id);
+        trace!("deallocating: {alloc_id:?}");
 
         if offset.bytes() != 0 {
             throw_ub_format!(
@@ -289,10 +289,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Deallocating global memory -- always an error
             return Err(match self.tcx.get_global_alloc(alloc_id) {
                 Some(GlobalAlloc::Function(..)) => {
-                    err_ub_format!("deallocating {}, which is a function", alloc_id)
+                    err_ub_format!("deallocating {alloc_id:?}, which is a function")
                 }
                 Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => {
-                    err_ub_format!("deallocating {}, which is static memory", alloc_id)
+                    err_ub_format!("deallocating {alloc_id:?}, which is static memory")
                 }
                 None => err_ub!(PointerUseAfterFree(alloc_id)),
             }
@@ -302,21 +302,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         debug!(?alloc);
 
         if alloc.mutability == Mutability::Not {
-            throw_ub_format!("deallocating immutable allocation {}", alloc_id);
+            throw_ub_format!("deallocating immutable allocation {alloc_id:?}");
         }
         if alloc_kind != kind {
             throw_ub_format!(
-                "deallocating {}, which is {} memory, using {} deallocation operation",
-                alloc_id,
-                alloc_kind,
-                kind
+                "deallocating {alloc_id:?}, which is {alloc_kind} memory, using {kind} deallocation operation"
             );
         }
         if let Some((size, align)) = old_size_and_align {
             if size != alloc.size() || align != alloc.align {
                 throw_ub_format!(
-                    "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}",
-                    alloc_id,
+                    "incorrect layout on deallocation: {alloc_id:?} has size {} and alignment {}, but gave size {} and alignment {}",
                     alloc.size().bytes(),
                     alloc.align.bytes(),
                     size.bytes(),
@@ -815,7 +811,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
                 continue;
             }
 
-            write!(fmt, "{}", id)?;
+            write!(fmt, "{id:?}")?;
             match self.ecx.memory.alloc_map.get(id) {
                 Some(&(kind, ref alloc)) => {
                     // normal alloc
@@ -859,25 +855,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
 
 /// Reading and writing.
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
+    /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn write_scalar(
         &mut self,
         range: AllocRange,
         val: ScalarMaybeUninit<Tag>,
     ) -> InterpResult<'tcx> {
         let range = self.range.subrange(range);
-        debug!(
-            "write_scalar in {} at {:#x}, size {}: {:?}",
-            self.alloc_id,
-            range.start.bytes(),
-            range.size.bytes(),
-            val
-        );
+        debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id);
         Ok(self
             .alloc
             .write_scalar(&self.tcx, range, val)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
 
+    /// `offset` is relative to this allocation reference, not the base of the allocation.
     pub fn write_ptr_sized(
         &mut self,
         offset: Size,
@@ -896,6 +888,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
 }
 
 impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
+    /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn read_scalar(
         &self,
         range: AllocRange,
@@ -906,24 +899,16 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
             .alloc
             .read_scalar(&self.tcx, range, read_provenance)
             .map_err(|e| e.to_interp_error(self.alloc_id))?;
-        debug!(
-            "read_scalar in {} at {:#x}, size {}: {:?}",
-            self.alloc_id,
-            range.start.bytes(),
-            range.size.bytes(),
-            res
-        );
+        debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id);
         Ok(res)
     }
 
-    pub fn read_integer(
-        &self,
-        offset: Size,
-        size: Size,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
-        self.read_scalar(alloc_range(offset, size), /*read_provenance*/ false)
+    /// `range` is relative to this allocation reference, not the base of the allocation.
+    pub fn read_integer(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        self.read_scalar(range, /*read_provenance*/ false)
     }
 
+    /// `offset` is relative to this allocation reference, not the base of the allocation.
     pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
         self.read_scalar(
             alloc_range(offset, self.tcx.data_layout().pointer_size),
@@ -931,6 +916,7 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
         )
     }
 
+    /// `range` is relative to this allocation reference, not the base of the allocation.
     pub fn check_bytes(
         &self,
         range: AllocRange,
@@ -942,6 +928,11 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
             .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit, allow_ptr)
             .map_err(|e| e.to_interp_error(self.alloc_id))?)
     }
+
+    /// Returns whether the allocation has relocations for the entire range of the `AllocRef`.
+    pub(crate) fn has_relocations(&self) -> bool {
+        self.alloc.has_relocations(&self.tcx, self.range)
+    }
 }
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index e7a08e05275..d11ae7b4925 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -10,11 +10,11 @@ use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Printer};
 use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
 use rustc_middle::{mir, ty};
-use rustc_target::abi::{self, Abi, HasDataLayout, Size, TagEncoding};
+use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 use super::{
-    alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId,
+    alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId,
     InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer,
     PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit,
 };
@@ -28,8 +28,15 @@ use super::{
 /// defined on `Immediate`, and do not have to work with a `Place`.
 #[derive(Copy, Clone, PartialEq, Eq, HashStable, Hash, Debug)]
 pub enum Immediate<Tag: Provenance = AllocId> {
+    /// A single scalar value (must have *initialized* `Scalar` ABI).
+    /// FIXME: we also currently often use this for ZST.
+    /// `ScalarMaybeUninit` should reject ZST, and we should use `Uninit` for them instead.
     Scalar(ScalarMaybeUninit<Tag>),
+    /// A pair of two scalar value (must have `ScalarPair` ABI where both fields are
+    /// `Scalar::Initialized`).
     ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>),
+    /// A value of fully uninitialized memory. Can have and size and layout.
+    Uninit,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -71,27 +78,33 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
     }
 
     #[inline]
+    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
     pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
         match self {
             Immediate::Scalar(val) => val,
             Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
+            Immediate::Uninit => ScalarMaybeUninit::Uninit,
         }
     }
 
     #[inline]
+    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
     pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
         self.to_scalar_or_uninit().check_init()
     }
 
     #[inline]
+    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
     pub fn to_scalar_or_uninit_pair(self) -> (ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>) {
         match self {
             Immediate::ScalarPair(val1, val2) => (val1, val2),
             Immediate::Scalar(..) => bug!("Got a scalar where a scalar pair was expected"),
+            Immediate::Uninit => (ScalarMaybeUninit::Uninit, ScalarMaybeUninit::Uninit),
         }
     }
 
     #[inline]
+    #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980)
     pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
         let (val1, val2) = self.to_scalar_or_uninit_pair();
         Ok((val1.check_init()?, val2.check_init()?))
@@ -149,7 +162,10 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'_, Tag> {
                 }
                 Immediate::ScalarPair(a, b) => {
                     // FIXME(oli-obk): at least print tuples and slices nicely
-                    write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty,)
+                    write!(f, "({:x}, {:x}): {}", a, b, self.layout.ty)
+                }
+                Immediate::Uninit => {
+                    write!(f, "uninit: {}", self.layout.ty)
                 }
             }
         })
@@ -177,10 +193,18 @@ pub enum Operand<Tag: Provenance = AllocId> {
 pub struct OpTy<'tcx, Tag: Provenance = AllocId> {
     op: Operand<Tag>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
+    /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
+    /// it needs to have a different alignment than the field type would usually have.
+    /// So we represent this here with a separate field that "overwrites" `layout.align`.
+    /// This means `layout.align` should never be used for an `OpTy`!
+    /// `None` means "alignment does not matter since this is a by-value operand"
+    /// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`.
+    /// Also CTFE ignores alignment anyway, so this is for Miri only.
+    pub align: Option<Align>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(OpTy<'_>, 80);
+rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
 
 impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> {
     type Target = Operand<Tag>;
@@ -193,28 +217,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for OpTy<'tcx, Tag> {
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
-        OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout }
+        OpTy { op: Operand::Indirect(*mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
 impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
-        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
 impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
-        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout, align: Some(mplace.align) }
     }
 }
 
 impl<'tcx, Tag: Provenance> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Tag>) -> Self {
-        OpTy { op: Operand::Immediate(val.imm), layout: val.layout }
+        OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
     }
 }
 
@@ -273,8 +297,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         let Some(alloc) = self.get_place_alloc(mplace)? else {
             return Ok(Some(ImmTy {
-                // zero-sized type
-                imm: Scalar::ZST.into(),
+                // zero-sized type can be left uninit
+                imm: Immediate::Uninit,
                 layout: mplace.layout,
             }));
         };
@@ -298,9 +322,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             s.is_ptr() || (number_may_have_provenance && size == self.pointer_size())
         };
         if let Some(s) = scalar_layout {
-            //FIXME(#96185): let size = s.size(self);
-            //FIXME(#96185): assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
-            let size = mplace.layout.size; //FIXME(#96185): remove this line
+            let size = s.size(self);
+            assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
             let scalar =
                 alloc.read_scalar(alloc_range(Size::ZERO, size), read_provenance(s, size))?;
             return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }));
@@ -390,7 +413,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.scalar_to_ptr(self.read_scalar(op)?.check_init()?)
     }
 
-    // Turn the wide MPlace into a string (must already be dereferenced!)
+    /// Turn the wide MPlace into a string (must already be dereferenced!)
     pub fn read_str(&self, mplace: &MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.read_bytes_ptr(mplace.ptr, Size::from_bytes(len))?;
@@ -418,8 +441,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // This makes several assumptions about what layouts we will encounter; we match what
         // codegen does as good as we can (see `extract_field` in `rustc_codegen_ssa/src/mir/operand.rs`).
         let field_val: Immediate<_> = match (*base, base.layout.abi) {
-            // the field contains no information
-            _ if field_layout.is_zst() => Scalar::ZST.into(),
+            // the field contains no information, can be left uninit
+            _ if field_layout.is_zst() => Immediate::Uninit,
             // the field covers the entire type
             _ if field_layout.size == base.layout.size => {
                 assert!(match (base.layout.abi, field_layout.abi) {
@@ -450,7 +473,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ),
         };
 
-        Ok(OpTy { op: Operand::Immediate(field_val), layout: field_layout })
+        Ok(OpTy { op: Operand::Immediate(field_val), layout: field_layout, align: None })
     }
 
     pub fn operand_index(
@@ -521,21 +544,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Will not access memory, instead an indirect `Operand` is returned.
     ///
     /// This is public because it is used by [priroda](https://github.com/oli-obk/priroda) to get an
-    /// OpTy from a local
-    pub fn access_local(
+    /// OpTy from a local.
+    pub fn local_to_op(
         &self,
-        frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
+        frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
         local: mir::Local,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let layout = self.layout_of_local(frame, local, layout)?;
         let op = if layout.is_zst() {
-            // Do not read from ZST, they might not be initialized
-            Operand::Immediate(Scalar::ZST.into())
+            // Bypass `access_local` (helps in ConstProp)
+            Operand::Immediate(Immediate::Uninit)
         } else {
-            M::access_local(&self, frame, local)?
+            *M::access_local(frame, local)?
         };
-        Ok(OpTy { op, layout })
+        Ok(OpTy { op, layout, align: Some(layout.align.abi) })
     }
 
     /// Every place can be read from, so we can turn them into an operand.
@@ -549,10 +572,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let op = match **place {
             Place::Ptr(mplace) => Operand::Indirect(mplace),
             Place::Local { frame, local } => {
-                *self.access_local(&self.stack()[frame], local, None)?
+                *self.local_to_op(&self.stack()[frame], local, None)?
             }
         };
-        Ok(OpTy { op, layout: place.layout })
+        Ok(OpTy { op, layout: place.layout, align: Some(place.align) })
     }
 
     /// Evaluate a place with the goal of reading from it.  This lets us sometimes
@@ -566,7 +589,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // here is not the entire place.
         let layout = if place.projection.is_empty() { layout } else { None };
 
-        let base_op = self.access_local(self.frame(), place.local, layout)?;
+        let base_op = self.local_to_op(self.frame(), place.local, layout)?;
 
         let op = place
             .projection
@@ -603,11 +626,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Constant(ref constant) => {
                 let val =
                     self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
+
                 // This can still fail:
                 // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
                 //   checked yet.
                 // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
-
                 self.mir_const_to_op(&val, layout)?
             }
         };
@@ -683,9 +706,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen.
                 let ptr = self.global_base_pointer(Pointer::new(id, offset))?;
-                Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi))
+                Operand::Indirect(MemPlace::from_ptr(ptr.into()))
             }
             ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
+            ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit),
             ConstValue::Slice { data, start, end } => {
                 // We rely on mutability being set correctly in `data` to prevent writes
                 // where none should happen.
@@ -700,7 +724,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 ))
             }
         };
-        Ok(OpTy { op, layout })
+        Ok(OpTy { op, layout, align: Some(layout.align.abi) })
     }
 
     /// Read discriminant, return the runtime value as well as the variant index.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 85ee88e9e47..f0c113376ea 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -5,15 +5,20 @@ use rustc_middle::mir;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_target::abi::Abi;
 
 use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Applies the binary operation `op` to the two operands and writes a tuple of the result
     /// and a boolean signifying the potential overflow to the destination.
+    ///
+    /// `force_overflow_checks` indicates whether overflow checks should be done even when
+    /// `tcx.sess.overflow_checks()` is `false`.
     pub fn binop_with_overflow(
         &mut self,
         op: mir::BinOp,
+        force_overflow_checks: bool,
         left: &ImmTy<'tcx, M::PointerTag>,
         right: &ImmTy<'tcx, M::PointerTag>,
         dest: &PlaceTy<'tcx, M::PointerTag>,
@@ -25,8 +30,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             "type mismatch for result of {:?}",
             op,
         );
-        let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
-        self.write_immediate(val, dest)
+        // As per https://github.com/rust-lang/rust/pull/98738, we always return `false` in the 2nd
+        // component when overflow checking is disabled.
+        let overflowed =
+            overflowed && (force_overflow_checks || M::checked_binop_checks_overflow(self));
+        // Write the result to `dest`.
+        if let Abi::ScalarPair(..) = dest.layout.abi {
+            // We can use the optimized path and avoid `place_field` (which might do
+            // `force_allocation`).
+            let pair = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
+            self.write_immediate(pair, dest)?;
+        } else {
+            assert!(self.tcx.sess.opts.debugging_opts.randomize_layout);
+            // With randomized layout, `(int, bool)` might cease to be a `ScalarPair`, so we have to
+            // do a component-wise write here. This code path is slower than the above because
+            // `place_field` will have to `force_allocate` locals here.
+            let val_field = self.place_field(&dest, 0)?;
+            self.write_scalar(val, &val_field)?;
+            let overflowed_field = self.place_field(&dest, 1)?;
+            self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?;
+        }
+        Ok(())
     }
 
     /// Applies the binary operation `op` to the arguments and writes the result to the
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 337fcd28c66..57ecad07b42 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -10,13 +10,14 @@ use rustc_macros::HashStable;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
-use rustc_target::abi::{HasDataLayout, Size, VariantIdx, Variants};
+use rustc_target::abi::{
+    Abi, Align, FieldsShape, HasDataLayout, Size, TagEncoding, VariantIdx, Variants,
+};
 
 use super::{
     alloc_range, mir_assign_valid_types, AllocId, AllocRef, AllocRefMut, CheckInAllocMsg,
-    ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy,
-    Operand, Pointer, Provenance, Scalar, ScalarMaybeUninit,
+    ConstAlloc, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, OpTy, Operand,
+    Pointer, Provenance, Scalar, ScalarMaybeUninit,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
@@ -57,7 +58,6 @@ impl<Tag: Provenance> MemPlaceMeta<Tag> {
 pub struct MemPlace<Tag: Provenance = AllocId> {
     /// The pointer can be a pure integer, with the `None` tag.
     pub ptr: Pointer<Option<Tag>>,
-    pub align: Align,
     /// Metadata for unsized places. Interpretation is up to the type.
     /// Must not be present for sized types, but can be missing for unsized types
     /// (e.g., `extern type`).
@@ -65,7 +65,7 @@ pub struct MemPlace<Tag: Provenance = AllocId> {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlace, 48);
+rustc_data_structures::static_assert_size!(MemPlace, 40);
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable, Debug)]
 pub enum Place<Tag: Provenance = AllocId> {
@@ -78,12 +78,17 @@ pub enum Place<Tag: Provenance = AllocId> {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Place, 56);
+rustc_data_structures::static_assert_size!(Place, 48);
 
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceTy<'tcx, Tag: Provenance = AllocId> {
     place: Place<Tag>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
+    /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
+    /// it needs to have a different alignment than the field type would usually have.
+    /// So we represent this here with a separate field that "overwrites" `layout.align`.
+    /// This means `layout.align` should never be used for a `PlaceTy`!
+    pub align: Align,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -102,6 +107,11 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for PlaceTy<'tcx, Tag> {
 pub struct MPlaceTy<'tcx, Tag: Provenance = AllocId> {
     mplace: MemPlace<Tag>,
     pub layout: TyAndLayout<'tcx>,
+    /// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
+    /// it needs to have a different alignment than the field type would usually have.
+    /// So we represent this here with a separate field that "overwrites" `layout.align`.
+    /// This means `layout.align` should never be used for a `MPlaceTy`!
+    pub align: Align,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -118,28 +128,28 @@ impl<'tcx, Tag: Provenance> std::ops::Deref for MPlaceTy<'tcx, Tag> {
 impl<'tcx, Tag: Provenance> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
-        PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout }
+        PlaceTy { place: Place::Ptr(*mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
 impl<'tcx, Tag: Provenance> From<&'_ MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
-        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
+        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
 impl<'tcx, Tag: Provenance> From<&'_ mut MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
     #[inline(always)]
     fn from(mplace: &mut MPlaceTy<'tcx, Tag>) -> Self {
-        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout }
+        PlaceTy { place: Place::Ptr(**mplace), layout: mplace.layout, align: mplace.align }
     }
 }
 
 impl<Tag: Provenance> MemPlace<Tag> {
     #[inline(always)]
-    pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self {
-        MemPlace { ptr, align, meta: MemPlaceMeta::None }
+    pub fn from_ptr(ptr: Pointer<Option<Tag>>) -> Self {
+        MemPlace { ptr, meta: MemPlaceMeta::None }
     }
 
     /// Adjust the provenance of the main pointer (metadata is unaffected).
@@ -170,11 +180,19 @@ impl<Tag: Provenance> MemPlace<Tag> {
         meta: MemPlaceMeta<Tag>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
-        Ok(MemPlace {
-            ptr: self.ptr.offset(offset, cx)?,
-            align: self.align.restrict_for_offset(offset),
-            meta,
-        })
+        Ok(MemPlace { ptr: self.ptr.offset(offset, cx)?, meta })
+    }
+}
+
+impl<Tag: Provenance> Place<Tag> {
+    /// Asserts that this points to some local variable.
+    /// Returns the frame idx and the variable idx.
+    #[inline]
+    pub fn assert_local(&self) -> (usize, mir::Local) {
+        match self {
+            Place::Local { frame, local } => (*frame, *local),
+            _ => bug!("assert_local: expected Place::Local, got {:?}", self),
+        }
     }
 }
 
@@ -183,9 +201,9 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
     #[inline]
     pub fn dangling(layout: TyAndLayout<'tcx>) -> Self {
         let align = layout.align.abi;
-        let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address
+        let ptr = Pointer::from_addr(align.bytes()); // no provenance, absolute address
         // `Poison` this to make sure that the pointer value `ptr` is never observable by the program.
-        MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout }
+        MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::Poison }, layout, align }
     }
 
     #[inline]
@@ -196,12 +214,16 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
         layout: TyAndLayout<'tcx>,
         cx: &impl HasDataLayout,
     ) -> InterpResult<'tcx, Self> {
-        Ok(MPlaceTy { mplace: self.mplace.offset(offset, meta, cx)?, layout })
+        Ok(MPlaceTy {
+            mplace: self.mplace.offset(offset, meta, cx)?,
+            align: self.align.restrict_for_offset(offset),
+            layout,
+        })
     }
 
     #[inline]
     pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self {
-        MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
+        MPlaceTy { mplace: MemPlace::from_ptr(ptr), layout, align: layout.align.abi }
     }
 
     #[inline]
@@ -210,10 +232,10 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
         layout: TyAndLayout<'tcx>,
         meta: MemPlaceMeta<Tag>,
     ) -> Self {
-        let mut mplace = MemPlace::from_ptr(ptr, layout.align.abi);
+        let mut mplace = MemPlace::from_ptr(ptr);
         mplace.meta = meta;
 
-        MPlaceTy { mplace, layout }
+        MPlaceTy { mplace, layout, align: layout.align.abi }
     }
 
     #[inline]
@@ -250,7 +272,9 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
     /// read from the resulting mplace, not to get its address back.
     pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
         match **self {
-            Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
+            Operand::Indirect(mplace) => {
+                Ok(MPlaceTy { mplace, layout: self.layout, align: self.align.unwrap() })
+            }
             Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout)),
             Operand::Immediate(imm) => Err(ImmTy::from_immediate(imm, self.layout)),
         }
@@ -264,20 +288,19 @@ impl<'tcx, Tag: Provenance> OpTy<'tcx, Tag> {
     }
 }
 
-impl<Tag: Provenance> Place<Tag> {
+impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
+    /// A place is either an mplace or some local.
     #[inline]
-    pub fn assert_mem_place(self) -> MemPlace<Tag> {
-        match self {
-            Place::Ptr(mplace) => mplace,
-            _ => bug!("assert_mem_place: expected Place::Ptr, got {:?}", self),
+    pub fn try_as_mplace(&self) -> Result<MPlaceTy<'tcx, Tag>, (usize, mir::Local)> {
+        match **self {
+            Place::Ptr(mplace) => Ok(MPlaceTy { mplace, layout: self.layout, align: self.align }),
+            Place::Local { frame, local } => Err((frame, local)),
         }
     }
-}
 
-impl<'tcx, Tag: Provenance> PlaceTy<'tcx, Tag> {
     #[inline]
-    pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
-        MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout }
+    pub fn assert_mem_place(&self) -> MPlaceTy<'tcx, Tag> {
+        self.try_as_mplace().unwrap()
     }
 }
 
@@ -304,18 +327,13 @@ where
         let (ptr, meta) = match **val {
             Immediate::Scalar(ptr) => (ptr, MemPlaceMeta::None),
             Immediate::ScalarPair(ptr, meta) => (ptr, MemPlaceMeta::Meta(meta.check_init()?)),
+            Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
         };
 
-        let mplace = MemPlace {
-            ptr: self.scalar_to_ptr(ptr.check_init()?)?,
-            // We could use the run-time alignment here. For now, we do not, because
-            // the point of tracking the alignment here is to make sure that the *static*
-            // alignment information emitted with the loads is correct. The run-time
-            // alignment can only be more restrictive.
-            align: layout.align.abi,
-            meta,
-        };
-        Ok(MPlaceTy { mplace, layout })
+        let mplace = MemPlace { ptr: self.scalar_to_ptr(ptr.check_init()?)?, meta };
+        // When deref'ing a pointer, the *static* alignment given by the type is what matters.
+        let align = layout.align.abi;
+        Ok(MPlaceTy { mplace, layout, align })
     }
 
     /// Take an operand, representing a pointer, and dereference it to a place -- that
@@ -368,7 +386,7 @@ where
         let (size, align) = self
             .size_and_align_of_mplace(&mplace)?
             .unwrap_or((mplace.layout.size, mplace.layout.align.abi));
-        assert!(mplace.mplace.align <= align, "dynamic alignment less strict than static one?");
+        assert!(mplace.align <= align, "dynamic alignment less strict than static one?");
         let align = M::enforce_alignment(self).then_some(align);
         self.check_ptr_access_align(mplace.ptr, size, align.unwrap_or(Align::ONE), msg)?;
         Ok(())
@@ -533,7 +551,7 @@ where
 
             Index(local) => {
                 let layout = self.layout_of(self.tcx.types.usize)?;
-                let n = self.access_local(self.frame(), local, Some(layout))?;
+                let n = self.local_to_op(self.frame(), local, Some(layout))?;
                 let n = self.read_scalar(&n)?;
                 let n = n.to_machine_usize(self)?;
                 self.mplace_index(base, n)?
@@ -608,11 +626,9 @@ where
         variant: VariantIdx,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // Downcast just changes the layout
-        Ok(match base.place {
-            Place::Ptr(mplace) => {
-                self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into()
-            }
-            Place::Local { .. } => {
+        Ok(match base.try_as_mplace() {
+            Ok(mplace) => self.mplace_downcast(&mplace, variant)?.into(),
+            Err(..) => {
                 let layout = base.layout.for_variant(self, variant);
                 PlaceTy { layout, ..*base }
             }
@@ -649,6 +665,16 @@ where
         self.mplace_to_simd(&mplace)
     }
 
+    pub fn local_to_place(
+        &self,
+        frame: usize,
+        local: mir::Local,
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+        let layout = self.layout_of_local(&self.stack()[frame], local, None)?;
+        let place = Place::Local { frame, local };
+        Ok(PlaceTy { place, layout, align: layout.align.abi })
+    }
+
     /// Computes a place. You should only use this if you intend to write into this
     /// place; for reading, a more efficient alternative is `eval_place_to_op`.
     #[instrument(skip(self), level = "debug")]
@@ -656,11 +682,7 @@ where
         &mut self,
         place: mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
-        let mut place_ty = PlaceTy {
-            // This works even for dead/uninitialized locals; we check further when writing
-            place: Place::Local { frame: self.frame_idx(), local: place.local },
-            layout: self.layout_of_local(self.frame(), place.local, None)?,
-        };
+        let mut place_ty = self.local_to_place(self.frame_idx(), place.local)?;
 
         for elem in place.projection.iter() {
             place_ty = self.place_projection(&place_ty, &elem)?
@@ -668,14 +690,19 @@ where
 
         trace!("{:?}", self.dump_place(place_ty.place));
         // Sanity-check the type we ended up with.
-        debug_assert!(mir_assign_valid_types(
-            *self.tcx,
-            self.param_env,
-            self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
-                place.ty(&self.frame().body.local_decls, *self.tcx).ty
-            )?)?,
-            place_ty.layout,
-        ));
+        debug_assert!(
+            mir_assign_valid_types(
+                *self.tcx,
+                self.param_env,
+                self.layout_of(self.subst_from_current_frame_and_normalize_erasing_regions(
+                    place.ty(&self.frame().body.local_decls, *self.tcx).ty
+                )?)?,
+                place_ty.layout,
+            ),
+            "eval_place of a MIR place with type {:?} produced an interpret place with type {:?}",
+            place.ty(&self.frame().body.local_decls, *self.tcx).ty,
+            place_ty.layout.ty,
+        );
         Ok(place_ty)
     }
 
@@ -733,32 +760,33 @@ where
         let mplace = match dest.place {
             Place::Local { frame, local } => {
                 match M::access_local_mut(self, frame, local)? {
-                    Ok(local) => {
+                    Operand::Immediate(local) => {
                         // Local can be updated in-place.
-                        *local = LocalValue::Live(Operand::Immediate(src));
+                        *local = src;
                         return Ok(());
                     }
-                    Err(mplace) => {
+                    Operand::Indirect(mplace) => {
                         // The local is in memory, go on below.
-                        mplace
+                        *mplace
                     }
                 }
             }
             Place::Ptr(mplace) => mplace, // already referring to memory
         };
-        let dest = MPlaceTy { mplace, layout: dest.layout };
 
         // This is already in memory, write there.
-        self.write_immediate_to_mplace_no_validate(src, &dest)
+        self.write_immediate_to_mplace_no_validate(src, dest.layout, dest.align, mplace)
     }
 
     /// Write an immediate to memory.
     /// If you use this you are responsible for validating that things got copied at the
-    /// right type.
+    /// right layout.
     fn write_immediate_to_mplace_no_validate(
         &mut self,
         value: Immediate<M::PointerTag>,
-        dest: &MPlaceTy<'tcx, M::PointerTag>,
+        layout: TyAndLayout<'tcx>,
+        align: Align,
+        dest: MemPlace<M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here
@@ -766,31 +794,30 @@ where
         // wrong type.
 
         let tcx = *self.tcx;
-        let Some(mut alloc) = self.get_place_alloc_mut(dest)? else {
+        let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout, align })? else {
             // zero-sized access
             return Ok(());
         };
 
         match value {
             Immediate::Scalar(scalar) => {
-                let Abi::Scalar(s) = dest.layout.abi else { span_bug!(
+                let Abi::Scalar(s) = layout.abi else { span_bug!(
                         self.cur_span(),
-                        "write_immediate_to_mplace: invalid Scalar layout: {:#?}",
-                        dest.layout
+                        "write_immediate_to_mplace: invalid Scalar layout: {layout:#?}",
                     )
                 };
                 let size = s.size(&tcx);
-                //FIXME(#96185): assert_eq!(dest.layout.size, size, "abi::Scalar size does not match layout size");
+                assert_eq!(size, layout.size, "abi::Scalar size does not match layout size");
                 alloc.write_scalar(alloc_range(Size::ZERO, size), scalar)
             }
             Immediate::ScalarPair(a_val, b_val) => {
                 // We checked `ptr_align` above, so all fields will have the alignment they need.
                 // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`,
                 // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
-                let Abi::ScalarPair(a, b) = dest.layout.abi else { span_bug!(
+                let Abi::ScalarPair(a, b) = layout.abi else { span_bug!(
                         self.cur_span(),
                         "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
-                        dest.layout
+                        layout
                     )
                 };
                 let (a_size, b_size) = (a.size(&tcx), b.size(&tcx));
@@ -804,33 +831,22 @@ where
                 alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?;
                 alloc.write_scalar(alloc_range(b_offset, b_size), b_val)
             }
+            Immediate::Uninit => alloc.write_uninit(),
         }
     }
 
     pub fn write_uninit(&mut self, dest: &PlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
-        let mplace = match dest.place {
-            Place::Ptr(mplace) => MPlaceTy { mplace, layout: dest.layout },
-            Place::Local { frame, local } => {
+        let mplace = match dest.try_as_mplace() {
+            Ok(mplace) => mplace,
+            Err((frame, local)) => {
                 match M::access_local_mut(self, frame, local)? {
-                    Ok(local) => match dest.layout.abi {
-                        Abi::Scalar(_) => {
-                            *local = LocalValue::Live(Operand::Immediate(Immediate::Scalar(
-                                ScalarMaybeUninit::Uninit,
-                            )));
-                            return Ok(());
-                        }
-                        Abi::ScalarPair(..) => {
-                            *local = LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(
-                                ScalarMaybeUninit::Uninit,
-                                ScalarMaybeUninit::Uninit,
-                            )));
-                            return Ok(());
-                        }
-                        _ => self.force_allocation(dest)?,
-                    },
-                    Err(mplace) => {
+                    Operand::Immediate(local) => {
+                        *local = Immediate::Uninit;
+                        return Ok(());
+                    }
+                    Operand::Indirect(mplace) => {
                         // The local is in memory, go on below.
-                        MPlaceTy { mplace, layout: dest.layout }
+                        MPlaceTy { mplace: *mplace, layout: dest.layout, align: dest.align }
                     }
                 }
             }
@@ -843,16 +859,17 @@ where
         Ok(())
     }
 
-    /// Copies the data from an operand to a place. This does not support transmuting!
-    /// Use `copy_op_transmute` if the layouts could disagree.
+    /// Copies the data from an operand to a place.
+    /// `allow_transmute` indicates whether the layouts may disagree.
     #[inline(always)]
     #[instrument(skip(self), level = "debug")]
     pub fn copy_op(
         &mut self,
         src: &OpTy<'tcx, M::PointerTag>,
         dest: &PlaceTy<'tcx, M::PointerTag>,
+        allow_transmute: bool,
     ) -> InterpResult<'tcx> {
-        self.copy_op_no_validate(src, dest)?;
+        self.copy_op_no_validate(src, dest, allow_transmute)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
@@ -862,8 +879,8 @@ where
         Ok(())
     }
 
-    /// Copies the data from an operand to a place. This does not support transmuting!
-    /// Use `copy_op_transmute` if the layouts could disagree.
+    /// Copies the data from an operand to a place.
+    /// `allow_transmute` indicates whether the layouts may disagree.
     /// Also, if you use this you are responsible for validating that things get copied at the
     /// right type.
     #[instrument(skip(self), level = "debug")]
@@ -871,10 +888,13 @@ where
         &mut self,
         src: &OpTy<'tcx, M::PointerTag>,
         dest: &PlaceTy<'tcx, M::PointerTag>,
+        allow_transmute: bool,
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
-        if !mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
+        let layout_compat =
+            mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout);
+        if !allow_transmute && !layout_compat {
             span_bug!(
                 self.cur_span(),
                 "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
@@ -883,100 +903,68 @@ where
             );
         }
 
-        // Let us see if the layout is simple so we take a shortcut, avoid force_allocation.
+        // Let us see if the layout is simple so we take a shortcut,
+        // avoid force_allocation.
         let src = match self.read_immediate_raw(src, /*force*/ false)? {
             Ok(src_val) => {
                 assert!(!src.layout.is_unsized(), "cannot have unsized immediates");
+                assert!(
+                    !dest.layout.is_unsized(),
+                    "the src is sized, so the dest must also be sized"
+                );
+                assert_eq!(src.layout.size, dest.layout.size);
                 // Yay, we got a value that we can write directly.
-                return self.write_immediate_no_validate(*src_val, dest);
+                return if layout_compat {
+                    self.write_immediate_no_validate(*src_val, dest)
+                } else {
+                    // This is tricky. The problematic case is `ScalarPair`: the `src_val` was
+                    // loaded using the offsets defined by `src.layout`. When we put this back into
+                    // the destination, we have to use the same offsets! So (a) we make sure we
+                    // write back to memory, and (b) we use `dest` *with the source layout*.
+                    let dest_mem = self.force_allocation(dest)?;
+                    self.write_immediate_to_mplace_no_validate(
+                        *src_val,
+                        src.layout,
+                        dest_mem.align,
+                        *dest_mem,
+                    )
+                };
             }
             Err(mplace) => mplace,
         };
         // Slow path, this does not fit into an immediate. Just memcpy.
         trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty);
 
-        // This interprets `src.meta` with the `dest` local's layout, if an unsized local
-        // is being initialized!
-        let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?;
-        let size = size.unwrap_or_else(|| {
-            assert!(
-                !dest.layout.is_unsized(),
-                "Cannot copy into already initialized unsized place"
-            );
-            dest.layout.size
-        });
-        assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
-
-        self.mem_copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ false)
-    }
-
-    /// Copies the data from an operand to a place. The layouts may disagree, but they must
-    /// have the same size.
-    pub fn copy_op_transmute(
-        &mut self,
-        src: &OpTy<'tcx, M::PointerTag>,
-        dest: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx> {
-        if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
-            // Fast path: Just use normal `copy_op`
-            return self.copy_op(src, dest);
-        }
-        // We still require the sizes to match.
-        if src.layout.size != dest.layout.size {
-            span_bug!(
-                self.cur_span(),
-                "size-changing transmute, should have been caught by transmute checking: {:#?}\ndest: {:#?}",
-                src,
-                dest
-            );
-        }
-        // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want
-        // to avoid that here.
-        assert!(
-            !src.layout.is_unsized() && !dest.layout.is_unsized(),
-            "Cannot transmute unsized data"
-        );
-
-        // The hard case is `ScalarPair`.  `src` is already read from memory in this case,
-        // using `src.layout` to figure out which bytes to use for the 1st and 2nd field.
-        // We have to write them to `dest` at the offsets they were *read at*, which is
-        // not necessarily the same as the offsets in `dest.layout`!
-        // Hence we do the copy with the source layout on both sides.  We also make sure to write
-        // into memory, because if `dest` is a local we would not even have a way to write
-        // at the `src` offsets; the fact that we came from a different layout would
-        // just be lost.
-        let dest = self.force_allocation(dest)?;
-        self.copy_op_no_validate(
-            src,
-            &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
-        )?;
-
-        if M::enforce_validity(self) {
-            // Data got changed, better make sure it matches the type!
-            self.validate_operand(&dest.into())?;
+        let dest = self.force_allocation(&dest)?;
+        let Some((dest_size, _)) = self.size_and_align_of_mplace(&dest)? else {
+            span_bug!(self.cur_span(), "copy_op needs (dynamically) sized values")
+        };
+        if cfg!(debug_assertions) {
+            let src_size = self.size_and_align_of_mplace(&src)?.unwrap().0;
+            assert_eq!(src_size, dest_size, "Cannot copy differently-sized data");
+        } else {
+            // As a cheap approximation, we compare the fixed parts of the size.
+            assert_eq!(src.layout.size, dest.layout.size);
         }
 
-        Ok(())
+        self.mem_copy(
+            src.ptr, src.align, dest.ptr, dest.align, dest_size, /*nonoverlapping*/ false,
+        )
     }
 
     /// Ensures that a place is in memory, and returns where it is.
     /// If the place currently refers to a local that doesn't yet have a matching allocation,
     /// create such an allocation.
     /// This is essentially `force_to_memplace`.
-    ///
-    /// This supports unsized types and returns the computed size to avoid some
-    /// redundant computation when copying; use `force_allocation` for a simpler, sized-only
-    /// version.
     #[instrument(skip(self), level = "debug")]
-    pub fn force_allocation_maybe_sized(
+    pub fn force_allocation(
         &mut self,
         place: &PlaceTy<'tcx, M::PointerTag>,
-        meta: MemPlaceMeta<M::PointerTag>,
-    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
-        let (mplace, size) = match place.place {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        let mplace = match place.place {
             Place::Local { frame, local } => {
                 match M::access_local_mut(self, frame, local)? {
-                    Ok(&mut local_val) => {
+                    &mut Operand::Immediate(local_val) => {
                         // We need to make an allocation.
 
                         // We need the layout of the local.  We can NOT use the layout we got,
@@ -984,40 +972,34 @@ where
                         // that has different alignment than the outer field.
                         let local_layout =
                             self.layout_of_local(&self.stack()[frame], local, None)?;
-                        // We also need to support unsized types, and hence cannot use `allocate`.
-                        let (size, align) = self
-                            .size_and_align_of(&meta, &local_layout)?
-                            .expect("Cannot allocate for non-dyn-sized type");
-                        let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?;
-                        let mplace = MemPlace { ptr: ptr.into(), align, meta };
-                        if let LocalValue::Live(Operand::Immediate(value)) = local_val {
-                            // Preserve old value.
+                        if local_layout.is_unsized() {
+                            throw_unsup_format!("unsized locals are not supported");
+                        }
+                        let mplace = *self.allocate(local_layout, MemoryKind::Stack)?;
+                        if !matches!(local_val, Immediate::Uninit) {
+                            // Preserve old value. (As an optimization, we can skip this if it was uninit.)
                             // We don't have to validate as we can assume the local
                             // was already valid for its type.
-                            let mplace = MPlaceTy { mplace, layout: local_layout };
-                            self.write_immediate_to_mplace_no_validate(value, &mplace)?;
+                            self.write_immediate_to_mplace_no_validate(
+                                local_val,
+                                local_layout,
+                                local_layout.align.abi,
+                                mplace,
+                            )?;
                         }
                         // Now we can call `access_mut` again, asserting it goes well,
                         // and actually overwrite things.
-                        *M::access_local_mut(self, frame, local).unwrap().unwrap() =
-                            LocalValue::Live(Operand::Indirect(mplace));
-                        (mplace, Some(size))
+                        *M::access_local_mut(self, frame, local).unwrap() =
+                            Operand::Indirect(mplace);
+                        mplace
                     }
-                    Err(mplace) => (mplace, None), // this already was an indirect local
+                    &mut Operand::Indirect(mplace) => mplace, // this already was an indirect local
                 }
             }
-            Place::Ptr(mplace) => (mplace, None),
+            Place::Ptr(mplace) => mplace,
         };
         // Return with the original layout, so that the caller can go on
-        Ok((MPlaceTy { mplace, layout: place.layout }, size))
-    }
-
-    #[inline(always)]
-    pub fn force_allocation(
-        &mut self,
-        place: &PlaceTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
-        Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
+        Ok(MPlaceTy { mplace, layout: place.layout, align: place.align })
     }
 
     pub fn allocate(
@@ -1025,6 +1007,7 @@ where
         layout: TyAndLayout<'tcx>,
         kind: MemoryKind<M::MemoryKind>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+        assert!(!layout.is_unsized());
         let ptr = self.allocate_ptr(layout.size, layout.align.abi, kind)?;
         Ok(MPlaceTy::from_aligned_ptr(ptr.into(), layout))
     }
@@ -1038,15 +1021,14 @@ where
     ) -> MPlaceTy<'tcx, M::PointerTag> {
         let ptr = self.allocate_bytes_ptr(str.as_bytes(), Align::ONE, kind, mutbl);
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
-        let mplace =
-            MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
+        let mplace = MemPlace { ptr: ptr.into(), meta: MemPlaceMeta::Meta(meta) };
 
         let ty = self.tcx.mk_ref(
             self.tcx.lifetimes.re_static,
             ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
         );
         let layout = self.layout_of(ty).unwrap();
-        MPlaceTy { mplace, layout }
+        MPlaceTy { mplace, layout, align: layout.align.abi }
     }
 
     /// Writes the discriminant of the given variant.
@@ -1166,7 +1148,11 @@ where
             assert_eq!(align, layout.align.abi);
         }
 
-        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout };
+        let mplace = MPlaceTy {
+            mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace },
+            layout,
+            align: layout.align.abi,
+        };
         Ok((instance, mplace))
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 98f69456e49..240910c08b2 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -169,7 +169,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Use(ref operand) => {
                 // Avoid recomputing the layout
                 let op = self.eval_operand(operand, Some(dest.layout))?;
-                self.copy_op(&op, &dest)?;
+                self.copy_op(&op, &dest, /*allow_transmute*/ false)?;
             }
 
             BinaryOp(bin_op, box (ref left, ref right)) => {
@@ -185,7 +185,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                 let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
                 let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
-                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
+                self.binop_with_overflow(
+                    bin_op, /*force_overflow_checks*/ false, &left, &right, &dest,
+                )?;
             }
 
             UnaryOp(un_op, ref operand) => {
@@ -202,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 for (field_index, operand) in operands.iter().enumerate() {
                     let op = self.eval_operand(operand, None)?;
                     let field_dest = self.place_field(&dest, field_index)?;
-                    self.copy_op(&op, &field_dest)?;
+                    self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?;
                 }
             }
 
@@ -218,7 +220,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 } else {
                     // Write the src to the first element.
                     let first = self.mplace_field(&dest, 0)?;
-                    self.copy_op(&src, &first.into())?;
+                    self.copy_op(&src, &first.into(), /*allow_transmute*/ false)?;
 
                     // This is performance-sensitive code for big static/const arrays! So we
                     // avoid writing each operand individually and instead just make many copies
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 57d06b48ca4..515cc222dc6 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -12,8 +12,8 @@ use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMo
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Scalar,
-    StackPopCleanup, StackPopUnwind,
+    FnVal, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy, Operand,
+    PlaceTy, Scalar, StackPopCleanup, StackPopUnwind,
 };
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -185,11 +185,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // No question
                 return true;
             }
+            if caller_abi.layout.is_unsized() || callee_abi.layout.is_unsized() {
+                // No, no, no. We require the types to *exactly* match for unsized arguments. If
+                // these are somehow unsized "in a different way" (say, `dyn Trait` vs `[i32]`),
+                // then who knows what happens.
+                return false;
+            }
             if caller_abi.layout.size != callee_abi.layout.size
                 || caller_abi.layout.align.abi != callee_abi.layout.align.abi
             {
                 // This cannot go well...
-                // FIXME: What about unsized types?
                 return false;
             }
             // The rest *should* be okay, but we are extra conservative.
@@ -287,11 +292,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 caller_arg.layout.ty
             )
         }
+        // Special handling for unsized parameters.
+        if caller_arg.layout.is_unsized() {
+            // `check_argument_compat` ensures that both have the same type, so we know they will use the metadata the same way.
+            assert_eq!(caller_arg.layout.ty, callee_arg.layout.ty);
+            // We have to properly pre-allocate the memory for the callee.
+            // So let's tear down some wrappers.
+            // This all has to be in memory, there are no immediate unsized values.
+            let src = caller_arg.assert_mem_place();
+            // The destination cannot be one of these "spread args".
+            let (dest_frame, dest_local) = callee_arg.assert_local();
+            // We are just initializing things, so there can't be anything here yet.
+            assert!(matches!(
+                *self.local_to_op(&self.stack()[dest_frame], dest_local, None)?,
+                Operand::Immediate(Immediate::Uninit)
+            ));
+            // Allocate enough memory to hold `src`.
+            let Some((size, align)) = self.size_and_align_of_mplace(&src)? else {
+                span_bug!(self.cur_span(), "unsized fn arg with `extern` type tail should not be allowed")
+            };
+            let ptr = self.allocate_ptr(size, align, MemoryKind::Stack)?;
+            let dest_place =
+                MPlaceTy::from_aligned_ptr_with_meta(ptr.into(), callee_arg.layout, src.meta);
+            // Update the local to be that new place.
+            *M::access_local_mut(self, dest_frame, dest_local)? = Operand::Indirect(*dest_place);
+        }
         // We allow some transmutes here.
         // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This
         // is true for all `copy_op`, but there are a lot of special cases for argument passing
         // specifically.)
-        self.copy_op_transmute(&caller_arg, callee_arg)
+        self.copy_op(&caller_arg, callee_arg, /*allow_transmute*/ true)
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs
index 9c48f3e8337..22c23df7b1a 100644
--- a/compiler/rustc_const_eval/src/interpret/traits.rs
+++ b/compiler/rustc_const_eval/src/interpret/traits.rs
@@ -1,6 +1,6 @@
 use std::convert::TryFrom;
 
-use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic};
+use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
     COMMON_VTABLE_ENTRIES_SIZE,
@@ -102,18 +102,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )?
             .expect("cannot be a ZST");
         let size = vtable
-            .read_integer(
+            .read_integer(alloc_range(
                 pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
                 pointer_size,
-            )?
+            ))?
             .check_init()?;
         let size = size.to_machine_usize(self)?;
         let size = Size::from_bytes(size);
         let align = vtable
-            .read_integer(
+            .read_integer(alloc_range(
                 pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
                 pointer_size,
-            )?
+            ))?
             .check_init()?;
         let align = align.to_machine_usize(self)?;
         let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index b9866995e9f..2bc521d5bbe 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,5 +1,5 @@
 use rustc_middle::mir::interpret::InterpResult;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use std::convert::TryInto;
 use std::ops::ControlFlow;
 
@@ -10,7 +10,7 @@ use std::ops::ControlFlow;
 /// case these parameters are unused.
 pub(crate) fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
 where
-    T: TypeFoldable<'tcx>,
+    T: TypeVisitable<'tcx>,
 {
     debug!("ensure_monomorphic_enough: ty={:?}", ty);
     if !ty.needs_subst() {
@@ -44,22 +44,10 @@ where
                         let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
                         // Only recurse when generic parameters in fns, closures and generators
                         // are used and require substitution.
-                        match (is_used, subst.needs_subst()) {
-                            // Just in case there are closures or generators within this subst,
-                            // recurse.
-                            (true, true) => return subst.visit_with(self),
-                            // Confirm that polymorphization replaced the parameter with
-                            // `ty::Param`/`ty::ConstKind::Param`.
-                            (false, true) if cfg!(debug_assertions) => match subst.unpack() {
-                                ty::subst::GenericArgKind::Type(ty) => {
-                                    assert!(matches!(ty.kind(), ty::Param(_)))
-                                }
-                                ty::subst::GenericArgKind::Const(ct) => {
-                                    assert!(matches!(ct.kind(), ty::ConstKind::Param(_)))
-                                }
-                                ty::subst::GenericArgKind::Lifetime(..) => (),
-                            },
-                            _ => {}
+                        // Just in case there are closures or generators within this subst,
+                        // recurse.
+                        if is_used && subst.needs_subst() {
+                            return subst.visit_with(self);
                         }
                     }
                     ControlFlow::CONTINUE
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 905ab6cb578..08102585a7b 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -244,7 +244,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                         // for a generator).
                         let var_hir_id = captured_place.get_root_variable();
                         let node = self.ecx.tcx.hir().get(var_hir_id);
-                        if let hir::Node::Binding(pat) = node {
+                        if let hir::Node::Pat(pat) = node {
                             if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
                                 name = Some(ident.name);
                             }
@@ -427,7 +427,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             err_ub!(DanglingIntPointer(0, _)) =>
                 { "a null {kind}" },
             err_ub!(DanglingIntPointer(i, _)) =>
-                { "a dangling {kind} (address 0x{i:x} is unallocated)" },
+                { "a dangling {kind} (address {i:#x} is unallocated)" },
             err_ub!(PointerOutOfBounds { .. }) =>
                 { "a dangling {kind} (going beyond the bounds of its allocation)" },
             // This cannot happen during const-eval (because interning already detects
@@ -593,16 +593,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 self.check_safe_pointer(value, "reference")?;
                 Ok(true)
             }
-            ty::Adt(def, ..) if def.is_box() => {
-                let unique = self.ecx.operand_field(value, 0)?;
-                let nonnull = self.ecx.operand_field(&unique, 0)?;
-                let ptr = self.ecx.operand_field(&nonnull, 0)?;
-                self.check_safe_pointer(&ptr, "box")?;
-
-                // Check other fields of Box
-                self.walk_value(value)?;
-                Ok(true)
-            }
             ty::FnPtr(_sig) => {
                 let value = try_validation!(
                     self.ecx.read_scalar(value).and_then(|v| v.check_init()),
@@ -814,6 +804,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     }
 
     #[inline]
+    fn visit_box(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+        self.check_safe_pointer(op, "box")?;
+        Ok(())
+    }
+
+    #[inline]
     fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         trace!("visit_value: {:?}, {:?}", *op, op.layout);
 
@@ -821,8 +817,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         if self.try_visit_primitive(op)? {
             return Ok(());
         }
-        // Sanity check: `builtin_deref` does not know any pointers that are not primitive.
-        assert!(op.layout.ty.builtin_deref(true).is_none());
 
         // Special check preventing `UnsafeCell` in the inner part of constants
         if let Some(def) = op.layout.ty.ty_adt_def() {
@@ -947,7 +941,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                                 // element that byte belongs to so we can
                                 // provide an index.
                                 let i = usize::try_from(
-                                    access.uninit_offset.bytes() / layout.size.bytes(),
+                                    access.uninit.start.bytes() / layout.size.bytes(),
                                 )
                                 .unwrap();
                                 self.path.push(PathElem::ArrayElem(i));
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 2b77ed89893..ded4c6a557a 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -151,6 +151,14 @@ macro_rules! make_value_visitor {
             {
                 Ok(())
             }
+            /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into.
+            /// The type of `v` will be a raw pointer, but this is a field of `Box<T>` and the
+            /// pointee type is the actual `T`.
+            #[inline(always)]
+            fn visit_box(&mut self, _v: &Self::V) -> InterpResult<'tcx>
+            {
+                Ok(())
+            }
             /// Visits this value as an aggregate, you are getting an iterator yielding
             /// all the fields (still in an `InterpResult`, you have to do error handling yourself).
             /// Recurses into the fields.
@@ -221,6 +229,47 @@ macro_rules! make_value_visitor {
                     // Slices do not need special handling here: they have `Array` field
                     // placement with length 0, so we enter the `Array` case below which
                     // indirectly uses the metadata to determine the actual length.
+
+                    // However, `Box`... let's talk about `Box`.
+                    ty::Adt(def, ..) if def.is_box() => {
+                        // `Box` is a hybrid primitive-library-defined type that one the one hand is
+                        // a dereferenceable pointer, on the other hand has *basically arbitrary
+                        // user-defined layout* since the user controls the 'allocator' field. So it
+                        // cannot be treated like a normal pointer, since it does not fit into an
+                        // `Immediate`. Yeah, it is quite terrible. But many visitors want to do
+                        // something with "all boxed pointers", so we handle this mess for them.
+                        //
+                        // When we hit a `Box`, we do not do the usual `visit_aggregate`; instead,
+                        // we (a) call `visit_box` on the pointer value, and (b) recurse on the
+                        // allocator field. We also assert tons of things to ensure we do not miss
+                        // any other fields.
+
+                        // `Box` has two fields: the pointer we care about, and the allocator.
+                        assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields");
+                        let (unique_ptr, alloc) =
+                            (v.project_field(self.ecx(), 0)?, v.project_field(self.ecx(), 1)?);
+                        // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
+                        // (which means another 2 fields, the second of which is a `PhantomData`)
+                        assert_eq!(unique_ptr.layout().fields.count(), 2);
+                        let (nonnull_ptr, phantom) = (
+                            unique_ptr.project_field(self.ecx(), 0)?,
+                            unique_ptr.project_field(self.ecx(), 1)?,
+                        );
+                        assert!(
+                            phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
+                            "2nd field of `Unique` should be PhantomData but is {:?}",
+                            phantom.layout().ty,
+                        );
+                        // ... that contains a `NonNull`... (gladly, only a single field here)
+                        assert_eq!(nonnull_ptr.layout().fields.count(), 1);
+                        let raw_ptr = nonnull_ptr.project_field(self.ecx(), 0)?; // the actual raw ptr
+                        // ... whose only field finally is a raw ptr we can dereference.
+                        self.visit_box(&raw_ptr)?;
+
+                        // The second `Box` field is the allocator, which we recursively check for validity
+                        // like in regular structs.
+                        self.visit_field(v, 1, &alloc)?;
+                    }
                     _ => {},
                 };
 
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 5bf91879066..d65d4f7eb72 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust.
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
+#![feature(is_some_with)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
@@ -30,6 +31,7 @@ extern crate tracing;
 extern crate rustc_middle;
 
 pub mod const_eval;
+mod errors;
 pub mod interpret;
 pub mod transform;
 pub mod util;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 069fbed36ee..3dcd96df33c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -1,6 +1,6 @@
 //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations.
 
-use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed};
+use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
@@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeFoldable};
+use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -24,6 +24,7 @@ use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDro
 use super::resolver::FlowSensitiveAnalysis;
 use super::{ConstCx, Qualif};
 use crate::const_eval::is_unstable_const_fn;
+use crate::errors::UnstableInStable;
 
 type QualifResults<'mir, 'tcx, Q> =
     rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
@@ -418,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             PlaceContext::MutatingUse(MutatingUseContext::Borrow)
                         }
                     };
-                    self.visit_local(&reborrowed_place_ref.local, ctx, location);
+                    self.visit_local(reborrowed_place_ref.local, ctx, location);
                     self.visit_projection(reborrowed_place_ref, ctx, location);
                     return;
                 }
@@ -431,7 +432,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                         }
                         Mutability::Mut => PlaceContext::MutatingUse(MutatingUseContext::AddressOf),
                     };
-                    self.visit_local(&reborrowed_place_ref.local, ctx, location);
+                    self.visit_local(reborrowed_place_ref.local, ctx, location);
                     self.visit_projection(reborrowed_place_ref, ctx, location);
                     return;
                 }
@@ -1026,23 +1027,5 @@ fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
 fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
     let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
 
-    ccx.tcx
-        .sess
-        .struct_span_err(
-            span,
-            &format!("const-stable function cannot use `#[feature({})]`", gate.as_str()),
-        )
-        .span_suggestion(
-            attr_span,
-            "if it is not part of the public API, make this function unstably const",
-            concat!(r#"#[rustc_const_unstable(feature = "...", issue = "...")]"#, '\n'),
-            Applicability::HasPlaceholders,
-        )
-        .span_suggestion(
-            attr_span,
-            "otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks",
-            format!("#[rustc_allow_const_fn_unstable({})]\n", gate),
-            Applicability::MaybeIncorrect,
-        )
-        .emit();
+    ccx.tcx.sess.emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
 }
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 0c587220cb7..1d083b0bf82 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -1,7 +1,9 @@
 //! Concrete error types for all operations which may be invalid in a certain const context.
 
 use hir::def_id::LocalDefId;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{
+    error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
@@ -20,6 +22,10 @@ use rustc_span::{BytePos, Pos, Span, Symbol};
 use rustc_trait_selection::traits::SelectionContext;
 
 use super::ConstCx;
+use crate::errors::{
+    MutDerefErr, NonConstOpErr, PanicNonStrErr, RawPtrComparisonErr, RawPtrToIntErr,
+    StaticAccessErr, TransientMutBorrowErr, TransientMutBorrowErrRaw,
+};
 use crate::util::{call_kind, CallDesugaringKind, CallKind};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -155,8 +161,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     });
 
                     if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
-                        let span =
-                            tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
+                        let span = tcx.def_span(data.impl_def_id);
                         err.span_note(span, "impl defined here, but it is not `const`");
                     }
                 }
@@ -205,7 +210,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
 
                 match self_ty.kind() {
                     FnDef(def_id, ..) => {
-                        let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
+                        let span = tcx.def_span(*def_id);
                         if ccx.tcx.is_const_fn_raw(*def_id) {
                             span_bug!(span, "calling const FnDef errored when it shouldn't");
                         }
@@ -294,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                 err.note(&format!("attempting to deref into `{}`", deref_target_ty));
 
                 // Check first whether the source is accessible (issue #87060)
-                if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+                if tcx.sess.source_map().is_span_accessible(deref_target) {
                     err.span_note(deref_target, "deref defined here");
                 }
 
@@ -591,17 +596,17 @@ impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let raw = match self.0 {
-            hir::BorrowKind::Raw => "raw ",
-            hir::BorrowKind::Ref => "",
-        };
-
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_mut_refs,
-            span,
-            &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
-        )
+        let kind = ccx.const_kind();
+        match self.0 {
+            hir::BorrowKind::Raw => ccx
+                .tcx
+                .sess
+                .create_feature_err(TransientMutBorrowErrRaw { span, kind }, sym::const_mut_refs),
+            hir::BorrowKind::Ref => ccx
+                .tcx
+                .sess
+                .create_feature_err(TransientMutBorrowErr { span, kind }, sym::const_mut_refs),
+        }
     }
 }
 
@@ -622,12 +627,9 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_mut_refs,
-            span,
-            &format!("mutation through a reference is not allowed in {}s", ccx.const_kind()),
-        )
+        ccx.tcx
+            .sess
+            .create_feature_err(MutDerefErr { span, kind: ccx.const_kind() }, sym::const_mut_refs)
     }
 }
 
@@ -640,10 +642,7 @@ impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        ccx.tcx.sess.struct_span_err(
-            span,
-            "argument to `panic!()` in a const context must have type `&str`",
-        )
+        ccx.tcx.sess.create_err(PanicNonStrErr { span })
     }
 }
 
@@ -658,15 +657,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = ccx
-            .tcx
-            .sess
-            .struct_span_err(span, "pointers cannot be reliably compared during const eval");
-        err.note(
-            "see issue #53020 <https://github.com/rust-lang/rust/issues/53020> \
-            for more information",
-        );
-        err
+        ccx.tcx.sess.create_err(RawPtrComparisonErr { span })
     }
 }
 
@@ -702,15 +693,7 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = ccx
-            .tcx
-            .sess
-            .struct_span_err(span, "pointers cannot be cast to integers during const eval");
-        err.note("at compile-time, pointers do not have an integer value");
-        err.note(
-            "avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior",
-        );
-        err
+        ccx.tcx.sess.create_err(RawPtrToIntErr { span })
     }
 }
 
@@ -731,24 +714,11 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = struct_span_err!(
-            ccx.tcx.sess,
+        ccx.tcx.sess.create_err(StaticAccessErr {
             span,
-            E0013,
-            "{}s cannot refer to statics",
-            ccx.const_kind()
-        );
-        err.help(
-            "consider extracting the value of the `static` to a `const`, and referring to that",
-        );
-        if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
-            err.note(
-                "`static` and `const` variables can refer to other `const` variables. \
-                    A `const` variable, however, cannot refer to a `static` variable.",
-            );
-            err.help("To fix this, the value can be extracted to a `const` and then used.");
-        }
-        err
+            kind: ccx.const_kind(),
+            teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()),
+        })
     }
 }
 
@@ -761,13 +731,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
         ccx: &ConstCx<'_, 'tcx>,
         span: Span,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        struct_span_err!(
-            ccx.tcx.sess,
-            span,
-            E0625,
-            "thread-local statics cannot be \
-            accessed at compile-time"
-        )
+        ccx.tcx.sess.create_err(NonConstOpErr { span })
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 6e5a0c813ac..0aa7b117b89 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -226,7 +226,7 @@ impl Qualif for CustomEq {
         // because that component may be part of an enum variant (e.g.,
         // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
         // structural-match (`Option::None`).
-        traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
+        traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty, true).is_some()
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 3595a488d0c..12527a9b2ae 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::traversal::ReversePostorderIter;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, List, TyCtxt, TypeVisitable};
 use rustc_span::Span;
 
 use rustc_index::vec::{Idx, IndexVec};
@@ -106,7 +106,7 @@ struct Collector<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
-    fn visit_local(&mut self, &index: &Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, index: Local, context: PlaceContext, location: Location) {
         debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
         // We're only interested in temporaries and the return place
         match self.ccx.body.local_kind(index) {
@@ -856,7 +856,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     literal: ConstantKind::from_const(_const, tcx),
                 }))
             };
-            let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();
+            let blocks = self.source.basic_blocks.as_mut();
+            let local_decls = &mut self.source.local_decls;
             let loc = candidate.location;
             let statement = &mut blocks[loc.block].statements[loc.statement_index];
             match statement.kind {
@@ -865,7 +866,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                     Rvalue::Ref(ref mut region, borrow_kind, ref mut place),
                 )) => {
                     // Use the underlying local for this (necessarily interior) borrow.
-                    let ty = local_decls.local_decls()[place.local].ty;
+                    let ty = local_decls[place.local].ty;
                     let span = statement.source_info.span;
 
                     let ref_ty = tcx.mk_ref(
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 66d66ea9510..d3bf6b49f12 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -7,14 +7,15 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass,
-    MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement,
-    StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
+    MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope,
+    Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
-use rustc_mir_dataflow::storage::always_live_locals;
+use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
 use rustc_target::abi::{Size, VariantIdx};
 
@@ -48,7 +49,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
         let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
 
-        let always_live_locals = always_live_locals(body);
+        let always_live_locals = always_storage_live_locals(body);
         let storage_liveness = MaybeStorageLive::new(always_live_locals)
             .into_engine(tcx, body)
             .iterate_to_fixpoint()
@@ -196,8 +197,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
-        if self.body.local_decls.get(*local).is_none() {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
+        if self.body.local_decls.get(local).is_none() {
             self.fail(
                 location,
                 format!("local {:?} has no corresponding declaration in `body.local_decls`", local),
@@ -205,10 +206,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         }
 
         if self.reachable_blocks.contains(location.block) && context.is_use() {
-            // Uses of locals must occur while the local's storage is allocated.
+            // We check that the local is live whenever it is used. Technically, violating this
+            // restriction is only UB and not actually indicative of not well-formed MIR. This means
+            // that an optimization which turns MIR that already has UB into MIR that fails this
+            // check is not necessarily wrong. However, we have no such optimizations at the moment,
+            // and so we include this check anyway to help us catch bugs. If you happen to write an
+            // optimization that might cause this to incorrectly fire, feel free to remove this
+            // check.
             self.storage_liveness.seek_after_primary_effect(location);
             let locals_with_storage = self.storage_liveness.get();
-            if !locals_with_storage.contains(*local) {
+            if !locals_with_storage.contains(local) {
                 self.fail(location, format!("use of local {:?}, which has no storage here", local));
             }
         }
@@ -275,7 +282,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                 };
 
-                match parent_ty.ty.kind() {
+                let kind = match parent_ty.ty.kind() {
+                    &ty::Opaque(def_id, substs) => {
+                        self.tcx.bound_type_of(def_id).subst(self.tcx, substs).kind()
+                    }
+                    kind => kind,
+                };
+
+                match kind {
                     ty::Tuple(fields) => {
                         let Some(f_ty) = fields.get(f.as_usize()) else {
                             fail_out_of_bounds(self, location);
@@ -299,12 +313,39 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         };
                         check_equal(self, location, f_ty);
                     }
-                    ty::Generator(_, substs, _) => {
-                        let substs = substs.as_generator();
-                        let Some(f_ty) = substs.upvar_tys().nth(f.as_usize()) else {
-                            fail_out_of_bounds(self, location);
-                            return;
+                    &ty::Generator(def_id, substs, _) => {
+                        let f_ty = if let Some(var) = parent_ty.variant_index {
+                            let gen_body = if def_id == self.body.source.def_id() {
+                                self.body
+                            } else {
+                                self.tcx.optimized_mir(def_id)
+                            };
+
+                            let Some(layout) = gen_body.generator_layout() else {
+                                self.fail(location, format!("No generator layout for {:?}", parent_ty));
+                                return;
+                            };
+
+                            let Some(&local) = layout.variant_fields[var].get(f) else {
+                                fail_out_of_bounds(self, location);
+                                return;
+                            };
+
+                            let Some(&f_ty) = layout.field_tys.get(local) else {
+                                self.fail(location, format!("Out of bounds local {:?} for {:?}", local, parent_ty));
+                                return;
+                            };
+
+                            f_ty
+                        } else {
+                            let Some(f_ty) = substs.as_generator().prefix_tys().nth(f.index()) else {
+                                fail_out_of_bounds(self, location);
+                                return;
+                            };
+
+                            f_ty
                         };
+
                         check_equal(self, location, f_ty);
                     }
                     _ => {
@@ -328,6 +369,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         {
             self.fail(location, format!("{:?}, has deref at the wrong place", place));
         }
+
+        self.super_place(place, cntxt, location);
     }
 
     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
@@ -361,6 +404,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     );
                 }
             }
+            Rvalue::Ref(..) => {}
             Rvalue::Len(p) => {
                 let pty = p.ty(&self.body.local_decls, self.tcx).ty;
                 check_kinds!(
@@ -503,7 +547,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 let a = operand.ty(&self.body.local_decls, self.tcx);
                 check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
             }
-            _ => {}
+            Rvalue::Cast(kind, operand, target_type) => {
+                match kind {
+                    CastKind::Misc => {
+                        let op_ty = operand.ty(self.body, self.tcx);
+                        if op_ty.is_enum() {
+                            self.fail(
+                                location,
+                                format!(
+                                    "enum -> int casts should go through `Rvalue::Discriminant`: {operand:?}:{op_ty} as {target_type}",
+                                ),
+                            );
+                        }
+                    }
+                    // Nothing to check here
+                    CastKind::PointerFromExposedAddress
+                    | CastKind::PointerExposeAddress
+                    | CastKind::Pointer(_) => {}
+                }
+            }
+            Rvalue::Repeat(_, _)
+            | Rvalue::ThreadLocalRef(_)
+            | Rvalue::AddressOf(_, _)
+            | Rvalue::NullaryOp(_, _)
+            | Rvalue::Discriminant(_) => {}
         }
         self.super_rvalue(rvalue, location);
     }
@@ -823,8 +890,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         self.super_terminator(terminator, location);
     }
 
-    fn visit_source_scope(&mut self, scope: &SourceScope) {
-        if self.body.source_scopes.get(*scope).is_none() {
+    fn visit_source_scope(&mut self, scope: SourceScope) {
+        if self.body.source_scopes.get(scope).is_none() {
             self.tcx.sess.diagnostic().delay_span_bug(
                 self.body.span,
                 &format!(
diff --git a/compiler/rustc_const_eval/src/util/collect_writes.rs b/compiler/rustc_const_eval/src/util/collect_writes.rs
index 9c56fd722bd..8d92bb35938 100644
--- a/compiler/rustc_const_eval/src/util/collect_writes.rs
+++ b/compiler/rustc_const_eval/src/util/collect_writes.rs
@@ -24,8 +24,8 @@ struct FindLocalAssignmentVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
-    fn visit_local(&mut self, local: &Local, place_context: PlaceContext, location: Location) {
-        if self.needle != *local {
+    fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
+        if self.needle != local {
             return;
         }
 
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 390a44d3f33..0a2d2b40709 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(array_windows)]
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
+#![feature(cell_leak)]
 #![feature(control_flow_enum)]
 #![feature(extend_one)]
 #![feature(let_else)]
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 4437c0b1b69..cf0940df9e4 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -539,6 +539,33 @@ impl<T> RwLock<T> {
     pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
         self.write()
     }
+
+    #[cfg(not(parallel_compiler))]
+    #[inline(always)]
+    pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
+        ReadGuard::clone(rg)
+    }
+
+    #[cfg(parallel_compiler)]
+    #[inline(always)]
+    pub fn clone_guard<'a>(rg: &ReadGuard<'a, T>) -> ReadGuard<'a, T> {
+        ReadGuard::rwlock(&rg).read()
+    }
+
+    #[cfg(not(parallel_compiler))]
+    #[inline(always)]
+    pub fn leak(&self) -> &T {
+        ReadGuard::leak(self.read())
+    }
+
+    #[cfg(parallel_compiler)]
+    #[inline(always)]
+    pub fn leak(&self) -> &T {
+        let guard = self.read();
+        let ret = unsafe { &*(&*guard as *const T) };
+        std::mem::forget(guard);
+        ret
+    }
 }
 
 // FIXME: Probably a bad idea
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 3096af90d47..b71cdad718a 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -849,10 +849,10 @@ Available lint options:
     };
 
     println!("Lint checks provided by rustc:\n");
-    println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
-    println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
 
     let print_lints = |lints: Vec<&Lint>| {
+        println!("    {}  {:7.7}  {}", padded("name"), "default", "meaning");
+        println!("    {}  {:7.7}  {}", padded("----"), "-------", "-------");
         for lint in lints {
             let name = lint.name_lower().replace('_', "-");
             println!(
@@ -884,11 +884,15 @@ Available lint options:
     };
 
     println!("Lint groups provided by rustc:\n");
-    println!("    {}  sub-lints", padded("name"));
-    println!("    {}  ---------", padded("----"));
-    println!("    {}  all lints that are set to issue warnings", padded("warnings"));
 
-    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>| {
+    let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
+        println!("    {}  sub-lints", padded("name"));
+        println!("    {}  ---------", padded("----"));
+
+        if all_warnings {
+            println!("    {}  all lints that are set to issue warnings", padded("warnings"));
+        }
+
         for (name, to) in lints {
             let name = name.to_lowercase().replace('_', "-");
             let desc = to
@@ -901,7 +905,7 @@ Available lint options:
         println!("\n");
     };
 
-    print_lint_groups(builtin_groups);
+    print_lint_groups(builtin_groups, true);
 
     match (loaded_plugins, plugin.len(), plugin_groups.len()) {
         (false, 0, _) | (false, _, 0) => {
@@ -916,7 +920,7 @@ Available lint options:
             }
             if g > 0 {
                 println!("Lint groups provided by plugins loaded by this crate:\n");
-                print_lint_groups(plugin_groups);
+                print_lint_groups(plugin_groups, false);
             }
         }
     }
diff --git a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
index 4a42d52f710..1d3e33c8185 100644
--- a/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/builtin_macros.ftl
@@ -1,5 +1,5 @@
-builtin_macros-requires-cfg-pattern =
+builtin-macros-requires-cfg-pattern =
     macro requires a cfg-pattern as an argument
     .label = cfg-pattern required
 
-builtin_macros-expected-one-cfg-pattern = expected 1 cfg-pattern
+builtin-macros-expected-one-cfg-pattern = expected 1 cfg-pattern
diff --git a/compiler/rustc_error_messages/locales/en-US/const_eval.ftl b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl
new file mode 100644
index 00000000000..3f2ff861001
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/const_eval.ftl
@@ -0,0 +1,31 @@
+const-eval-unstable-in-stable =
+    const-stable function cannot use `#[feature({$gate})]`
+    .unstable-sugg = if it is not part of the public API, make this function unstably const
+    .bypass-sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+
+const-eval-thread-local-access =
+    thread-local statics cannot be accessed at compile-time
+
+const-eval-static-access =
+    {$kind}s cannot refer to statics
+    .help = consider extracting the value of the `static` to a `const`, and referring to that
+    .teach-note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
+    .teach-help = To fix this, the value can be extracted to a `const` and then used.
+
+const-eval-raw-ptr-to-int =
+    pointers cannot be cast to integers during const eval
+    .note = at compile-time, pointers do not have an integer value
+    .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
+
+const-eval-raw-ptr-comparison =
+    pointers cannot be reliably compared during const eval
+    .note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
+
+const-eval-panic-non-str = argument to `panic!()` in a const context must have type `&str`
+
+const-eval-mut-deref =
+    mutation through a reference is not allowed in {$kind}s
+
+const-eval-transient-mut-borrow = mutable references are not allowed in {$kind}s
+
+const-eval-transient-mut-borrow-raw = raw mutable references are not allowed in {$kind}s
diff --git a/compiler/rustc_error_messages/locales/en-US/expand.ftl b/compiler/rustc_error_messages/locales/en-US/expand.ftl
new file mode 100644
index 00000000000..8d506a3ea8b
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/expand.ftl
@@ -0,0 +1,5 @@
+expand-explain-doc-comment-outer =
+    outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
+
+expand-explain-doc-comment-inner =
+    inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl
new file mode 100644
index 00000000000..e7e07093c03
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl
@@ -0,0 +1,400 @@
+lint-array-into-iter =
+    this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
+    .use-iter-suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
+    .remove-into-iter-suggestion = or remove `.into_iter()` to iterate by value
+    .use-explicit-into-iter-suggestion =
+        or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+
+lint-enum-intrinsics-mem-discriminant =
+    the return value of `mem::discriminant` is unspecified when called with a non-enum type
+    .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
+
+lint-enum-intrinsics-mem-variant =
+    the return value of `mem::variant_count` is unspecified when called with a non-enum type
+    .note = the type parameter of `variant_count` should be an enum, but it was instantiated with the type `{$ty_param}`, which is not an enum.
+
+lint-expectation = this lint expectation is unfulfilled
+    .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
+
+lint-hidden-unicode-codepoints = unicode codepoint changing visible direction of text present in {$label}
+    .label = this {$label} contains {$count ->
+        [one] an invisible
+        *[other] invisible
+    } unicode text flow control {$count ->
+        [one] codepoint
+        *[other] codepoints
+    }
+    .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+    .suggestion-remove = if their presence wasn't intentional, you can remove them
+    .suggestion-escape = if you want to keep them but make them visible in your source code, you can escape them
+    .no-suggestion-note-escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped}
+
+lint-default-hash-types = prefer `{$preferred}` over `{$used}`, it has better performance
+    .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
+
+lint-query-instability = using `{$query}` can result in unstable query results
+    .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+
+lint-tykind-kind = usage of `ty::TyKind::<kind>`
+    .suggestion = try using `ty::<kind>` directly
+
+lint-tykind = usage of `ty::TyKind`
+    .help = try using `Ty` instead
+
+lint-ty-qualified = usage of qualified `ty::{$ty}`
+    .suggestion = try importing it and using it unqualified
+
+lint-lintpass-by-hand = implementing `LintPass` by hand
+    .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+
+lint-non-existant-doc-keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = \"...\")]`
+    .help = only existing keywords are allowed in core/std
+
+lint-diag-out-of-impl =
+    diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls
+
+lint-untranslatable-diag = diagnostics should be created using translatable messages
+
+lint-cstring-ptr = getting the inner pointer of a temporary `CString`
+    .as-ptr-label = this pointer will be invalid
+    .unwrap-label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+    .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+    .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
+
+lint-identifier-non-ascii-char = identifier contains non-ASCII characters
+
+lint-identifier-uncommon-codepoints = identifier contains uncommon Unicode codepoints
+
+lint-confusable-identifier-pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
+    .label = this is where the previous identifier occurred
+
+lint-mixed-script-confusables =
+    the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
+    .includes-note = the usage includes {$includes}
+    .note = please recheck to make sure their usages are indeed what you want
+
+lint-non-fmt-panic = panic message is not a string literal
+    .note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021
+    .more-info-note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+    .supports-fmt-note = the `{$name}!()` macro supports formatting, so there's no need for the `format!()` macro here
+    .supports-fmt-suggestion = remove the `format!(..)` macro call
+    .display-suggestion = add a "{"{"}{"}"}" format string to `Display` the message
+    .debug-suggestion =
+        add a "{"{"}:?{"}"}" format string to use the `Debug` implementation of `{$ty}`
+    .panic-suggestion = {$already_suggested ->
+        [true] or use
+        *[false] use
+    } std::panic::panic_any instead
+
+lint-non-fmt-panic-unused =
+    panic message contains {$count ->
+        [one] an unused
+        *[other] unused
+    } formatting {$count ->
+        [one] placeholder
+        *[other] placeholders
+    }
+    .note = this message is not used as a format string when given without arguments, but will be in Rust 2021
+    .add-args-suggestion = add the missing {$count ->
+        [one] argument
+        *[other] arguments
+    }
+    .add-fmt-suggestion = or add a "{"{"}{"}"}" format string to use the message literally
+
+lint-non-fmt-panic-braces =
+    panic message contains {$count ->
+        [one] a brace
+        *[other] braces
+    }
+    .note = this message is not used as a format string, but will be in Rust 2021
+    .suggestion = add a "{"{"}{"}"}" format string to use the message literally
+
+lint-non-camel-case-type = {$sort} `{$name}` should have an upper camel case name
+    .suggestion = convert the identifier to upper camel case
+    .label = should have an UpperCamelCase name
+
+lint-non-snake-case = {$sort} `{$name}` should have a snake case name
+    .rename-or-convert-suggestion = rename the identifier or convert it to a snake case raw identifier
+    .cannot-convert-note = `{$sc}` cannot be used as a raw identifier
+    .rename-suggestion = rename the identifier
+    .convert-suggestion = convert the identifier to snake case
+    .help = convert the identifier to snake case: `{$sc}`
+    .label = should have a snake_case name
+
+lint-non-upper_case-global = {$sort} `{$name}` should have an upper case name
+    .suggestion = convert the identifier to upper case
+    .label = should have an UPPER_CASE name
+
+lint-noop-method-call = call to `.{$method}()` on a reference in this situation does nothing
+    .label = unnecessary method call
+    .note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed
+
+lint-pass-by-value = passing `{$ty}` by reference
+    .suggestion = try passing by value
+
+lint-redundant-semicolons =
+    unnecessary trailing {$multiple ->
+        [true] semicolons
+        *[false] semicolon
+    }
+    .suggestion = remove {$multiple ->
+        [true] these semicolons
+        *[false] this semicolon
+    }
+
+lint-drop-trait-constraints =
+    bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped
+
+lint-drop-glue =
+    types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
+
+lint-range-endpoint-out-of-range = range endpoint is out of range for `{$ty}`
+    .suggestion = use an inclusive range instead
+
+lint-overflowing-bin-hex = literal out of range for `{$ty}`
+    .negative-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
+    .negative-becomes-note = and the value `-{$lit}` will become `{$actually}{$ty}`
+    .positive-note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}` and will become `{$actually}{$ty}`
+    .suggestion = consider using the type `{$suggestion_ty}` instead
+    .help = consider using the type `{$suggestion_ty}` instead
+
+lint-overflowing-int = literal out of range for `{$ty}`
+    .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
+    .help = consider using the type `{$suggestion_ty}` instead
+
+lint-only-cast-u8-to-char = only `u8` can be cast into `char`
+    .suggestion = use a `char` literal instead
+
+lint-overflowing-uint = literal out of range for `{$ty}`
+    .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
+
+lint-overflowing-literal = literal out of range for `{$ty}`
+    .note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY`
+
+lint-unused-comparisons = comparison is useless due to type limits
+
+lint-improper-ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
+    .label = not FFI-safe
+    .note = the type is defined here
+
+lint-improper-ctypes-opaque = opaque types have no C equivalent
+
+lint-improper-ctypes-fnptr-reason = this function pointer has Rust-specific calling convention
+lint-improper-ctypes-fnptr-help = consider using an `extern fn(...) -> ...` function pointer instead
+
+lint-improper-ctypes-tuple-reason = tuples have unspecified layout
+lint-improper-ctypes-tuple-help = consider using a struct instead
+
+lint-improper-ctypes-str-reason = string slices have no C equivalent
+lint-improper-ctypes-str-help = consider using `*const u8` and a length instead
+
+lint-improper-ctypes-dyn = trait objects have no C equivalent
+
+lint-improper-ctypes-slice-reason = slices have no C equivalent
+lint-improper-ctypes-slice-help = consider using a raw pointer instead
+
+lint-improper-ctypes-128bit = 128-bit integers don't currently have a known stable ABI
+
+lint-improper-ctypes-char-reason = the `char` type has no C equivalent
+lint-improper-ctypes-char-help = consider using `u32` or `libc::wchar_t` instead
+
+lint-improper-ctypes-non-exhaustive = this enum is non-exhaustive
+lint-improper-ctypes-non-exhaustive-variant = this enum has non-exhaustive variants
+
+lint-improper-ctypes-enum-repr-reason = enum has no representation hint
+lint-improper-ctypes-enum-repr-help =
+    consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+
+lint-improper-ctypes-struct-fieldless-reason = this struct has no fields
+lint-improper-ctypes-struct-fieldless-help = consider adding a member to this struct
+
+lint-improper-ctypes-union-fieldless-reason = this union has no fields
+lint-improper-ctypes-union-fieldless-help = consider adding a member to this union
+
+lint-improper-ctypes-struct-non-exhaustive = this struct is non-exhaustive
+lint-improper-ctypes-union-non-exhaustive = this union is non-exhaustive
+
+lint-improper-ctypes-struct-layout-reason = this struct has unspecified layout
+lint-improper-ctypes-struct-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+
+lint-improper-ctypes-union-layout-reason = this union has unspecified layout
+lint-improper-ctypes-union-layout-help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+
+lint-improper-ctypes-box = box cannot be represented as a single pointer
+
+lint-improper-ctypes-enum-phantomdata = this enum contains a PhantomData field
+
+lint-improper-ctypes-struct-zst = this struct contains only zero-sized fields
+
+lint-improper-ctypes-array-reason = passing raw arrays by value is not FFI-safe
+lint-improper-ctypes-array-help = consider passing a pointer to the array
+
+lint-improper-ctypes-only-phantomdata = composed only of `PhantomData`
+
+lint-variant-size-differences =
+    enum variant is more than three times larger ({$largest} bytes) than the next largest
+
+lint-atomic-ordering-load = atomic loads cannot have `Release` or `AcqRel` ordering
+    .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+lint-atomic-ordering-store = atomic stores cannot have `Acquire` or `AcqRel` ordering
+    .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+lint-atomic-ordering-fence = memory fences cannot have `Relaxed` ordering
+    .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+
+lint-atomic-ordering-invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write
+    .label = invalid failure ordering
+    .help = consider using `Acquire` or `Relaxed` failure ordering instead
+
+lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering
+    .fail-label = `{$fail_ordering}` failure ordering
+    .success-label = `{$success_ordering}` success ordering
+    .suggestion = consider using `{$success_suggestion}` success ordering instead
+
+lint-unused-op = unused {$op} that must be used
+    .label = the {$op} produces a value
+    .suggestion = use `let _ = ...` to ignore the resulting value
+
+lint-unused-result = unused result of type `{$ty}`
+
+lint-unused-closure =
+    unused {$pre}{$count ->
+        [one] closure
+        *[other] closures
+    }{$post} that must be used
+    .note = closures are lazy and do nothing unless called
+
+lint-unused-generator =
+    unused {$pre}{$count ->
+        [one] generator
+        *[other] generator
+    }{$post} that must be used
+    .note = generators are lazy and do nothing unless resumed
+
+lint-unused-def = unused {$pre}`{$def}`{$post} that must be used
+
+lint-path-statement-drop = path statement drops value
+    .suggestion = use `drop` to clarify the intent
+
+lint-path-statement-no-effect = path statement with no effect
+
+lint-unused-delim = unnecessary {$delim} around {$item}
+    .suggestion = remove these {$delim}
+
+lint-unused-import-braces = braces around {$node} is unnecessary
+
+lint-unused-allocation = unnecessary allocation, use `&` instead
+lint-unused-allocation-mut = unnecessary allocation, use `&mut` instead
+
+lint-builtin-while-true = denote infinite loops with `loop {"{"} ... {"}"}`
+    .suggestion = use `loop`
+
+lint-builtin-box-pointers = type uses owned (Box type) pointers: {$ty}
+
+lint-builtin-non-shorthand-field-patterns = the `{$ident}:` in this pattern is redundant
+    .suggestion = use shorthand field pattern
+
+lint-builtin-overridden-symbol-name =
+    the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
+
+lint-builtin-overridden-symbol-section =
+    the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them
+
+lint-builtin-allow-internal-unsafe =
+    `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
+
+lint-builtin-unsafe-block = usage of an `unsafe` block
+
+lint-builtin-unsafe-trait = declaration of an `unsafe` trait
+
+lint-builtin-unsafe-impl = implementation of an `unsafe` trait
+
+lint-builtin-no-mangle-fn = declaration of a `no_mangle` function
+lint-builtin-export-name-fn = declaration of a function with `export_name`
+lint-builtin-link-section-fn = declaration of a function with `link_section`
+
+lint-builtin-no-mangle-static = declaration of a `no_mangle` static
+lint-builtin-export-name-static = declaration of a static with `export_name`
+lint-builtin-link-section-static = declaration of a static with `link_section`
+
+lint-builtin-no-mangle-method = declaration of a `no_mangle` method
+lint-builtin-export-name-method = declaration of a method with `export_name`
+
+lint-builtin-decl-unsafe-fn = declaration of an `unsafe` function
+lint-builtin-decl-unsafe-method = declaration of an `unsafe` method
+lint-builtin-impl-unsafe-method = implementation of an `unsafe` method
+
+lint-builtin-missing-doc = missing documentation for {$article} {$desc}
+
+lint-builtin-missing-copy-impl = type could implement `Copy`; consider adding `impl Copy`
+
+lint-builtin-missing-debug-impl =
+    type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation
+
+lint-builtin-anonymous-params = anonymous parameters are deprecated and will be removed in the next edition
+    .suggestion = try naming the parameter or explicitly ignoring it
+
+lint-builtin-deprecated-attr-link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
+lint-builtin-deprecated-attr-used = use of deprecated attribute `{$name}`: no longer used.
+lint-builtin-deprecated-attr-default-suggestion = remove this attribute
+
+lint-builtin-unused-doc-comment = unused doc comment
+    .label = rustdoc does not generate documentation for {$kind}
+    .plain-help = use `//` for a plain comment
+    .block-help = use `/* */` for a plain comment
+
+lint-builtin-no-mangle-generic = functions generic over types or consts must be mangled
+    .suggestion = remove this attribute
+
+lint-builtin-const-no-mangle = const items should never be `#[no_mangle]`
+    .suggestion = try a static value
+
+lint-builtin-mutable-transmutes =
+    transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
+
+lint-builtin-unstable-features = unstable feature
+
+lint-builtin-unreachable-pub = unreachable `pub` {$what}
+    .suggestion = consider restricting its visibility
+    .help = or consider exporting it for use by other crates
+
+lint-builtin-type-alias-bounds-help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
+
+lint-builtin-type-alias-where-clause = where clauses are not enforced in type aliases
+    .suggestion = the clause will not be checked when the type alias is used, and should be removed
+
+lint-builtin-type-alias-generic-bounds = bounds on generic parameters are not enforced in type aliases
+    .suggestion = the bound will not be checked when the type alias is used, and should be removed
+
+lint-builtin-trivial-bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
+
+lint-builtin-ellipsis-inclusive-range-patterns = `...` range patterns are deprecated
+    .suggestion = use `..=` for an inclusive range
+
+lint-builtin-unnameable-test-items = cannot test inner items
+
+lint-builtin-keyword-idents = `{$kw}` is a keyword in the {$next} edition
+    .suggestion = you can use a raw identifier to stay compatible
+
+lint-builtin-explicit-outlives = outlives requirements can be inferred
+    .suggestion = remove {$count ->
+        [one] this bound
+        *[other] these bounds
+    }
+
+lint-builtin-incomplete-features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
+    .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
+    .help = consider using `min_{$name}` instead, which is more stable and complete
+
+lint-builtin-clashing-extern-same-name = `{$this_fi}` redeclared with a different signature
+    .previous-decl-label = `{$orig}` previously declared here
+    .mismatch-label = this signature doesn't match the previous declaration
+lint-builtin-clashing-extern-diff-name = `{$this_fi}` redeclares `{$orig}` with a different signature
+    .previous-decl-label = `{$orig}` previously declared here
+    .mismatch-label = this signature doesn't match the previous declaration
+
+lint-builtin-deref-nullptr = dereferencing a null pointer
+    .label = this code causes undefined behavior when executed
+
+lint-builtin-asm-labels = avoid using named labels in inline assembly
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index d52b94b78df..d16171cb162 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -31,11 +31,14 @@ pub use unic_langid::{langid, LanguageIdentifier};
 
 // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
 fluent_messages! {
+    borrowck => "../locales/en-US/borrowck.ftl",
+    builtin_macros => "../locales/en-US/builtin_macros.ftl",
+    const_eval => "../locales/en-US/const_eval.ftl",
+    expand => "../locales/en-US/expand.ftl",
+    lint => "../locales/en-US/lint.ftl",
     parser => "../locales/en-US/parser.ftl",
     privacy => "../locales/en-US/privacy.ftl",
     typeck => "../locales/en-US/typeck.ftl",
-    builtin_macros => "../locales/en-US/builtin_macros.ftl",
-    borrowck => "../locales/en-US/borrowck.ftl",
 }
 
 pub use fluent_generated::{self as fluent, DEFAULT_LOCALE_RESOURCES};
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 89557626057..7d7e92c5229 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -13,6 +13,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 unicode-width = "0.1.4"
 atty = "0.2"
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index b8545139cec..9429ad1a897 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -1,14 +1,15 @@
 use crate::snippet::Style;
 use crate::{
-    CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution,
-    SubstitutionPart, SuggestionStyle,
+    CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan,
+    SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
 };
 use rustc_data_structures::stable_map::FxHashMap;
 use rustc_error_messages::FluentValue;
+use rustc_hir as hir;
 use rustc_lint_defs::{Applicability, LintExpectationId};
 use rustc_span::edition::LATEST_STABLE_EDITION;
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{edition::Edition, Span, DUMMY_SP};
 use std::borrow::Cow;
 use std::fmt;
 use std::hash::{Hash, Hasher};
@@ -39,12 +40,94 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
+impl IntoDiagnosticArg for bool {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        if self {
+            DiagnosticArgValue::Str(Cow::Borrowed("true"))
+        } else {
+            DiagnosticArgValue::Str(Cow::Borrowed("false"))
+        }
+    }
+}
+
+impl IntoDiagnosticArg for i8 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for u8 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for i16 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for u16 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for i32 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for u32 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for i64 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for u64 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for i128 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for u128 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
 impl IntoDiagnosticArg for String {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         DiagnosticArgValue::Str(Cow::Owned(self))
     }
 }
 
+impl IntoDiagnosticArg for std::num::NonZeroU32 {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
+impl IntoDiagnosticArg for Edition {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
 impl IntoDiagnosticArg for Symbol {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
         self.to_ident_string().into_diagnostic_arg()
@@ -78,6 +161,16 @@ impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
     }
 }
 
+impl IntoDiagnosticArg for hir::ConstContext {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        DiagnosticArgValue::Str(Cow::Borrowed(match self {
+            hir::ConstContext::ConstFn => "constant function",
+            hir::ConstContext::Static(_) => "static",
+            hir::ConstContext::Const => "constant",
+        }))
+    }
+}
+
 /// Trait implemented by error types. This should not be implemented manually. Instead, use
 /// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic].
 #[rustc_diagnostic_item = "AddSubdiagnostic"]
@@ -86,6 +179,14 @@ pub trait AddSubdiagnostic {
     fn add_to_diagnostic(self, diag: &mut Diagnostic);
 }
 
+/// Trait implemented by lint types. This should not be implemented manually. Instead, use
+/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
+#[rustc_diagnostic_item = "DecorateLint"]
+pub trait DecorateLint<'a, G: EmissionGuarantee> {
+    /// Decorate and emit a lint.
+    fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>);
+}
+
 #[must_use]
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub struct Diagnostic {
@@ -286,7 +387,7 @@ impl Diagnostic {
     ///
     /// This span is *not* considered a ["primary span"][`MultiSpan`]; only
     /// the `Span` supplied when creating the diagnostic is primary.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label));
         self
@@ -405,7 +506,7 @@ impl Diagnostic {
     }
 
     /// Add a note attached to this diagnostic.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::Note, msg, MultiSpan::new(), None);
         self
@@ -428,7 +529,7 @@ impl Diagnostic {
 
     /// Prints the span with a note above it.
     /// This is like [`Diagnostic::note()`], but it gets its own span.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_note<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
@@ -450,7 +551,7 @@ impl Diagnostic {
     }
 
     /// Add a warning attached to this diagnostic.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::Warning(None), msg, MultiSpan::new(), None);
         self
@@ -458,7 +559,7 @@ impl Diagnostic {
 
     /// Prints the span with a warning above it.
     /// This is like [`Diagnostic::warn()`], but it gets its own span.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_warn<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
@@ -469,7 +570,7 @@ impl Diagnostic {
     }
 
     /// Add a help message attached to this diagnostic.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
         self.sub(Level::Help, msg, MultiSpan::new(), None);
         self
@@ -483,7 +584,7 @@ impl Diagnostic {
 
     /// Prints the span with some help above it.
     /// This is like [`Diagnostic::help()`], but it gets its own span.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_help<S: Into<MultiSpan>>(
         &mut self,
         sp: S,
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 9e0a99849a3..c3341fd68f4 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -529,7 +529,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         applicability: Applicability,
     ) -> &mut Self);
 
-    forward!(pub fn set_primary_message(&mut self, msg: impl Into<String>) -> &mut Self);
+    forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
     forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
     forward!(pub fn set_arg(
@@ -589,3 +589,26 @@ macro_rules! struct_span_err {
 macro_rules! error_code {
     ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
 }
+
+/// Wrapper around a `DiagnosticBuilder` for creating lints.
+pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
+
+impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
+    /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
+    pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
+        self.0.set_primary_message(msg);
+        self.0.set_is_lint();
+        self.0
+    }
+
+    /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
+    pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
+        LintDiagnosticBuilder(err)
+    }
+}
+
+impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
+    pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
+        LintDiagnosticBuilder(self.0.forget_guarantee())
+    }
+}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 6d74e9a9f2b..85ea8eb3937 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -63,7 +63,7 @@ impl HumanReadableErrorType {
         bundle: Option<Lrc<FluentBundle>>,
         fallback_bundle: LazyFallbackBundle,
         teach: bool,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> EmitterWriter {
         let (short, color_config) = self.unzip();
@@ -76,7 +76,7 @@ impl HumanReadableErrorType {
             short,
             teach,
             color,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         )
     }
@@ -710,7 +710,7 @@ pub struct EmitterWriter {
     short_message: bool,
     teach: bool,
     ui_testing: bool,
-    terminal_width: Option<usize>,
+    diagnostic_width: Option<usize>,
 
     macro_backtrace: bool,
 }
@@ -730,7 +730,7 @@ impl EmitterWriter {
         fallback_bundle: LazyFallbackBundle,
         short_message: bool,
         teach: bool,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> EmitterWriter {
         let dst = Destination::from_stderr(color_config);
@@ -742,7 +742,7 @@ impl EmitterWriter {
             short_message,
             teach,
             ui_testing: false,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         }
     }
@@ -755,7 +755,7 @@ impl EmitterWriter {
         short_message: bool,
         teach: bool,
         colored: bool,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> EmitterWriter {
         EmitterWriter {
@@ -766,7 +766,7 @@ impl EmitterWriter {
             short_message,
             teach,
             ui_testing: false,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         }
     }
@@ -1615,7 +1615,7 @@ impl EmitterWriter {
                     width_offset + annotated_file.multiline_depth + 1
                 };
 
-                let column_width = if let Some(width) = self.terminal_width {
+                let column_width = if let Some(width) = self.diagnostic_width {
                     width.saturating_sub(code_offset)
                 } else if self.ui_testing {
                     DEFAULT_COLUMN_WIDTH
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index d4d1491c169..b8cd334b4c6 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -42,7 +42,7 @@ pub struct JsonEmitter {
     pretty: bool,
     ui_testing: bool,
     json_rendered: HumanReadableErrorType,
-    terminal_width: Option<usize>,
+    diagnostic_width: Option<usize>,
     macro_backtrace: bool,
 }
 
@@ -54,7 +54,7 @@ impl JsonEmitter {
         fallback_bundle: LazyFallbackBundle,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -66,7 +66,7 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         }
     }
@@ -76,7 +76,7 @@ impl JsonEmitter {
         json_rendered: HumanReadableErrorType,
         fluent_bundle: Option<Lrc<FluentBundle>>,
         fallback_bundle: LazyFallbackBundle,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         let file_path_mapping = FilePathMapping::empty();
@@ -87,7 +87,7 @@ impl JsonEmitter {
             fallback_bundle,
             pretty,
             json_rendered,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         )
     }
@@ -100,7 +100,7 @@ impl JsonEmitter {
         fallback_bundle: LazyFallbackBundle,
         pretty: bool,
         json_rendered: HumanReadableErrorType,
-        terminal_width: Option<usize>,
+        diagnostic_width: Option<usize>,
         macro_backtrace: bool,
     ) -> JsonEmitter {
         JsonEmitter {
@@ -112,7 +112,7 @@ impl JsonEmitter {
             pretty,
             ui_testing: false,
             json_rendered,
-            terminal_width,
+            diagnostic_width,
             macro_backtrace,
         }
     }
@@ -345,7 +345,7 @@ impl Diagnostic {
                 je.fluent_bundle.clone(),
                 je.fallback_bundle.clone(),
                 false,
-                je.terminal_width,
+                je.diagnostic_width,
                 je.macro_backtrace,
             )
             .ui_testing(je.ui_testing)
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 9c42f6f26fc..e59a74e380a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -370,10 +370,10 @@ impl fmt::Display for ExplicitBug {
 impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{
-    AddSubdiagnostic, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
+    AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
     DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
-pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee};
+pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder};
 use std::backtrace::Backtrace;
 
 /// A handler deals with errors and other compiler output.
@@ -649,7 +649,7 @@ impl Handler {
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_warn(
         &self,
         span: impl Into<MultiSpan>,
@@ -678,7 +678,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_allow(
         &self,
         span: impl Into<MultiSpan>,
@@ -691,7 +691,7 @@ impl Handler {
 
     /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
     /// Also include a code.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -708,7 +708,7 @@ impl Handler {
     /// Attempting to `.emit()` the builder will only emit if either:
     /// * `can_emit_warnings` is `true`
     /// * `is_force_warn` was set in `DiagnosticId::Lint`
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Warning(None), msg)
     }
@@ -728,13 +728,13 @@ impl Handler {
     }
 
     /// Construct a builder at the `Allow` level with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Allow, msg)
     }
 
     /// Construct a builder at the `Expect` level with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -744,7 +744,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -756,7 +756,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -770,7 +770,7 @@ impl Handler {
 
     /// Construct a builder at the `Error` level with the `msg`.
     // FIXME: This method should be removed (every error should have an associated error code).
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -785,7 +785,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Error` level with the `msg` and the `code`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -797,7 +797,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Warn` level with the `msg` and the `code`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -809,7 +809,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_fatal(
         &self,
         span: impl Into<MultiSpan>,
@@ -821,7 +821,7 @@ impl Handler {
     }
 
     /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -834,19 +834,19 @@ impl Handler {
     }
 
     /// Construct a builder at the `Error` level with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         DiagnosticBuilder::new_fatal(self, msg)
     }
 
     /// Construct a builder at the `Help` level with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         DiagnosticBuilder::new(self, Level::Help, msg)
     }
 
     /// Construct a builder at the `Note` level with the `msg`.
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_note_without_error(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -854,13 +854,13 @@ impl Handler {
         DiagnosticBuilder::new(self, Level::Note, msg)
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
         self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
         FatalError.raise()
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_fatal_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -871,7 +871,7 @@ impl Handler {
         FatalError.raise()
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err(
         &self,
         span: impl Into<MultiSpan>,
@@ -880,7 +880,7 @@ impl Handler {
         self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span).unwrap()
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -893,12 +893,12 @@ impl Handler {
         );
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
         self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_warn_with_code(
         &self,
         span: impl Into<MultiSpan>,
@@ -1558,7 +1558,7 @@ pub fn add_elided_lifetime_in_path_suggestion(
     insertion_span: Span,
 ) {
     diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
-    if source_map.span_to_snippet(insertion_span).is_err() {
+    if !source_map.is_span_accessible(insertion_span) {
         // Do not try to suggest anything if generated by a proc-macro.
         return;
     }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 1e57d66dd9f..bfe2d773788 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1077,7 +1077,7 @@ impl<'a> ExtCtxt<'a> {
         self.current_expansion.id.expansion_cause()
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -1102,11 +1102,11 @@ impl<'a> ExtCtxt<'a> {
     ///
     /// Compilation will be stopped in the near future (at the end of
     /// the macro expansion phase).
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
     }
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 1694a8865dd..74e9bbeeeaf 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -152,6 +152,19 @@ impl<'a> ExtCtxt<'a> {
         ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) }
     }
 
+    pub fn stmt_let_pat(&self, sp: Span, pat: P<ast::Pat>, ex: P<ast::Expr>) -> ast::Stmt {
+        let local = P(ast::Local {
+            pat,
+            ty: None,
+            id: ast::DUMMY_NODE_ID,
+            kind: LocalKind::Init(ex),
+            span: sp,
+            attrs: AttrVec::new(),
+            tokens: None,
+        });
+        self.stmt_local(local, sp)
+    }
+
     pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P<ast::Expr>) -> ast::Stmt {
         self.stmt_let_ty(sp, mutbl, ident, None, ex)
     }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f40c365cbcc..3e9ddd6aec0 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -25,6 +25,7 @@ use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::Transparency;
+use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::Span;
 
@@ -345,7 +346,7 @@ fn expand_macro<'cx>(
     if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
         err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
     }
-
+    annotate_doc_comment(&mut err, sess.source_map(), span);
     // Check whether there's a missing comma in this macro call, like `println!("{}" a);`
     if let Some((arg, comma_span)) = arg.add_comma() {
         for lhs in lhses {
@@ -453,7 +454,10 @@ pub fn compile_declarative_macro(
         Failure(token, msg) => {
             let s = parse_failure_msg(&token);
             let sp = token.span.substitute_dummy(def.span);
-            sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
+            let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, &s);
+            err.span_label(sp, msg);
+            annotate_doc_comment(&mut err, sess.source_map(), sp);
+            err.emit();
             return dummy_syn_ext();
         }
         Error(sp, msg) => {
@@ -590,6 +594,34 @@ pub fn compile_declarative_macro(
     (mk_syn_ext(expander), rule_spans)
 }
 
+#[derive(SessionSubdiagnostic)]
+enum ExplainDocComment {
+    #[label(expand::explain_doc_comment_inner)]
+    Inner {
+        #[primary_span]
+        span: Span,
+    },
+    #[label(expand::explain_doc_comment_outer)]
+    Outer {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+fn annotate_doc_comment(
+    err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+    sm: &SourceMap,
+    span: Span,
+) {
+    if let Ok(src) = sm.span_to_snippet(span) {
+        if src.starts_with("///") || src.starts_with("/**") {
+            err.subdiagnostic(ExplainDocComment::Outer { span });
+        } else if src.starts_with("//!") || src.starts_with("/*!") {
+            err.subdiagnostic(ExplainDocComment::Inner { span });
+        }
+    }
+}
+
 fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 0e909e2f982..411d6be9c44 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -426,6 +426,10 @@ impl server::TokenStream for Rustc<'_, '_> {
         // We don't use `TokenStream::from_ast` as the tokenstream currently cannot
         // be recovered in the general case.
         match &expr.kind {
+            ast::ExprKind::Lit(l) if l.token.kind == token::Bool => {
+                Ok(tokenstream::TokenTree::token(token::Ident(l.token.symbol, false), l.span)
+                    .into())
+            }
             ast::ExprKind::Lit(l) => {
                 Ok(tokenstream::TokenTree::token(token::Literal(l.token), l.span).into())
             }
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 064ed0cde96..69ad623b7ea 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 doctest = false
 
 [dependencies]
+rustc_arena = { path = "../rustc_arena" }
 rustc_target = { path = "../rustc_target" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 5d1314ebb48..a6d10f3adae 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -9,7 +9,7 @@ macro_rules! arena_types {
             // HIR types
             [] hir_krate: rustc_hir::Crate<'tcx>,
             [] arm: rustc_hir::Arm<'tcx>,
-            [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, Span),
+            [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span),
             [] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [] attribute: rustc_ast::Attribute,
             [] block: rustc_hir::Block<'tcx>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a7fc59255d7..04f585df34c 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1438,18 +1438,8 @@ impl<'hir> Body<'hir> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(
-    Clone,
-    PartialEq,
-    PartialOrd,
-    Eq,
-    Hash,
-    HashStable_Generic,
-    Encodable,
-    Decodable,
-    Debug,
-    Copy
-)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1481,18 +1471,8 @@ impl GeneratorKind {
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(
-    Clone,
-    PartialEq,
-    PartialOrd,
-    Eq,
-    Hash,
-    HashStable_Generic,
-    Encodable,
-    Decodable,
-    Debug,
-    Copy
-)]
+#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -1595,6 +1575,9 @@ impl fmt::Display for ConstContext {
     }
 }
 
+// NOTE: `IntoDiagnosticArg` impl for `ConstContext` lives in `rustc_errors`
+// due to a cyclical dependency between hir that crate.
+
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
@@ -3326,7 +3309,6 @@ pub enum Node<'hir> {
     Ty(&'hir Ty<'hir>),
     TypeBinding(&'hir TypeBinding<'hir>),
     TraitRef(&'hir TraitRef<'hir>),
-    Binding(&'hir Pat<'hir>),
     Pat(&'hir Pat<'hir>),
     Arm(&'hir Arm<'hir>),
     Block(&'hir Block<'hir>),
@@ -3378,7 +3360,6 @@ impl<'hir> Node<'hir> {
             | Node::Block(..)
             | Node::Ctor(..)
             | Node::Pat(..)
-            | Node::Binding(..)
             | Node::Arm(..)
             | Node::Local(..)
             | Node::Crate(..)
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 384a0f9c225..531d9f14040 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -19,7 +19,7 @@
 //!    - Example: Examine each expression to look for its type and do some check or other.
 //!    - How: Implement `intravisit::Visitor` and override the `NestedFilter` type to
 //!      `nested_filter::OnlyBodies` (and implement `nested_visit_map`), and use
-//!      `tcx.hir().deep_visit_all_item_likes(&mut visitor)`. Within your
+//!      `tcx.hir().visit_all_item_likes_in_crate(&mut visitor)`. Within your
 //!      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
 //!      `intravisit::walk_expr()` to keep walking the subparts).
 //!    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
@@ -190,7 +190,7 @@ use nested_filter::NestedFilter;
 /// (this is why the module is called `intravisit`, to distinguish it
 /// from the AST's `visit` module, which acts differently). If you
 /// simply want to visit all items in the crate in some order, you
-/// should call `Crate::visit_all_items`. Otherwise, see the comment
+/// should call `tcx.hir().visit_all_item_likes_in_crate`. Otherwise, see the comment
 /// on `visit_nested_item` for details on how to visit nested items.
 ///
 /// If you want to ensure that your code handles every variant
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 9f32a7da159..0f9e6fa7b98 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -18,6 +18,8 @@ extern crate rustc_macros;
 #[macro_use]
 extern crate rustc_data_structures;
 
+extern crate self as rustc_hir;
+
 mod arena;
 pub mod def;
 pub mod def_path_hash_map;
@@ -41,3 +43,5 @@ pub use hir_id::*;
 pub use lang_items::{LangItem, LanguageItems};
 pub use stable_hash_impls::HashStableContext;
 pub use target::{MethodKind, Target};
+
+arena_types!(rustc_arena::declare_arena);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 7bf91df9f76..50acb0270b0 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -59,7 +59,7 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
             Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
             Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
             Nested::Body(id) => state.print_expr(&self.body(id).value),
-            Nested::BodyParamPat(id, i) => state.print_pat(&self.body(id).params[i].pat),
+            Nested::BodyParamPat(id, i) => state.print_pat(self.body(id).params[i].pat),
         }
     }
 }
@@ -74,37 +74,37 @@ pub struct State<'a> {
 impl<'a> State<'a> {
     pub fn print_node(&mut self, node: Node<'_>) {
         match node {
-            Node::Param(a) => self.print_param(&a),
-            Node::Item(a) => self.print_item(&a),
-            Node::ForeignItem(a) => self.print_foreign_item(&a),
+            Node::Param(a) => self.print_param(a),
+            Node::Item(a) => self.print_item(a),
+            Node::ForeignItem(a) => self.print_foreign_item(a),
             Node::TraitItem(a) => self.print_trait_item(a),
             Node::ImplItem(a) => self.print_impl_item(a),
-            Node::Variant(a) => self.print_variant(&a),
-            Node::AnonConst(a) => self.print_anon_const(&a),
-            Node::Expr(a) => self.print_expr(&a),
-            Node::Stmt(a) => self.print_stmt(&a),
-            Node::PathSegment(a) => self.print_path_segment(&a),
-            Node::Ty(a) => self.print_type(&a),
-            Node::TypeBinding(a) => self.print_type_binding(&a),
-            Node::TraitRef(a) => self.print_trait_ref(&a),
-            Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
-            Node::Arm(a) => self.print_arm(&a),
+            Node::Variant(a) => self.print_variant(a),
+            Node::AnonConst(a) => self.print_anon_const(a),
+            Node::Expr(a) => self.print_expr(a),
+            Node::Stmt(a) => self.print_stmt(a),
+            Node::PathSegment(a) => self.print_path_segment(a),
+            Node::Ty(a) => self.print_type(a),
+            Node::TypeBinding(a) => self.print_type_binding(a),
+            Node::TraitRef(a) => self.print_trait_ref(a),
+            Node::Pat(a) => self.print_pat(a),
+            Node::Arm(a) => self.print_arm(a),
             Node::Infer(_) => self.word("_"),
             Node::Block(a) => {
                 // Containing cbox, will be closed by print-block at `}`.
                 self.cbox(INDENT_UNIT);
                 // Head-ibox, will be closed by print-block after `{`.
                 self.ibox(0);
-                self.print_block(&a)
+                self.print_block(a);
             }
-            Node::Lifetime(a) => self.print_lifetime(&a),
+            Node::Lifetime(a) => self.print_lifetime(a),
             Node::GenericParam(_) => panic!("cannot print Node::GenericParam"),
             Node::Field(_) => panic!("cannot print Node::Field"),
             // These cases do not carry enough information in the
             // `hir_map` to reconstruct their full structure for pretty
             // printing.
             Node::Ctor(..) => panic!("cannot print isolated Ctor"),
-            Node::Local(a) => self.print_local_decl(&a),
+            Node::Local(a) => self.print_local_decl(a),
             Node::Crate(..) => panic!("cannot print Crate"),
         }
     }
@@ -266,7 +266,7 @@ impl<'a> State<'a> {
     }
 
     pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) {
-        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
+        self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
     }
 
     pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
@@ -287,9 +287,9 @@ impl<'a> State<'a> {
         self.maybe_print_comment(ty.span.lo());
         self.ibox(0);
         match ty.kind {
-            hir::TyKind::Slice(ref ty) => {
+            hir::TyKind::Slice(ty) => {
                 self.word("[");
-                self.print_type(&ty);
+                self.print_type(ty);
                 self.word("]");
             }
             hir::TyKind::Ptr(ref mt) => {
@@ -304,23 +304,16 @@ impl<'a> State<'a> {
             hir::TyKind::Never => {
                 self.word("!");
             }
-            hir::TyKind::Tup(ref elts) => {
+            hir::TyKind::Tup(elts) => {
                 self.popen();
-                self.commasep(Inconsistent, &elts, |s, ty| s.print_type(&ty));
+                self.commasep(Inconsistent, elts, |s, ty| s.print_type(ty));
                 if elts.len() == 1 {
                     self.word(",");
                 }
                 self.pclose();
             }
-            hir::TyKind::BareFn(ref f) => {
-                self.print_ty_fn(
-                    f.abi,
-                    f.unsafety,
-                    &f.decl,
-                    None,
-                    &f.generic_params,
-                    f.param_names,
-                );
+            hir::TyKind::BareFn(f) => {
+                self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
@@ -344,9 +337,9 @@ impl<'a> State<'a> {
                     self.print_lifetime(lifetime);
                 }
             }
-            hir::TyKind::Array(ref ty, ref length) => {
+            hir::TyKind::Array(ty, ref length) => {
                 self.word("[");
-                self.print_type(&ty);
+                self.print_type(ty);
                 self.word("; ");
                 self.print_array_length(length);
                 self.word("]");
@@ -373,7 +366,7 @@ impl<'a> State<'a> {
         self.maybe_print_comment(item.span.lo());
         self.print_outer_attributes(self.attrs(item.hir_id()));
         match item.kind {
-            hir::ForeignItemKind::Fn(ref decl, ref arg_names, ref generics) => {
+            hir::ForeignItemKind::Fn(decl, arg_names, generics) => {
                 self.head("");
                 self.print_fn(
                     decl,
@@ -392,14 +385,14 @@ impl<'a> State<'a> {
                 self.word(";");
                 self.end() // end the outer fn box
             }
-            hir::ForeignItemKind::Static(ref t, m) => {
+            hir::ForeignItemKind::Static(t, m) => {
                 self.head("static");
                 if m == hir::Mutability::Mut {
                     self.word_space("mut");
                 }
                 self.print_ident(item.ident);
                 self.word_space(":");
-                self.print_type(&t);
+                self.print_type(t);
                 self.word(";");
                 self.end(); // end the head-ibox
                 self.end() // end the outer cbox
@@ -442,7 +435,7 @@ impl<'a> State<'a> {
     ) {
         self.word_space("type");
         self.print_ident(ident);
-        self.print_generic_params(&generics.params);
+        self.print_generic_params(generics.params);
         if let Some(bounds) = bounds {
             self.print_bounds(":", bounds);
         }
@@ -463,7 +456,7 @@ impl<'a> State<'a> {
     ) {
         self.head("type");
         self.print_ident(item.ident);
-        self.print_generic_params(&generics.params);
+        self.print_generic_params(generics.params);
         self.end(); // end the inner ibox
 
         self.print_where_clause(generics);
@@ -494,7 +487,7 @@ impl<'a> State<'a> {
                 self.end(); // end inner head-block
                 self.end(); // end outer head-block
             }
-            hir::ItemKind::Use(ref path, kind) => {
+            hir::ItemKind::Use(path, kind) => {
                 self.head("use");
                 self.print_path(path, false);
 
@@ -513,14 +506,14 @@ impl<'a> State<'a> {
                 self.end(); // end inner head-block
                 self.end(); // end outer head-block
             }
-            hir::ItemKind::Static(ref ty, m, expr) => {
+            hir::ItemKind::Static(ty, m, expr) => {
                 self.head("static");
                 if m == hir::Mutability::Mut {
                     self.word_space("mut");
                 }
                 self.print_ident(item.ident);
                 self.word_space(":");
-                self.print_type(&ty);
+                self.print_type(ty);
                 self.space();
                 self.end(); // end the head-ibox
 
@@ -529,11 +522,11 @@ impl<'a> State<'a> {
                 self.word(";");
                 self.end(); // end the outer cbox
             }
-            hir::ItemKind::Const(ref ty, expr) => {
+            hir::ItemKind::Const(ty, expr) => {
                 self.head("const");
                 self.print_ident(item.ident);
                 self.word_space(":");
-                self.print_type(&ty);
+                self.print_type(ty);
                 self.space();
                 self.end(); // end the head-ibox
 
@@ -542,10 +535,10 @@ impl<'a> State<'a> {
                 self.word(";");
                 self.end(); // end the outer cbox
             }
-            hir::ItemKind::Fn(ref sig, ref param_names, body) => {
+            hir::ItemKind::Fn(ref sig, param_names, body) => {
                 self.head("");
                 self.print_fn(
-                    &sig.decl,
+                    sig.decl,
                     sig.header,
                     Some(item.ident.name),
                     param_names,
@@ -578,22 +571,22 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::GlobalAsm(ref asm) => {
+            hir::ItemKind::GlobalAsm(asm) => {
                 self.head("global_asm!");
                 self.print_inline_asm(asm);
                 self.end()
             }
-            hir::ItemKind::TyAlias(ref ty, ref generics) => {
-                self.print_item_type(item, &generics, |state| {
+            hir::ItemKind::TyAlias(ty, generics) => {
+                self.print_item_type(item, generics, |state| {
                     state.word_space("=");
-                    state.print_type(&ty);
+                    state.print_type(ty);
                 });
             }
             hir::ItemKind::OpaqueTy(ref opaque_ty) => {
-                self.print_item_type(item, &opaque_ty.generics, |state| {
+                self.print_item_type(item, opaque_ty.generics, |state| {
                     let mut real_bounds = Vec::with_capacity(opaque_ty.bounds.len());
-                    for b in opaque_ty.bounds.iter() {
-                        if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                    for b in opaque_ty.bounds {
+                        if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
                             state.space();
                             state.word_space("for ?");
                             state.print_trait_ref(&ptr.trait_ref);
@@ -604,39 +597,39 @@ impl<'a> State<'a> {
                     state.print_bounds("= impl", real_bounds);
                 });
             }
-            hir::ItemKind::Enum(ref enum_definition, ref params) => {
+            hir::ItemKind::Enum(ref enum_definition, params) => {
                 self.print_enum_def(enum_definition, params, item.ident.name, item.span);
             }
-            hir::ItemKind::Struct(ref struct_def, ref generics) => {
+            hir::ItemKind::Struct(ref struct_def, generics) => {
                 self.head("struct");
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
-            hir::ItemKind::Union(ref struct_def, ref generics) => {
+            hir::ItemKind::Union(ref struct_def, generics) => {
                 self.head("union");
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
-            hir::ItemKind::Impl(hir::Impl {
+            hir::ItemKind::Impl(&hir::Impl {
                 unsafety,
                 polarity,
                 defaultness,
                 constness,
                 defaultness_span: _,
-                ref generics,
+                generics,
                 ref of_trait,
-                ref self_ty,
+                self_ty,
                 items,
             }) => {
                 self.head("");
-                self.print_defaultness(*defaultness);
-                self.print_unsafety(*unsafety);
+                self.print_defaultness(defaultness);
+                self.print_unsafety(unsafety);
                 self.word_nbsp("impl");
 
                 if !generics.params.is_empty() {
-                    self.print_generic_params(&generics.params);
+                    self.print_generic_params(generics.params);
                     self.space();
                 }
 
-                if *constness == hir::Constness::Const {
+                if constness == hir::Constness::Const {
                     self.word_nbsp("const");
                 }
 
@@ -644,33 +637,33 @@ impl<'a> State<'a> {
                     self.word("!");
                 }
 
-                if let Some(ref t) = of_trait {
+                if let Some(t) = of_trait {
                     self.print_trait_ref(t);
                     self.space();
                     self.word_space("for");
                 }
 
-                self.print_type(&self_ty);
+                self.print_type(self_ty);
                 self.print_where_clause(generics);
 
                 self.space();
                 self.bopen();
                 self.print_inner_attributes(attrs);
-                for impl_item in *items {
+                for impl_item in items {
                     self.ann.nested(self, Nested::ImplItem(impl_item.id));
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, trait_items) => {
+            hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, trait_items) => {
                 self.head("");
                 self.print_is_auto(is_auto);
                 self.print_unsafety(unsafety);
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
+                self.print_generic_params(generics.params);
                 let mut real_bounds = Vec::with_capacity(bounds.len());
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                for b in bounds {
+                    if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
                         self.space();
                         self.word_space("for ?");
                         self.print_trait_ref(&ptr.trait_ref);
@@ -687,14 +680,14 @@ impl<'a> State<'a> {
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
+            hir::ItemKind::TraitAlias(generics, bounds) => {
                 self.head("trait");
                 self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
+                self.print_generic_params(generics.params);
                 let mut real_bounds = Vec::with_capacity(bounds.len());
                 // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
+                for b in bounds {
+                    if let GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = b {
                         self.space();
                         self.word_space("for ?");
                         self.print_trait_ref(&ptr.trait_ref);
@@ -714,7 +707,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) {
-        self.print_path(&t.path, false)
+        self.print_path(t.path, false);
     }
 
     fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
@@ -726,8 +719,8 @@ impl<'a> State<'a> {
     }
 
     fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
-        self.print_formal_generic_params(&t.bound_generic_params);
-        self.print_trait_ref(&t.trait_ref)
+        self.print_formal_generic_params(t.bound_generic_params);
+        self.print_trait_ref(&t.trait_ref);
     }
 
     pub fn print_enum_def(
@@ -739,10 +732,10 @@ impl<'a> State<'a> {
     ) {
         self.head("enum");
         self.print_name(name);
-        self.print_generic_params(&generics.params);
+        self.print_generic_params(generics.params);
         self.print_where_clause(generics);
         self.space();
-        self.print_variants(&enum_definition.variants, span)
+        self.print_variants(enum_definition.variants, span);
     }
 
     pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) {
@@ -776,7 +769,7 @@ impl<'a> State<'a> {
         print_finalizer: bool,
     ) {
         self.print_name(name);
-        self.print_generic_params(&generics.params);
+        self.print_generic_params(generics.params);
         match struct_def {
             hir::VariantData::Tuple(..) | hir::VariantData::Unit(..) => {
                 if let hir::VariantData::Tuple(..) = struct_def {
@@ -784,7 +777,7 @@ impl<'a> State<'a> {
                     self.commasep(Inconsistent, struct_def.fields(), |s, field| {
                         s.maybe_print_comment(field.span.lo());
                         s.print_outer_attributes(s.attrs(field.hir_id));
-                        s.print_type(&field.ty)
+                        s.print_type(field.ty);
                     });
                     self.pclose();
                 }
@@ -807,7 +800,7 @@ impl<'a> State<'a> {
                     self.print_outer_attributes(self.attrs(field.hir_id));
                     self.print_ident(field.ident);
                     self.word_nbsp(":");
-                    self.print_type(&field.ty);
+                    self.print_type(field.ty);
                     self.word(",");
                 }
 
@@ -819,7 +812,7 @@ impl<'a> State<'a> {
     pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
         self.head("");
         let generics = hir::Generics::empty();
-        self.print_struct(&v.data, &generics, v.ident.name, v.span, false);
+        self.print_struct(&v.data, generics, v.ident.name, v.span, false);
         if let Some(ref d) = v.disr_expr {
             self.space();
             self.word_space("=");
@@ -834,7 +827,7 @@ impl<'a> State<'a> {
         arg_names: &[Ident],
         body_id: Option<hir::BodyId>,
     ) {
-        self.print_fn(&m.decl, m.header, Some(ident.name), generics, arg_names, body_id)
+        self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id);
     }
 
     pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
@@ -843,28 +836,23 @@ impl<'a> State<'a> {
         self.maybe_print_comment(ti.span.lo());
         self.print_outer_attributes(self.attrs(ti.hir_id()));
         match ti.kind {
-            hir::TraitItemKind::Const(ref ty, default) => {
-                self.print_associated_const(ti.ident, &ty, default);
+            hir::TraitItemKind::Const(ty, default) => {
+                self.print_associated_const(ti.ident, ty, default);
             }
-            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref arg_names)) => {
-                self.print_method_sig(ti.ident, sig, &ti.generics, arg_names, None);
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => {
+                self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None);
                 self.word(";");
             }
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
                 self.head("");
-                self.print_method_sig(ti.ident, sig, &ti.generics, &[], Some(body));
+                self.print_method_sig(ti.ident, sig, ti.generics, &[], Some(body));
                 self.nbsp();
                 self.end(); // need to close a box
                 self.end(); // need to close a box
                 self.ann.nested(self, Nested::Body(body));
             }
-            hir::TraitItemKind::Type(ref bounds, ref default) => {
-                self.print_associated_type(
-                    ti.ident,
-                    &ti.generics,
-                    Some(bounds),
-                    default.as_ref().map(|ty| &**ty),
-                );
+            hir::TraitItemKind::Type(bounds, default) => {
+                self.print_associated_type(ti.ident, ti.generics, Some(bounds), default);
             }
         }
         self.ann.post(self, AnnNode::SubItem(ti.hir_id()))
@@ -877,19 +865,19 @@ impl<'a> State<'a> {
         self.print_outer_attributes(self.attrs(ii.hir_id()));
 
         match ii.kind {
-            hir::ImplItemKind::Const(ref ty, expr) => {
-                self.print_associated_const(ii.ident, &ty, Some(expr));
+            hir::ImplItemKind::Const(ty, expr) => {
+                self.print_associated_const(ii.ident, ty, Some(expr));
             }
             hir::ImplItemKind::Fn(ref sig, body) => {
                 self.head("");
-                self.print_method_sig(ii.ident, sig, &ii.generics, &[], Some(body));
+                self.print_method_sig(ii.ident, sig, ii.generics, &[], Some(body));
                 self.nbsp();
                 self.end(); // need to close a box
                 self.end(); // need to close a box
                 self.ann.nested(self, Nested::Body(body));
             }
-            hir::ImplItemKind::TyAlias(ref ty) => {
-                self.print_associated_type(ii.ident, &ii.generics, None, Some(ty));
+            hir::ImplItemKind::TyAlias(ty) => {
+                self.print_associated_type(ii.ident, ii.generics, None, Some(ty));
             }
         }
         self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
@@ -904,10 +892,10 @@ impl<'a> State<'a> {
         decl(self);
         self.end();
 
-        if let Some(ref init) = init {
+        if let Some(init) = init {
             self.nbsp();
             self.word_space("=");
-            self.print_expr(&init);
+            self.print_expr(init);
         }
         self.end()
     }
@@ -915,17 +903,17 @@ impl<'a> State<'a> {
     pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
-            hir::StmtKind::Local(ref loc) => {
-                self.print_local(loc.init, |this| this.print_local_decl(&loc));
+            hir::StmtKind::Local(loc) => {
+                self.print_local(loc.init, |this| this.print_local_decl(loc));
             }
             hir::StmtKind::Item(item) => self.ann.nested(self, Nested::Item(item)),
-            hir::StmtKind::Expr(ref expr) => {
+            hir::StmtKind::Expr(expr) => {
                 self.space_if_not_bol();
-                self.print_expr(&expr);
+                self.print_expr(expr);
             }
-            hir::StmtKind::Semi(ref expr) => {
+            hir::StmtKind::Semi(expr) => {
                 self.space_if_not_bol();
-                self.print_expr(&expr);
+                self.print_expr(expr);
                 self.word(";");
             }
         }
@@ -966,9 +954,9 @@ impl<'a> State<'a> {
         for st in blk.stmts {
             self.print_stmt(st);
         }
-        if let Some(ref expr) = blk.expr {
+        if let Some(expr) = blk.expr {
             self.space_if_not_bol();
-            self.print_expr(&expr);
+            self.print_expr(expr);
             self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
         }
         self.bclose_maybe_open(blk.span, close_box);
@@ -979,21 +967,21 @@ impl<'a> State<'a> {
         if let Some(els_inner) = els {
             match els_inner.kind {
                 // Another `else if` block.
-                hir::ExprKind::If(ref i, ref then, ref e) => {
+                hir::ExprKind::If(i, then, e) => {
                     self.cbox(INDENT_UNIT - 1);
                     self.ibox(0);
                     self.word(" else if ");
-                    self.print_expr_as_cond(&i);
+                    self.print_expr_as_cond(i);
                     self.space();
-                    self.print_expr(&then);
-                    self.print_else(e.as_ref().map(|e| &**e))
+                    self.print_expr(then);
+                    self.print_else(e);
                 }
                 // Final `else` block.
-                hir::ExprKind::Block(ref b, _) => {
+                hir::ExprKind::Block(b, _) => {
                     self.cbox(INDENT_UNIT - 1);
                     self.ibox(0);
                     self.word(" else ");
-                    self.print_block(&b)
+                    self.print_block(b);
                 }
                 // Constraints would be great here!
                 _ => {
@@ -1048,7 +1036,7 @@ impl<'a> State<'a> {
         if needs_par {
             self.popen();
         }
-        if let hir::ExprKind::DropTemps(ref actual_expr) = expr.kind {
+        if let hir::ExprKind::DropTemps(actual_expr) = expr.kind {
             self.print_expr(actual_expr);
         } else {
             self.print_expr(expr);
@@ -1114,7 +1102,7 @@ impl<'a> State<'a> {
         &mut self,
         qpath: &hir::QPath<'_>,
         fields: &[hir::ExprField<'_>],
-        wth: &Option<&hir::Expr<'_>>,
+        wth: Option<&hir::Expr<'_>>,
     ) {
         self.print_qpath(qpath, true);
         self.word("{");
@@ -1127,28 +1115,24 @@ impl<'a> State<'a> {
                     s.print_ident(field.ident);
                     s.word_space(":");
                 }
-                s.print_expr(&field.expr);
+                s.print_expr(field.expr);
                 s.end()
             },
             |f| f.span,
         );
-        match *wth {
-            Some(ref expr) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.word(",");
-                    self.space();
-                }
-                self.word("..");
-                self.print_expr(&expr);
-                self.end();
-            }
-            _ => {
-                if !fields.is_empty() {
-                    self.word(",")
-                }
+        if let Some(expr) = wth {
+            self.ibox(INDENT_UNIT);
+            if !fields.is_empty() {
+                self.word(",");
+                self.space();
             }
+            self.word("..");
+            self.print_expr(expr);
+            self.end();
+        } else if !fields.is_empty() {
+            self.word(",");
         }
+
         self.word("}");
     }
 
@@ -1249,18 +1233,17 @@ impl<'a> State<'a> {
             Options(ast::InlineAsmOptions),
         }
 
-        let mut args =
-            vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&asm.template))];
+        let mut args = vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(asm.template))];
         args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
         if !asm.options.is_empty() {
             args.push(AsmArg::Options(asm.options));
         }
 
         self.popen();
-        self.commasep(Consistent, &args, |s, arg| match arg {
-            AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
-            AsmArg::Operand(op) => match op {
-                hir::InlineAsmOperand::In { reg, expr } => {
+        self.commasep(Consistent, &args, |s, arg| match *arg {
+            AsmArg::Template(ref template) => s.print_string(template, ast::StrStyle::Cooked),
+            AsmArg::Operand(op) => match *op {
+                hir::InlineAsmOperand::In { reg, ref expr } => {
                     s.word("in");
                     s.popen();
                     s.word(format!("{}", reg));
@@ -1268,8 +1251,8 @@ impl<'a> State<'a> {
                     s.space();
                     s.print_expr(expr);
                 }
-                hir::InlineAsmOperand::Out { reg, late, expr } => {
-                    s.word(if *late { "lateout" } else { "out" });
+                hir::InlineAsmOperand::Out { reg, late, ref expr } => {
+                    s.word(if late { "lateout" } else { "out" });
                     s.popen();
                     s.word(format!("{}", reg));
                     s.pclose();
@@ -1279,16 +1262,16 @@ impl<'a> State<'a> {
                         None => s.word("_"),
                     }
                 }
-                hir::InlineAsmOperand::InOut { reg, late, expr } => {
-                    s.word(if *late { "inlateout" } else { "inout" });
+                hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
+                    s.word(if late { "inlateout" } else { "inout" });
                     s.popen();
                     s.word(format!("{}", reg));
                     s.pclose();
                     s.space();
                     s.print_expr(expr);
                 }
-                hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
-                    s.word(if *late { "inlateout" } else { "inout" });
+                hir::InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => {
+                    s.word(if late { "inlateout" } else { "inout" });
                     s.popen();
                     s.word(format!("{}", reg));
                     s.pclose();
@@ -1301,17 +1284,17 @@ impl<'a> State<'a> {
                         None => s.word("_"),
                     }
                 }
-                hir::InlineAsmOperand::Const { anon_const } => {
+                hir::InlineAsmOperand::Const { ref anon_const } => {
                     s.word("const");
                     s.space();
                     s.print_anon_const(anon_const);
                 }
-                hir::InlineAsmOperand::SymFn { anon_const } => {
+                hir::InlineAsmOperand::SymFn { ref anon_const } => {
                     s.word("sym_fn");
                     s.space();
                     s.print_anon_const(anon_const);
                 }
-                hir::InlineAsmOperand::SymStatic { path, def_id: _ } => {
+                hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => {
                     s.word("sym_static");
                     s.space();
                     s.print_qpath(path, true);
@@ -1363,57 +1346,57 @@ impl<'a> State<'a> {
         self.ibox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Expr(expr));
         match expr.kind {
-            hir::ExprKind::Box(ref expr) => {
+            hir::ExprKind::Box(expr) => {
                 self.word_space("box");
                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
             }
-            hir::ExprKind::Array(ref exprs) => {
+            hir::ExprKind::Array(exprs) => {
                 self.print_expr_vec(exprs);
             }
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 self.print_expr_anon_const(anon_const);
             }
-            hir::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(&element, count);
+            hir::ExprKind::Repeat(element, ref count) => {
+                self.print_expr_repeat(element, count);
             }
-            hir::ExprKind::Struct(ref qpath, fields, ref wth) => {
+            hir::ExprKind::Struct(qpath, fields, wth) => {
                 self.print_expr_struct(qpath, fields, wth);
             }
-            hir::ExprKind::Tup(ref exprs) => {
+            hir::ExprKind::Tup(exprs) => {
                 self.print_expr_tup(exprs);
             }
-            hir::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(&func, args);
+            hir::ExprKind::Call(func, args) => {
+                self.print_expr_call(func, args);
             }
-            hir::ExprKind::MethodCall(ref segment, ref args, _) => {
+            hir::ExprKind::MethodCall(segment, args, _) => {
                 self.print_expr_method_call(segment, args);
             }
-            hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, &lhs, &rhs);
+            hir::ExprKind::Binary(op, lhs, rhs) => {
+                self.print_expr_binary(op, lhs, rhs);
             }
-            hir::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, &expr);
+            hir::ExprKind::Unary(op, expr) => {
+                self.print_expr_unary(op, expr);
             }
-            hir::ExprKind::AddrOf(k, m, ref expr) => {
-                self.print_expr_addr_of(k, m, &expr);
+            hir::ExprKind::AddrOf(k, m, expr) => {
+                self.print_expr_addr_of(k, m, expr);
             }
             hir::ExprKind::Lit(ref lit) => {
-                self.print_literal(&lit);
+                self.print_literal(lit);
             }
-            hir::ExprKind::Cast(ref expr, ref ty) => {
+            hir::ExprKind::Cast(expr, ty) => {
                 let prec = AssocOp::As.precedence() as i8;
-                self.print_expr_maybe_paren(&expr, prec);
+                self.print_expr_maybe_paren(expr, prec);
                 self.space();
                 self.word_space("as");
-                self.print_type(&ty);
+                self.print_type(ty);
             }
-            hir::ExprKind::Type(ref expr, ref ty) => {
+            hir::ExprKind::Type(expr, ty) => {
                 let prec = AssocOp::Colon.precedence() as i8;
-                self.print_expr_maybe_paren(&expr, prec);
+                self.print_expr_maybe_paren(expr, prec);
                 self.word_space(":");
-                self.print_type(&ty);
+                self.print_type(ty);
             }
-            hir::ExprKind::DropTemps(ref init) => {
+            hir::ExprKind::DropTemps(init) => {
                 // Print `{`:
                 self.cbox(INDENT_UNIT);
                 self.ibox(0);
@@ -1431,25 +1414,25 @@ impl<'a> State<'a> {
                 // Print `}`:
                 self.bclose_maybe_open(expr.span, true);
             }
-            hir::ExprKind::Let(hir::Let { pat, ty, init, .. }) => {
-                self.print_let(pat, *ty, init);
+            hir::ExprKind::Let(&hir::Let { pat, ty, init, .. }) => {
+                self.print_let(pat, ty, init);
             }
-            hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
+            hir::ExprKind::If(test, blk, elseopt) => {
+                self.print_if(test, blk, elseopt);
             }
-            hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
+            hir::ExprKind::Loop(blk, opt_label, _, _) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
                 self.head("loop");
-                self.print_block(&blk);
+                self.print_block(blk);
             }
-            hir::ExprKind::Match(ref expr, arms, _) => {
+            hir::ExprKind::Match(expr, arms, _) => {
                 self.cbox(INDENT_UNIT);
                 self.ibox(INDENT_UNIT);
                 self.word_nbsp("match");
-                self.print_expr_as_cond(&expr);
+                self.print_expr_as_cond(expr);
                 self.space();
                 self.bopen();
                 for arm in arms {
@@ -1460,7 +1443,7 @@ impl<'a> State<'a> {
             hir::ExprKind::Closure {
                 capture_clause,
                 bound_generic_params,
-                ref fn_decl,
+                fn_decl,
                 body,
                 fn_decl_span: _,
                 movability: _,
@@ -1468,7 +1451,7 @@ impl<'a> State<'a> {
                 self.print_formal_generic_params(bound_generic_params);
                 self.print_capture_clause(capture_clause);
 
-                self.print_closure_params(&fn_decl, body);
+                self.print_closure_params(fn_decl, body);
                 self.space();
 
                 // This is a bare expression.
@@ -1480,7 +1463,7 @@ impl<'a> State<'a> {
                 // empty box to satisfy the close.
                 self.ibox(0);
             }
-            hir::ExprKind::Block(ref blk, opt_label) => {
+            hir::ExprKind::Block(blk, opt_label) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
                     self.word_space(":");
@@ -1489,42 +1472,42 @@ impl<'a> State<'a> {
                 self.cbox(INDENT_UNIT);
                 // head-box, will be closed by print-block after `{`
                 self.ibox(0);
-                self.print_block(&blk);
+                self.print_block(blk);
             }
-            hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
+            hir::ExprKind::Assign(lhs, rhs, _) => {
                 let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(&lhs, prec + 1);
+                self.print_expr_maybe_paren(lhs, prec + 1);
                 self.space();
                 self.word_space("=");
-                self.print_expr_maybe_paren(&rhs, prec);
+                self.print_expr_maybe_paren(rhs, prec);
             }
-            hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+            hir::ExprKind::AssignOp(op, lhs, rhs) => {
                 let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(&lhs, prec + 1);
+                self.print_expr_maybe_paren(lhs, prec + 1);
                 self.space();
                 self.word(op.node.as_str());
                 self.word_space("=");
-                self.print_expr_maybe_paren(&rhs, prec);
+                self.print_expr_maybe_paren(rhs, prec);
             }
-            hir::ExprKind::Field(ref expr, ident) => {
+            hir::ExprKind::Field(expr, ident) => {
                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.word(".");
                 self.print_ident(ident);
             }
-            hir::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX);
+            hir::ExprKind::Index(expr, index) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
                 self.word("[");
-                self.print_expr(&index);
+                self.print_expr(index);
                 self.word("]");
             }
             hir::ExprKind::Path(ref qpath) => self.print_qpath(qpath, true),
-            hir::ExprKind::Break(destination, ref opt_expr) => {
+            hir::ExprKind::Break(destination, opt_expr) => {
                 self.word("break");
                 if let Some(label) = destination.label {
                     self.space();
                     self.print_ident(label.ident);
                 }
-                if let Some(ref expr) = *opt_expr {
+                if let Some(expr) = opt_expr {
                     self.space();
                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
                 }
@@ -1536,20 +1519,20 @@ impl<'a> State<'a> {
                     self.print_ident(label.ident);
                 }
             }
-            hir::ExprKind::Ret(ref result) => {
+            hir::ExprKind::Ret(result) => {
                 self.word("return");
-                if let Some(ref expr) = *result {
+                if let Some(expr) = result {
                     self.word(" ");
-                    self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
                 }
             }
-            hir::ExprKind::InlineAsm(ref asm) => {
+            hir::ExprKind::InlineAsm(asm) => {
                 self.word("asm!");
                 self.print_inline_asm(asm);
             }
-            hir::ExprKind::Yield(ref expr, _) => {
+            hir::ExprKind::Yield(expr, _) => {
                 self.word_space("yield");
-                self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
+                self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
             }
             hir::ExprKind::Err => {
                 self.popen();
@@ -1562,10 +1545,10 @@ impl<'a> State<'a> {
     }
 
     pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) {
-        self.print_pat(&loc.pat);
-        if let Some(ref ty) = loc.ty {
+        self.print_pat(loc.pat);
+        if let Some(ty) = loc.ty {
             self.word_space(":");
-            self.print_type(&ty);
+            self.print_type(ty);
         }
     }
 
@@ -1596,8 +1579,8 @@ impl<'a> State<'a> {
 
     pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) {
         match *qpath {
-            hir::QPath::Resolved(None, ref path) => self.print_path(path, colons_before_params),
-            hir::QPath::Resolved(Some(ref qself), ref path) => {
+            hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params),
+            hir::QPath::Resolved(Some(qself), path) => {
                 self.word("<");
                 self.print_type(qself);
                 self.space();
@@ -1627,11 +1610,11 @@ impl<'a> State<'a> {
                     colons_before_params,
                 )
             }
-            hir::QPath::TypeRelative(ref qself, ref item_segment) => {
+            hir::QPath::TypeRelative(qself, item_segment) => {
                 // If we've got a compound-qualified-path, let's push an additional pair of angle
                 // brackets, so that we pretty-print `<<A::B>::C>` as `<A::B>::C`, instead of just
                 // `A::B::C` (since the latter could be ambiguous to the user)
-                if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = &qself.kind {
+                if let hir::TyKind::Path(hir::QPath::Resolved(None, _)) = qself.kind {
                     self.print_type(qself);
                 } else {
                     self.word("<");
@@ -1663,7 +1646,7 @@ impl<'a> State<'a> {
     ) {
         if generic_args.parenthesized {
             self.word("(");
-            self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(&ty));
+            self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(ty));
             self.word(")");
 
             self.space_if_not_bol();
@@ -1694,7 +1677,7 @@ impl<'a> State<'a> {
                 start_or_comma(self);
                 self.commasep(
                     Inconsistent,
-                    &generic_args.args,
+                    generic_args.args,
                     |s, generic_arg| match generic_arg {
                         GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
                         GenericArg::Lifetime(_) => {}
@@ -1712,7 +1695,7 @@ impl<'a> State<'a> {
                 self.word("..");
             }
 
-            for binding in generic_args.bindings.iter() {
+            for binding in generic_args.bindings {
                 start_or_comma(self);
                 self.print_type_binding(binding);
             }
@@ -1731,7 +1714,7 @@ impl<'a> State<'a> {
             hir::TypeBindingKind::Equality { ref term } => {
                 self.word_space("=");
                 match term {
-                    Term::Ty(ref ty) => self.print_type(ty),
+                    Term::Ty(ty) => self.print_type(ty),
                     Term::Const(ref c) => self.print_anon_const(c),
                 }
             }
@@ -1748,7 +1731,7 @@ impl<'a> State<'a> {
         // is that it doesn't matter
         match pat.kind {
             PatKind::Wild => self.word("_"),
-            PatKind::Binding(binding_mode, _, ident, ref sub) => {
+            PatKind::Binding(binding_mode, _, ident, sub) => {
                 match binding_mode {
                     hir::BindingAnnotation::Ref => {
                         self.word_nbsp("ref");
@@ -1764,33 +1747,33 @@ impl<'a> State<'a> {
                     }
                 }
                 self.print_ident(ident);
-                if let Some(ref p) = *sub {
+                if let Some(p) = sub {
                     self.word("@");
-                    self.print_pat(&p);
+                    self.print_pat(p);
                 }
             }
-            PatKind::TupleStruct(ref qpath, ref elts, ddpos) => {
+            PatKind::TupleStruct(ref qpath, elts, ddpos) => {
                 self.print_qpath(qpath, true);
                 self.popen();
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p));
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
                     }
                     self.word("..");
                     if ddpos != elts.len() {
                         self.word(",");
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p));
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts, |s, p| s.print_pat(&p));
+                    self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
                 }
                 self.pclose();
             }
             PatKind::Path(ref qpath) => {
                 self.print_qpath(qpath, true);
             }
-            PatKind::Struct(ref qpath, ref fields, etc) => {
+            PatKind::Struct(ref qpath, fields, etc) => {
                 self.print_qpath(qpath, true);
                 self.nbsp();
                 self.word("{");
@@ -1800,14 +1783,14 @@ impl<'a> State<'a> {
                 }
                 self.commasep_cmnt(
                     Consistent,
-                    &fields,
+                    fields,
                     |s, f| {
                         s.cbox(INDENT_UNIT);
                         if !f.is_shorthand {
                             s.print_ident(f.ident);
                             s.word_nbsp(":");
                         }
-                        s.print_pat(&f.pat);
+                        s.print_pat(f.pat);
                         s.end()
                     },
                     |f| f.pat.span,
@@ -1823,58 +1806,58 @@ impl<'a> State<'a> {
                 }
                 self.word("}");
             }
-            PatKind::Or(ref pats) => {
-                self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(&p));
+            PatKind::Or(pats) => {
+                self.strsep("|", true, Inconsistent, pats, |s, p| s.print_pat(p));
             }
-            PatKind::Tuple(ref elts, ddpos) => {
+            PatKind::Tuple(elts, ddpos) => {
                 self.popen();
                 if let Some(ddpos) = ddpos {
-                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p));
+                    self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
                     if ddpos != 0 {
                         self.word_space(",");
                     }
                     self.word("..");
                     if ddpos != elts.len() {
                         self.word(",");
-                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p));
+                        self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
                     }
                 } else {
-                    self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p));
+                    self.commasep(Inconsistent, elts, |s, p| s.print_pat(p));
                     if elts.len() == 1 {
                         self.word(",");
                     }
                 }
                 self.pclose();
             }
-            PatKind::Box(ref inner) => {
+            PatKind::Box(inner) => {
                 let is_range_inner = matches!(inner.kind, PatKind::Range(..));
                 self.word("box ");
                 if is_range_inner {
                     self.popen();
                 }
-                self.print_pat(&inner);
+                self.print_pat(inner);
                 if is_range_inner {
                     self.pclose();
                 }
             }
-            PatKind::Ref(ref inner, mutbl) => {
+            PatKind::Ref(inner, mutbl) => {
                 let is_range_inner = matches!(inner.kind, PatKind::Range(..));
                 self.word("&");
                 self.word(mutbl.prefix_str());
                 if is_range_inner {
                     self.popen();
                 }
-                self.print_pat(&inner);
+                self.print_pat(inner);
                 if is_range_inner {
                     self.pclose();
                 }
             }
-            PatKind::Lit(ref e) => self.print_expr(&e),
-            PatKind::Range(ref begin, ref end, ref end_kind) => {
+            PatKind::Lit(e) => self.print_expr(e),
+            PatKind::Range(begin, end, end_kind) => {
                 if let Some(expr) = begin {
                     self.print_expr(expr);
                 }
-                match *end_kind {
+                match end_kind {
                     RangeEnd::Included => self.word("..."),
                     RangeEnd::Excluded => self.word(".."),
                 }
@@ -1882,24 +1865,24 @@ impl<'a> State<'a> {
                     self.print_expr(expr);
                 }
             }
-            PatKind::Slice(ref before, ref slice, ref after) => {
+            PatKind::Slice(before, slice, after) => {
                 self.word("[");
-                self.commasep(Inconsistent, &before, |s, p| s.print_pat(&p));
-                if let Some(ref p) = *slice {
+                self.commasep(Inconsistent, before, |s, p| s.print_pat(p));
+                if let Some(p) = slice {
                     if !before.is_empty() {
                         self.word_space(",");
                     }
                     if let PatKind::Wild = p.kind {
                         // Print nothing.
                     } else {
-                        self.print_pat(&p);
+                        self.print_pat(p);
                     }
                     self.word("..");
                     if !after.is_empty() {
                         self.word_space(",");
                     }
                 }
-                self.commasep(Inconsistent, &after, |s, p| s.print_pat(&p));
+                self.commasep(Inconsistent, after, |s, p| s.print_pat(p));
                 self.word("]");
             }
         }
@@ -1908,7 +1891,7 @@ impl<'a> State<'a> {
 
     pub fn print_param(&mut self, arg: &hir::Param<'_>) {
         self.print_outer_attributes(self.attrs(arg.hir_id));
-        self.print_pat(&arg.pat);
+        self.print_pat(arg.pat);
     }
 
     pub fn print_arm(&mut self, arm: &hir::Arm<'_>) {
@@ -1920,32 +1903,32 @@ impl<'a> State<'a> {
         self.cbox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Arm(arm));
         self.ibox(0);
-        self.print_outer_attributes(&self.attrs(arm.hir_id));
-        self.print_pat(&arm.pat);
+        self.print_outer_attributes(self.attrs(arm.hir_id));
+        self.print_pat(arm.pat);
         self.space();
         if let Some(ref g) = arm.guard {
-            match g {
+            match *g {
                 hir::Guard::If(e) => {
                     self.word_space("if");
-                    self.print_expr(&e);
+                    self.print_expr(e);
                     self.space();
                 }
-                hir::Guard::IfLet(hir::Let { pat, ty, init, .. }) => {
+                hir::Guard::IfLet(&hir::Let { pat, ty, init, .. }) => {
                     self.word_nbsp("if");
-                    self.print_let(pat, *ty, init);
+                    self.print_let(pat, ty, init);
                 }
             }
         }
         self.word_space("=>");
 
         match arm.body.kind {
-            hir::ExprKind::Block(ref blk, opt_label) => {
+            hir::ExprKind::Block(blk, opt_label) => {
                 if let Some(label) = opt_label {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
                 // the block will close the pattern's ibox
-                self.print_block_unclosed(&blk);
+                self.print_block_unclosed(blk);
 
                 // If it is a user-provided unsafe block, print a comma after it
                 if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = blk.rules
@@ -1955,7 +1938,7 @@ impl<'a> State<'a> {
             }
             _ => {
                 self.end(); // close the ibox for the pattern
-                self.print_expr(&arm.body);
+                self.print_expr(arm.body);
                 self.word(",");
             }
         }
@@ -1978,13 +1961,13 @@ impl<'a> State<'a> {
             self.nbsp();
             self.print_name(name);
         }
-        self.print_generic_params(&generics.params);
+        self.print_generic_params(generics.params);
 
         self.popen();
         let mut i = 0;
         // Make sure we aren't supplied *both* `arg_names` and `body_id`.
         assert!(arg_names.is_empty() || body_id.is_none());
-        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+        self.commasep(Inconsistent, decl.inputs, |s, ty| {
             s.ibox(INDENT_UNIT);
             if let Some(arg_name) = arg_names.get(i) {
                 s.word(arg_name.to_string());
@@ -2011,7 +1994,7 @@ impl<'a> State<'a> {
     fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) {
         self.word("|");
         let mut i = 0;
-        self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+        self.commasep(Inconsistent, decl.inputs, |s, ty| {
             s.ibox(INDENT_UNIT);
 
             s.ann.nested(s, Nested::BodyParamPat(body_id, i));
@@ -2035,8 +2018,8 @@ impl<'a> State<'a> {
         self.space_if_not_bol();
         self.word_space("->");
         match decl.output {
-            hir::FnRetTy::Return(ref ty) => {
-                self.print_type(&ty);
+            hir::FnRetTy::Return(ty) => {
+                self.print_type(ty);
                 self.maybe_print_comment(ty.span.lo());
             }
             hir::FnRetTy::DefaultReturn(..) => unreachable!(),
@@ -2107,20 +2090,20 @@ impl<'a> State<'a> {
 
         match param.kind {
             GenericParamKind::Lifetime { .. } => {}
-            GenericParamKind::Type { ref default, .. } => {
+            GenericParamKind::Type { default, .. } => {
                 if let Some(default) = default {
                     self.space();
                     self.word_space("=");
-                    self.print_type(&default)
+                    self.print_type(default);
                 }
             }
-            GenericParamKind::Const { ref ty, ref default } => {
+            GenericParamKind::Const { ty, ref default } => {
                 self.word_space(":");
                 self.print_type(ty);
-                if let Some(ref default) = default {
+                if let Some(default) = default {
                     self.space();
                     self.word_space("=");
-                    self.print_anon_const(&default)
+                    self.print_anon_const(default);
                 }
             }
         }
@@ -2143,7 +2126,7 @@ impl<'a> State<'a> {
                 self.word_space(",");
             }
 
-            match predicate {
+            match *predicate {
                 hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
                     bound_generic_params,
                     bounded_ty,
@@ -2151,11 +2134,11 @@ impl<'a> State<'a> {
                     ..
                 }) => {
                     self.print_formal_generic_params(bound_generic_params);
-                    self.print_type(&bounded_ty);
-                    self.print_bounds(":", *bounds);
+                    self.print_type(bounded_ty);
+                    self.print_bounds(":", bounds);
                 }
                 hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
-                    lifetime,
+                    ref lifetime,
                     bounds,
                     ..
                 }) => {
@@ -2200,7 +2183,7 @@ impl<'a> State<'a> {
 
     pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) {
         self.print_mutability(mt.mutbl, print_const);
-        self.print_type(&mt.ty)
+        self.print_type(mt.ty);
     }
 
     pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) {
@@ -2213,11 +2196,11 @@ impl<'a> State<'a> {
         self.word_space("->");
         match decl.output {
             hir::FnRetTy::DefaultReturn(..) => unreachable!(),
-            hir::FnRetTy::Return(ref ty) => self.print_type(&ty),
+            hir::FnRetTy::Return(ty) => self.print_type(ty),
         }
         self.end();
 
-        if let hir::FnRetTy::Return(ref output) = decl.output {
+        if let hir::FnRetTy::Return(output) = decl.output {
             self.maybe_print_comment(output.span.lo());
         }
     }
@@ -2243,7 +2226,7 @@ impl<'a> State<'a> {
                 asyncness: hir::IsAsync::NotAsync,
             },
             name,
-            &generics,
+            generics,
             arg_names,
             None,
         );
@@ -2312,7 +2295,7 @@ fn stmt_ends_with_semi(stmt: &hir::StmtKind<'_>) -> bool {
     match *stmt {
         hir::StmtKind::Local(_) => true,
         hir::StmtKind::Item(_) => false,
-        hir::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(&e),
+        hir::StmtKind::Expr(e) => expr_requires_semi_to_be_stmt(e),
         hir::StmtKind::Semi(..) => false,
     }
 }
@@ -2351,22 +2334,22 @@ fn contains_exterior_struct_lit(value: &hir::Expr<'_>) -> bool {
     match value.kind {
         hir::ExprKind::Struct(..) => true,
 
-        hir::ExprKind::Assign(ref lhs, ref rhs, _)
-        | hir::ExprKind::AssignOp(_, ref lhs, ref rhs)
-        | hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
+        hir::ExprKind::Assign(lhs, rhs, _)
+        | hir::ExprKind::AssignOp(_, lhs, rhs)
+        | hir::ExprKind::Binary(_, lhs, rhs) => {
             // `X { y: 1 } + X { y: 2 }`
-            contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
+            contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
         }
-        hir::ExprKind::Unary(_, ref x)
-        | hir::ExprKind::Cast(ref x, _)
-        | hir::ExprKind::Type(ref x, _)
-        | hir::ExprKind::Field(ref x, _)
-        | hir::ExprKind::Index(ref x, _) => {
+        hir::ExprKind::Unary(_, x)
+        | hir::ExprKind::Cast(x, _)
+        | hir::ExprKind::Type(x, _)
+        | hir::ExprKind::Field(x, _)
+        | hir::ExprKind::Index(x, _) => {
             // `&X { y: 1 }, X { y: 1 }.y`
-            contains_exterior_struct_lit(&x)
+            contains_exterior_struct_lit(x)
         }
 
-        hir::ExprKind::MethodCall(.., ref exprs, _) => {
+        hir::ExprKind::MethodCall(.., exprs, _) => {
             // `X { y: 1 }.bar(...)`
             contains_exterior_struct_lit(&exprs[0])
         }
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index a89b9eafaa6..93528b4514b 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -75,7 +75,7 @@ pub fn assert_dep_graph(tcx: TyCtxt<'_>) {
             let mut visitor =
                 IfThisChanged { tcx, if_this_changed: vec![], then_this_would_need: vec![] };
             visitor.process_attrs(hir::CRATE_HIR_ID);
-            tcx.hir().deep_visit_all_item_likes(&mut visitor);
+            tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
             (visitor.if_this_changed, visitor.then_this_would_need)
         };
 
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 9c325faae80..f59d8d596b9 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -161,19 +161,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
                 Decodable::decode(&mut work_product_decoder);
 
             for swp in work_products {
-                let mut all_files_exist = true;
-                let path = in_incr_comp_dir_sess(sess, &swp.work_product.saved_file);
-                if !path.exists() {
-                    all_files_exist = false;
-
-                    if sess.opts.debugging_opts.incremental_info {
-                        eprintln!(
-                            "incremental: could not find file for work \
-                                    product: {}",
-                            path.display()
-                        );
+                let all_files_exist = swp.work_product.saved_files.iter().all(|(_, path)| {
+                    let exists = in_incr_comp_dir_sess(sess, path).exists();
+                    if !exists && sess.opts.debugging_opts.incremental_info {
+                        eprintln!("incremental: could not find file for work product: {path}",);
                     }
-                }
+                    exists
+                });
 
                 if all_files_exist {
                     debug!("reconcile_work_products: all files for {:?} exist", swp);
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 79836d66011..4059b7cfc8e 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -108,16 +108,17 @@ pub fn save_work_product_index(
     for (id, wp) in previous_work_products.iter() {
         if !new_work_products.contains_key(id) {
             work_product::delete_workproduct_files(sess, wp);
-            debug_assert!(!in_incr_comp_dir_sess(sess, &wp.saved_file).exists());
+            debug_assert!(
+                !wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
+            );
         }
     }
 
     // Check that we did not delete one of the current work-products:
     debug_assert!({
-        new_work_products
-            .iter()
-            .map(|(_, wp)| in_incr_comp_dir_sess(sess, &wp.saved_file))
-            .all(|path| path.exists())
+        new_work_products.iter().all(|(_, wp)| {
+            wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
+        })
     });
 }
 
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index 4789c0f581f..1b184eca964 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -3,6 +3,7 @@
 //! [work products]: WorkProduct
 
 use crate::persist::fs::*;
+use rustc_data_structures::stable_map::FxHashMap;
 use rustc_fs_util::link_or_copy;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_session::Session;
@@ -13,38 +14,41 @@ use std::path::Path;
 pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
     sess: &Session,
     cgu_name: &str,
-    path: &Path,
+    files: &[(&'static str, &Path)],
 ) -> Option<(WorkProductId, WorkProduct)> {
-    debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
+    debug!(?cgu_name, ?files);
     sess.opts.incremental.as_ref()?;
 
-    let file_name = format!("{}.o", cgu_name);
-    let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
-    let saved_file = match link_or_copy(path, &path_in_incr_dir) {
-        Ok(_) => file_name,
-        Err(err) => {
-            sess.warn(&format!(
-                "error copying object file `{}` to incremental directory as `{}`: {}",
-                path.display(),
-                path_in_incr_dir.display(),
-                err
-            ));
-            return None;
+    let mut saved_files = FxHashMap::default();
+    for (ext, path) in files {
+        let file_name = format!("{cgu_name}.{ext}");
+        let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
+        match link_or_copy(path, &path_in_incr_dir) {
+            Ok(_) => {
+                let _ = saved_files.insert(ext.to_string(), file_name);
+            }
+            Err(err) => {
+                sess.warn(&format!(
+                    "error copying object file `{}` to incremental directory as `{}`: {}",
+                    path.display(),
+                    path_in_incr_dir.display(),
+                    err
+                ));
+            }
         }
-    };
-
-    let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
+    }
 
+    let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files };
+    debug!(?work_product);
     let work_product_id = WorkProductId::from_cgu_name(cgu_name);
     Some((work_product_id, work_product))
 }
 
 /// Removes files for a given work product.
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
-    let path = in_incr_comp_dir_sess(sess, &work_product.saved_file);
-    match std_fs::remove_file(&path) {
-        Ok(()) => {}
-        Err(err) => {
+    for (_, path) in &work_product.saved_files {
+        let path = in_incr_comp_dir_sess(sess, path);
+        if let Err(err) = std_fs::remove_file(&path) {
             sess.warn(&format!(
                 "file-system error deleting outdated file `{}`: {}",
                 path.display(),
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 976874c7cee..5b664e19c18 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -1546,6 +1546,16 @@ impl<T: Idx> GrowableBitSet<T> {
         let (word_index, mask) = word_index_and_mask(elem);
         self.bit_set.words.get(word_index).map_or(false, |word| (word & mask) != 0)
     }
+
+    #[inline]
+    pub fn iter(&self) -> BitIter<'_, T> {
+        self.bit_set.iter()
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.bit_set.count()
+    }
 }
 
 impl<T: Idx> From<BitSet<T>> for GrowableBitSet<T> {
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 8938ed78a94..7120d5ad934 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -128,7 +128,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
         let region_constraints = self.with_region_constraints(|region_constraints| {
             make_query_region_constraints(
                 tcx,
-                region_obligations.iter().map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)),
+                region_obligations.iter().map(|r_o| (r_o.sup_type, r_o.sub_region)),
                 region_constraints,
             )
         });
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 67dcb6e708b..8bf1de34a9b 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -37,7 +37,7 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index e319f17b0e6..05556f7d0f9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -68,7 +68,7 @@ use rustc_middle::dep_graph::DepContext;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
     self, error::TypeError, Binder, List, Region, Subst, Ty, TyCtxt, TypeFoldable,
-    TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable,
 };
 use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
 use rustc_target::spec::abi;
@@ -148,12 +148,10 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
     tcx: TyCtxt<'tcx>,
     region: ty::Region<'tcx>,
 ) -> (String, Span) {
-    let sm = tcx.sess.source_map();
-
     let scope = region.free_region_binding_scope(tcx).expect_local();
     match *region {
         ty::ReEarlyBound(ref br) => {
-            let mut sp = sm.guess_head_span(tcx.def_span(scope));
+            let mut sp = tcx.def_span(scope);
             if let Some(param) =
                 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
             {
@@ -174,7 +172,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
             } else {
                 match fr.bound_region {
                     ty::BoundRegionKind::BrNamed(_, name) => {
-                        let mut sp = sm.guess_head_span(tcx.def_span(scope));
+                        let mut sp = tcx.def_span(scope);
                         if let Some(param) =
                             tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
                         {
@@ -193,7 +191,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                     ),
                     _ => (
                         format!("the lifetime `{}` as defined here", region),
-                        sm.guess_head_span(tcx.def_span(scope)),
+                        tcx.def_span(scope),
                     ),
                 }
             }
@@ -1540,7 +1538,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
         }
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
+        impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 07dcf3876c8..4d29fc46946 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -315,8 +315,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         body_id: Option<hir::BodyId>,
         failure_span: Span,
         arg: GenericArg<'tcx>,
-        // FIXME(#94483): Either use this or remove it.
-        _impl_candidates: Vec<ty::TraitRef<'tcx>>,
         error_code: TypeAnnotationNeeded,
         should_label_span: bool,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
@@ -534,6 +532,23 @@ enum InferSourceKind<'tcx> {
     },
 }
 
+impl<'tcx> InferSource<'tcx> {
+    fn from_expansion(&self) -> bool {
+        let source_from_expansion = match self.kind {
+            InferSourceKind::LetBinding { insert_span, .. }
+            | InferSourceKind::ClosureArg { insert_span, .. }
+            | InferSourceKind::GenericArg { insert_span, .. } => insert_span.from_expansion(),
+            InferSourceKind::FullyQualifiedMethodCall { receiver, .. } => {
+                receiver.span.from_expansion()
+            }
+            InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
+                data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
+            }
+        };
+        source_from_expansion || self.span.from_expansion()
+    }
+}
+
 impl<'tcx> InferSourceKind<'tcx> {
     fn ty_msg(&self, infcx: &InferCtxt<'_, 'tcx>) -> String {
         match *self {
@@ -604,43 +619,65 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
     /// Sources with a small cost are prefer and should result
     /// in a clearer and idiomatic suggestion.
     fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
-        let tcx = self.infcx.tcx;
-
-        fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
-            match arg.unpack() {
-                GenericArgKind::Lifetime(_) => 0, // erased
-                GenericArgKind::Type(ty) => ty_cost(ty),
-                GenericArgKind::Const(_) => 3, // some non-zero value
-            }
+        #[derive(Clone, Copy)]
+        struct CostCtxt<'tcx> {
+            tcx: TyCtxt<'tcx>,
         }
-        fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
-            match ty.kind() {
-                ty::Closure(..) => 100,
-                ty::FnDef(..) => 20,
-                ty::FnPtr(..) => 10,
-                ty::Infer(..) => 0,
-                _ => 1,
+        impl<'tcx> CostCtxt<'tcx> {
+            fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
+                match arg.unpack() {
+                    GenericArgKind::Lifetime(_) => 0, // erased
+                    GenericArgKind::Type(ty) => self.ty_cost(ty),
+                    GenericArgKind::Const(_) => 3, // some non-zero value
+                }
+            }
+            fn ty_cost(self, ty: Ty<'tcx>) -> usize {
+                match *ty.kind() {
+                    ty::Closure(..) => 1000,
+                    ty::FnDef(..) => 150,
+                    ty::FnPtr(..) => 30,
+                    ty::Adt(def, substs) => {
+                        5 + self
+                            .tcx
+                            .generics_of(def.did())
+                            .own_substs_no_defaults(self.tcx, substs)
+                            .iter()
+                            .map(|&arg| self.arg_cost(arg))
+                            .sum::<usize>()
+                    }
+                    ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
+                    ty::Ref(_, ty, _) => 2 + self.ty_cost(ty),
+                    ty::Infer(..) => 0,
+                    _ => 1,
+                }
             }
         }
 
         // The sources are listed in order of preference here.
-        match source.kind {
-            InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
-            InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
+        let tcx = self.infcx.tcx;
+        let ctx = CostCtxt { tcx };
+        let base_cost = match source.kind {
+            InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
+            InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
             InferSourceKind::GenericArg { def_id, generic_args, .. } => {
                 let variant_cost = match tcx.def_kind(def_id) {
-                    DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
-                    _ => 12,
+                    // `None::<u32>` and friends are ugly.
+                    DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
+                    _ => 10,
                 };
-                variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
+                variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
             }
             InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
-                20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
+                20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
             }
             InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
-                30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
+                30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
             }
-        }
+        };
+
+        let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 };
+
+        base_cost + suggestion_may_apply
     }
 
     /// Uses `fn source_cost` to determine whether this inference source is preferable to
@@ -648,6 +685,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
         let cost = self.source_cost(&new_source) + self.attempt;
+        debug!(?cost);
         self.attempt += 1;
         if cost < self.infer_source_cost {
             self.infer_source_cost = cost;
@@ -655,6 +693,11 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         }
     }
 
+    fn node_substs_opt(&self, hir_id: HirId) -> Option<SubstsRef<'tcx>> {
+        let substs = self.typeck_results.node_substs_opt(hir_id);
+        self.infcx.resolve_vars_if_possible(substs)
+    }
+
     fn opt_node_type(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
         let ty = self.typeck_results.node_type_opt(hir_id);
         self.infcx.resolve_vars_if_possible(ty)
@@ -737,7 +780,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         let tcx = self.infcx.tcx;
         match expr.kind {
             hir::ExprKind::Path(ref path) => {
-                if let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id) {
+                if let Some(substs) = self.node_substs_opt(expr.hir_id) {
                     return self.path_inferred_subst_iter(expr.hir_id, substs, path);
                 }
             }
@@ -765,7 +808,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
                         if generics.has_impl_trait() {
                             None?
                         }
-                        let substs = self.typeck_results.node_substs_opt(expr.hir_id)?;
+                        let substs = self.node_substs_opt(expr.hir_id)?;
                         let span = tcx.hir().span(segment.hir_id?);
                         let insert_span = segment.ident.span.shrink_to_hi().with_hi(span.hi());
                         InsertableGenericArgs {
@@ -980,8 +1023,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             debug!(?args);
             let InsertableGenericArgs { insert_span, substs, generics_def_id, def_id } = args;
             let generics = tcx.generics_of(generics_def_id);
-            if let Some(argument_index) =
-                generics.own_substs(substs).iter().position(|&arg| self.generic_arg_is_target(arg))
+            if let Some(argument_index) = generics
+                .own_substs(substs)
+                .iter()
+                .position(|&arg| self.generic_arg_contains_target(arg))
             {
                 let substs = self.infcx.resolve_vars_if_possible(substs);
                 let generic_args = &generics.own_substs_no_defaults(tcx, substs)
@@ -1037,7 +1082,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             .any(|generics| generics.has_impl_trait())
         };
         if let ExprKind::MethodCall(path, args, span) = expr.kind
-            && let Some(substs) = self.typeck_results.node_substs_opt(expr.hir_id)
+            && let Some(substs) = self.node_substs_opt(expr.hir_id)
             && substs.iter().any(|arg| self.generic_arg_contains_target(arg))
             && let Some(def_id) = self.typeck_results.type_dependent_def_id(expr.hir_id)
             && self.infcx.tcx.trait_of_item(def_id).is_some()
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 09430a135a3..02928c4aa57 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -10,7 +10,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
 use rustc_middle::ty::{
-    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
+    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index f6b49e41d4c..91bf9695dfc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::print::RegionHighlightMode;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::{Span, Symbol};
 
 use std::ops::ControlFlow;
@@ -88,7 +88,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
         }
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
+        impl<'tcx> ty::visit::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if !r.has_name() && self.counter <= 3 {
                     self.highlight.highlighting_region(r, self.counter);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 42d52446ab6..b356da0be55 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::TyCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeVisitable};
 use rustc_span::Span;
 
 /// Information about the anonymous region we are searching for.
@@ -142,7 +142,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
     fn includes_region(
         &self,
-        ty: Binder<'tcx, impl TypeFoldable<'tcx>>,
+        ty: Binder<'tcx, impl TypeVisitable<'tcx>>,
         region: ty::BoundRegionKind,
     ) -> bool {
         let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 082eb1bf111..d566634a492 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -4,8 +4,7 @@
 //! and use that to decide when one free region outlives another, and so forth.
 
 use rustc_data_structures::transitive_relation::TransitiveRelation;
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, Lift, Region, TyCtxt};
+use rustc_middle::ty::{Lift, Region, TyCtxt};
 
 /// Combines a `FreeRegionMap` and a `TyCtxt`.
 ///
@@ -14,16 +13,13 @@ use rustc_middle::ty::{self, Lift, Region, TyCtxt};
 pub(crate) struct RegionRelations<'a, 'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// The context used for debug messages
-    pub context: DefId,
-
     /// Free-region relationships.
     pub free_regions: &'a FreeRegionMap<'tcx>,
 }
 
 impl<'a, 'tcx> RegionRelations<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, context: DefId, free_regions: &'a FreeRegionMap<'tcx>) -> Self {
-        Self { tcx, context, free_regions }
+    pub fn new(tcx: TyCtxt<'tcx>, free_regions: &'a FreeRegionMap<'tcx>) -> Self {
+        Self { tcx, free_regions }
     }
 
     pub fn lub_free_regions(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> Region<'tcx> {
@@ -53,7 +49,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
     // (with the exception that `'static: 'x` is not notable)
     pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
         debug!("relate_regions(sub={:?}, sup={:?})", sub, sup);
-        if self.is_free_or_static(sub) && self.is_free(sup) {
+        if sub.is_free_or_static() && sup.is_free() {
             self.relation.add(sub, sup)
         }
     }
@@ -72,7 +68,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
         r_a: Region<'tcx>,
         r_b: Region<'tcx>,
     ) -> bool {
-        assert!(self.is_free_or_static(r_a) && self.is_free_or_static(r_b));
+        assert!(r_a.is_free_or_static() && r_b.is_free_or_static());
         let re_static = tcx.lifetimes.re_static;
         if self.check_relation(re_static, r_b) {
             // `'a <= 'static` is always true, and not stored in the
@@ -89,20 +85,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
         r_a == r_b || self.relation.contains(r_a, r_b)
     }
 
-    /// True for free regions other than `'static`.
-    pub fn is_free(&self, r: Region<'_>) -> bool {
-        matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_))
-    }
-
-    /// True if `r` is a free region or static of the sort that this
-    /// free region map can be used with.
-    pub fn is_free_or_static(&self, r: Region<'_>) -> bool {
-        match *r {
-            ty::ReStatic => true,
-            _ => self.is_free(r),
-        }
-    }
-
     /// Computes the least-upper-bound of two free regions. In some
     /// cases, this is more conservative than necessary, in order to
     /// avoid making arbitrary choices. See
@@ -114,8 +96,8 @@ impl<'tcx> FreeRegionMap<'tcx> {
         r_b: Region<'tcx>,
     ) -> Region<'tcx> {
         debug!("lub_free_regions(r_a={:?}, r_b={:?})", r_a, r_b);
-        assert!(self.is_free(r_a));
-        assert!(self.is_free(r_b));
+        assert!(r_a.is_free());
+        assert!(r_b.is_free());
         let result = if r_a == r_b {
             r_a
         } else {
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 024f7409947..84004d2b21f 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -34,7 +34,7 @@ use super::InferCtxt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::infer::unify_key::ToType;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable};
 use std::collections::hash_map::Entry;
 
 pub struct TypeFreshener<'a, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index c82685d1b70..12c44b4baaa 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -34,31 +34,27 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
         T: Relate<'tcx>,
     {
         let span = self.trace.cause.span;
+        // First, we instantiate each bound region in the supertype with a
+        // fresh placeholder region. Note that this automatically creates
+        // a new universe if needed.
+        let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
 
-        self.infcx.commit_if_ok(|_| {
-            // First, we instantiate each bound region in the supertype with a
-            // fresh placeholder region. Note that this automatically creates
-            // a new universe if needed.
-            let sup_prime = self.infcx.replace_bound_vars_with_placeholders(sup);
+        // Next, we instantiate each bound region in the subtype
+        // with a fresh region variable. These region variables --
+        // but no other pre-existing region variables -- can name
+        // the placeholders.
+        let sub_prime = self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
 
-            // Next, we instantiate each bound region in the subtype
-            // with a fresh region variable. These region variables --
-            // but no other pre-existing region variables -- can name
-            // the placeholders.
-            let sub_prime =
-                self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, sub);
+        debug!("a_prime={:?}", sub_prime);
+        debug!("b_prime={:?}", sup_prime);
 
-            debug!("a_prime={:?}", sub_prime);
-            debug!("b_prime={:?}", sup_prime);
+        // Compare types now that bound regions have been replaced.
+        let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
 
-            // Compare types now that bound regions have been replaced.
-            let result = self.sub(sub_is_expected).relate(sub_prime, sup_prime)?;
-
-            debug!("higher_ranked_sub: OK result={result:?}");
-            // NOTE: returning the result here would be dangerous as it contains
-            // placeholders which **must not** be named afterwards.
-            Ok(())
-        })
+        debug!("OK result={result:?}");
+        // NOTE: returning the result here would be dangerous as it contains
+        // placeholders which **must not** be named afterwards.
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 68c709a2e24..3783cfb4cc5 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -47,7 +47,6 @@ pub(crate) fn resolve<'tcx>(
 #[derive(Clone)]
 pub struct LexicalRegionResolutions<'tcx> {
     pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
-    pub(crate) error_region: ty::Region<'tcx>,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -120,13 +119,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     ) -> LexicalRegionResolutions<'tcx> {
         let mut var_data = self.construct_var_data(self.tcx());
 
-        // Dorky hack to cause `dump_constraints` to only get called
-        // if debug mode is enabled:
-        debug!(
-            "----() End constraint listing (context={:?}) {:?}---",
-            self.region_rels.context,
-            self.dump_constraints(self.region_rels)
-        );
+        if cfg!(debug_assertions) {
+            self.dump_constraints();
+        }
 
         let graph = self.construct_graph();
         self.expand_givens(&graph);
@@ -144,7 +139,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     /// empty region. The `expansion` phase will grow this larger.
     fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
         LexicalRegionResolutions {
-            error_region: tcx.lifetimes.re_static,
             values: IndexVec::from_fn_n(
                 |vid| {
                     let vid_universe = self.var_infos[vid].universe;
@@ -156,8 +150,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
     }
 
-    fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) {
-        debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context);
+    #[instrument(level = "debug", skip(self))]
+    fn dump_constraints(&self) {
         for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
             debug!("Constraint {} => {:?}", idx, constraint);
         }
@@ -314,7 +308,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
         // Check for the case where we know that `'b: 'static` -- in that case,
         // `a <= b` for all `a`.
-        let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
+        let b_free_or_static = b.is_free_or_static();
         if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
             return true;
         }
@@ -324,7 +318,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         // `lub` relationship defined below, since sometimes the "lub"
         // is actually the `postdom_upper_bound` (see
         // `TransitiveRelation` for more details).
-        let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
+        let a_free_or_static = a.is_free_or_static();
         if a_free_or_static && b_free_or_static {
             return sub_free_regions(a, b);
         }
@@ -868,10 +862,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
     where
         T: TypeFoldable<'tcx>,
     {
-        tcx.fold_regions(value, |r, _db| match *r {
-            ty::ReVar(rid) => self.resolve_var(rid),
-            _ => r,
-        })
+        tcx.fold_regions(value, |r, _db| self.resolve_region(tcx, r))
     }
 
     fn value(&self, rid: RegionVid) -> &VarValue<'tcx> {
@@ -882,12 +873,19 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
         &mut self.values[rid]
     }
 
-    pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> {
-        let result = match self.values[rid] {
-            VarValue::Value(r) => r,
-            VarValue::ErrorValue => self.error_region,
+    pub(crate) fn resolve_region(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        let result = match *r {
+            ty::ReVar(rid) => match self.values[rid] {
+                VarValue::Value(r) => r,
+                VarValue::ErrorValue => tcx.lifetimes.re_static,
+            },
+            _ => r,
         };
-        debug!("resolve_var({:?}) = {:?}", rid, result);
+        debug!("resolve_region({:?}) = {:?}", r, result);
         result
     }
 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 6f88b83a473..28f037cc61a 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -15,7 +15,6 @@ use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
 use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
-use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
@@ -26,6 +25,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
+use rustc_middle::ty::visit::TypeVisitable;
 pub use rustc_middle::ty::IntVarValue;
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid};
@@ -147,7 +147,7 @@ pub struct InferCtxtInner<'tcx> {
     /// for each body-id in this map, which will process the
     /// obligations within. This is expected to be done 'late enough'
     /// that all type inference variables have been bound and so forth.
-    region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
+    region_obligations: Vec<RegionObligation<'tcx>>,
 
     undo_log: InferCtxtUndoLogs<'tcx>,
 
@@ -171,7 +171,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
     }
 
     #[inline]
-    pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] {
+    pub fn region_obligations(&self) -> &[RegionObligation<'tcx>] {
         &self.region_obligations
     }
 
@@ -319,7 +319,7 @@ pub struct InferCtxt<'a, 'tcx> {
 }
 
 /// See the `error_reporting` module for more details.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
 pub enum ValuePairs<'tcx> {
     Regions(ExpectedFound<ty::Region<'tcx>>),
     Terms(ExpectedFound<ty::Term<'tcx>>),
@@ -466,9 +466,6 @@ pub enum NllRegionVariableOrigin {
     /// from a `for<'a> T` binder). Meant to represent "any region".
     Placeholder(ty::PlaceholderRegion),
 
-    /// The variable we create to represent `'empty(U0)`.
-    RootEmptyRegion,
-
     Existential {
         /// If this is true, then this variable was created to represent a lifetime
         /// bound in a `for` binder. For example, it might have been created to
@@ -891,6 +888,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             .region_constraints_added_in_snapshot(&snapshot.undo_snapshot)
     }
 
+    pub fn opaque_types_added_in_snapshot(&self, snapshot: &CombinedSnapshot<'a, 'tcx>) -> bool {
+        self.inner.borrow().undo_log.opaque_types_in_snapshot(&snapshot.undo_snapshot)
+    }
+
     pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) {
         self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup);
     }
@@ -1250,7 +1251,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
 
         let lexical_region_resolutions = LexicalRegionResolutions {
-            error_region: self.tcx.lifetimes.re_static,
             values: rustc_index::vec::IndexVec::from_elem_n(
                 crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
                 var_infos.len(),
@@ -1267,7 +1267,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// `resolve_vars_if_possible` as well as `fully_resolve`.
     pub fn resolve_regions(
         &self,
-        region_context: DefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
     ) -> Vec<RegionResolutionError<'tcx>> {
         let (var_infos, data) = {
@@ -1286,8 +1285,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 .into_infos_and_data()
         };
 
-        let region_rels =
-            &RegionRelations::new(self.tcx, region_context, outlives_env.free_region_map());
+        let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map());
 
         let (lexical_region_resolutions, errors) =
             lexical_region_resolve::resolve(outlives_env.param_env, region_rels, var_infos, data);
@@ -1302,12 +1300,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// result. After this, no more unification operations should be
     /// done -- or the compiler will panic -- but it is legal to use
     /// `resolve_vars_if_possible` as well as `fully_resolve`.
-    pub fn resolve_regions_and_report_errors(
-        &self,
-        region_context: DefId,
-        outlives_env: &OutlivesEnvironment<'tcx>,
-    ) {
-        let errors = self.resolve_regions(region_context, outlives_env);
+    pub fn resolve_regions_and_report_errors(&self, outlives_env: &OutlivesEnvironment<'tcx>) {
+        let errors = self.resolve_regions(outlives_env);
 
         if !self.is_tainted_by_errors() {
             // As a heuristic, just skip reporting region errors
@@ -1445,7 +1439,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     /// `resolve_vars_if_possible()`.
     pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)>
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         value.visit_with(&mut resolve::UnresolvedTypeFinder::new(self)).break_value()
     }
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 846e7f7b921..bab4f3e9e36 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -27,8 +27,8 @@ use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use rustc_span::Span;
 use std::fmt::Debug;
@@ -810,7 +810,7 @@ struct ScopeInstantiator<'me, 'tcx> {
 }
 
 impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(
+    fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index cc36d6a0a4f..f11701bba6f 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -9,7 +9,8 @@ use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::subst::{GenericArgKind, Subst};
 use rustc_middle::ty::{
-    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+    self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitor,
 };
 use rustc_span::Span;
 
@@ -94,7 +95,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         }
         let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
-            ty::Opaque(def_id, substs) => {
+            ty::Opaque(def_id, substs) if def_id.is_local() => {
                 let origin = if self.defining_use_anchor.is_some() {
                     // Check that this is `impl Trait` type is
                     // declared by `parent_def_id` -- i.e., one whose
@@ -461,7 +462,7 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
-    fn visit_binder<T: TypeFoldable<'tcx>>(
+    fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index 5ea096f5cc2..7234660dbcd 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -4,7 +4,7 @@
 
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 use smallvec::{smallvec, SmallVec};
 
 #[derive(Debug)]
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index 9ddda7b92eb..b897de7315a 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -1,8 +1,6 @@
 use crate::infer::free_regions::FreeRegionMap;
 use crate::infer::{GenericKind, InferCtxt};
 use crate::traits::query::OutlivesBound;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
 use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
 
 use super::explicit_outlives_bounds;
@@ -31,9 +29,7 @@ pub struct OutlivesEnvironment<'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
     free_region_map: FreeRegionMap<'tcx>,
 
-    // Contains, for each body B that we are checking (that is, the fn
-    // item, but also any nested closures), the set of implied region
-    // bounds that are in scope in that particular body.
+    // Contains the implied region bounds in scope for our current body.
     //
     // Example:
     //
@@ -43,24 +39,15 @@ pub struct OutlivesEnvironment<'tcx> {
     // } // body B0
     // ```
     //
-    // Here, for body B0, the list would be `[T: 'a]`, because we
+    // Here, when checking the body B0, the list would be `[T: 'a]`, because we
     // infer that `T` must outlive `'a` from the implied bounds on the
     // fn declaration.
     //
-    // For the body B1, the list would be `[T: 'a, T: 'b]`, because we
+    // For the body B1 however, the list would be `[T: 'a, T: 'b]`, because we
     // also can see that -- within the closure body! -- `T` must
     // outlive `'b`. This is not necessarily true outside the closure
     // body, since the closure may never be called.
-    //
-    // We collect this map as we descend the tree. We then use the
-    // results when proving outlives obligations like `T: 'x` later
-    // (e.g., if `T: 'x` must be proven within the body B1, then we
-    // know it is true if either `'a: 'x` or `'b: 'x`).
-    region_bound_pairs_map: FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
-
-    // Used to compute `region_bound_pairs_map`: contains the set of
-    // in-scope region-bound pairs thus far.
-    region_bound_pairs_accum: RegionBoundPairs<'tcx>,
+    region_bound_pairs: RegionBoundPairs<'tcx>,
 }
 
 /// "Region-bound pairs" tracks outlives relations that are known to
@@ -73,8 +60,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
         let mut env = OutlivesEnvironment {
             param_env,
             free_region_map: Default::default(),
-            region_bound_pairs_map: Default::default(),
-            region_bound_pairs_accum: vec![],
+            region_bound_pairs: Default::default(),
         };
 
         env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
@@ -87,62 +73,9 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
         &self.free_region_map
     }
 
-    /// Borrows current value of the `region_bound_pairs`.
-    pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>> {
-        &self.region_bound_pairs_map
-    }
-
-    /// This is a hack to support the old-school regionck, which
-    /// processes region constraints from the main function and the
-    /// closure together. In that context, when we enter a closure, we
-    /// want to be able to "save" the state of the surrounding a
-    /// function. We can then add implied bounds and the like from the
-    /// closure arguments into the environment -- these should only
-    /// apply in the closure body, so once we exit, we invoke
-    /// `pop_snapshot_post_typeck_child` to remove them.
-    ///
-    /// Example:
-    ///
-    /// ```ignore (pseudo-rust)
-    /// fn foo<T>() {
-    ///    callback(for<'a> |x: &'a T| {
-    ///         // ^^^^^^^ not legal syntax, but probably should be
-    ///         // within this closure body, `T: 'a` holds
-    ///    })
-    /// }
-    /// ```
-    ///
-    /// This "containment" of closure's effects only works so well. In
-    /// particular, we (intentionally) leak relationships between free
-    /// regions that are created by the closure's bounds. The case
-    /// where this is useful is when you have (e.g.) a closure with a
-    /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this
-    /// case, we want to keep the relationship `'b: 'a` in the
-    /// free-region-map, so that later if we have to take `LUB('b,
-    /// 'a)` we can get the result `'b`.
-    ///
-    /// I have opted to keep **all modifications** to the
-    /// free-region-map, however, and not just those that concern free
-    /// variables bound in the closure. The latter seems more correct,
-    /// but it is not the existing behavior, and I could not find a
-    /// case where the existing behavior went wrong. In any case, it
-    /// seems like it'd be readily fixed if we wanted. There are
-    /// similar leaks around givens that seem equally suspicious, to
-    /// be honest. --nmatsakis
-    pub fn push_snapshot_pre_typeck_child(&self) -> usize {
-        self.region_bound_pairs_accum.len()
-    }
-
-    /// See `push_snapshot_pre_typeck_child`.
-    pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
-        self.region_bound_pairs_accum.truncate(len);
-    }
-
-    /// Save the current set of region-bound pairs under the given `body_id`.
-    pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
-        let old =
-            self.region_bound_pairs_map.insert(body_id, self.region_bound_pairs_accum.clone());
-        assert!(old.is_none());
+    /// Borrows current `region_bound_pairs`.
+    pub fn region_bound_pairs(&self) -> &RegionBoundPairs<'tcx> {
+        &self.region_bound_pairs
     }
 
     /// Processes outlives bounds that are known to hold, whether from implied or other sources.
@@ -164,11 +97,10 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
             debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
             match outlives_bound {
                 OutlivesBound::RegionSubParam(r_a, param_b) => {
-                    self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b)));
+                    self.region_bound_pairs.push((r_a, GenericKind::Param(param_b)));
                 }
                 OutlivesBound::RegionSubProjection(r_a, projection_b) => {
-                    self.region_bound_pairs_accum
-                        .push((r_a, GenericKind::Projection(projection_b)));
+                    self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b)));
                 }
                 OutlivesBound::RegionSubRegion(r_a, r_b) => {
                     if let (ReEarlyBound(_) | ReFree(_), ReVar(vid_b)) = (r_a.kind(), r_b.kind()) {
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 1c1906f3375..59cf39abe64 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -60,18 +60,16 @@
 //! imply that `'b: 'a`.
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
+use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::{
     self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
 };
 use crate::traits::{ObligationCause, ObligationCauseCode};
-use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
-
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::undo_log::UndoLogs;
-use rustc_hir as hir;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeVisitable};
 use smallvec::smallvec;
 
 impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
@@ -80,16 +78,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// and later processed by regionck, when full type information is
     /// available (see `region_obligations` field for more
     /// information).
-    pub fn register_region_obligation(
-        &self,
-        body_id: hir::HirId,
-        obligation: RegionObligation<'tcx>,
-    ) {
-        debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation);
-
+    #[instrument(level = "debug", skip(self))]
+    pub fn register_region_obligation(&self, obligation: RegionObligation<'tcx>) {
         let mut inner = self.inner.borrow_mut();
         inner.undo_log.push(UndoLog::PushRegionObligation);
-        inner.region_obligations.push((body_id, obligation));
+        inner.region_obligations.push(obligation);
     }
 
     pub fn register_region_obligation_with_cause(
@@ -109,14 +102,11 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
             )
         });
 
-        self.register_region_obligation(
-            cause.body_id,
-            RegionObligation { sup_type, sub_region, origin },
-        );
+        self.register_region_obligation(RegionObligation { sup_type, sub_region, origin });
     }
 
     /// Trait queries just want to pass back type obligations "as is"
-    pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> {
+    pub fn take_registered_region_obligations(&self) -> Vec<RegionObligation<'tcx>> {
         std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
@@ -144,10 +134,10 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
     /// - `param_env` is the parameter environment for the enclosing function.
     /// - `body_id` is the body-id whose region obligations are being
     ///   processed.
-    #[instrument(level = "debug", skip(self, region_bound_pairs_map))]
+    #[instrument(level = "debug", skip(self, region_bound_pairs))]
     pub fn process_registered_region_obligations(
         &self,
-        region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>,
+        region_bound_pairs: &RegionBoundPairs<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) {
         assert!(
@@ -157,7 +147,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
         let my_region_obligations = self.take_registered_region_obligations();
 
-        for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations {
+        for RegionObligation { sup_type, sub_region, origin } in my_region_obligations {
             debug!(
                 "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}",
                 sup_type, sub_region, origin
@@ -165,18 +155,23 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
             let sup_type = self.resolve_vars_if_possible(sup_type);
 
-            if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) {
-                let outlives =
-                    &mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
-                outlives.type_must_outlive(origin, sup_type, sub_region);
-            } else {
-                self.tcx.sess.delay_span_bug(
-                    origin.span(),
-                    &format!("no region-bound-pairs for {:?}", body_id),
-                );
-            }
+            let outlives =
+                &mut TypeOutlives::new(self, self.tcx, &region_bound_pairs, None, param_env);
+            outlives.type_must_outlive(origin, sup_type, sub_region);
         }
     }
+
+    pub fn check_region_obligations_and_report_errors(
+        &self,
+        outlives_env: &OutlivesEnvironment<'tcx>,
+    ) {
+        self.process_registered_region_obligations(
+            outlives_env.region_bound_pairs(),
+            outlives_env.param_env,
+        );
+
+        self.resolve_regions_and_report_errors(outlives_env)
+    }
 }
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 9f71ebae99e..772e297b7b4 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -1,7 +1,7 @@
 use std::collections::hash_map::Entry;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{
     self,
     error::TypeError,
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 19f83e3377a..c5747ecf702 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -165,7 +165,7 @@ pub struct Verify<'tcx> {
     pub bound: VerifyBound<'tcx>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
 pub enum GenericKind<'tcx> {
     Param(ty::ParamTy),
     Projection(ty::ProjectionTy<'tcx>),
@@ -272,7 +272,7 @@ pub enum VerifyBound<'tcx> {
 ///     }
 /// }
 /// ```
-#[derive(Debug, Copy, Clone, TypeFoldable)]
+#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable)]
 pub struct VerifyIfEq<'tcx> {
     /// Type which must match the generic `G`
     pub ty: Ty<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 1f3cb401314..3d99f0958f7 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,8 +1,9 @@
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::{FixupError, FixupResult, InferCtxt, Span};
 use rustc_middle::mir;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable, TypeVisitor};
-use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable, TypeVisitable};
 
 use std::ops::ControlFlow;
 
@@ -205,13 +206,13 @@ impl<'a, 'tcx> FallibleTypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> {
 
     fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
         match *r {
-            ty::ReVar(rid) => Ok(self
+            ty::ReVar(_) => Ok(self
                 .infcx
                 .lexical_region_resolutions
                 .borrow()
                 .as_ref()
                 .expect("region resolution not performed")
-                .resolve_var(rid)),
+                .resolve_region(self.infcx.tcx, r)),
             _ => Ok(r),
         }
     }
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index d0c6d8d16eb..b27571275b7 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -4,8 +4,8 @@ use super::SubregionOrigin;
 use crate::infer::combine::ConstEquateRelation;
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
 use crate::traits::Obligation;
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::TyVar;
 use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
 use std::mem;
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 1b696f21cbc..74a26ebc39f 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -185,6 +185,10 @@ impl<'tcx> InferCtxtUndoLogs<'tcx> {
         })
     }
 
+    pub(crate) fn opaque_types_in_snapshot(&self, s: &Snapshot<'tcx>) -> bool {
+        self.logs[s.undo_len..].iter().any(|log| matches!(log, UndoLog::OpaqueTypes(..)))
+    }
+
     pub(crate) fn region_constraints(
         &self,
     ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone {
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 4eafa3329c3..7e42458fda3 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -23,10 +23,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
 
-        if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
-            let span = self.tcx.sess.source_map().guess_head_span(trait_item_span);
+        if trait_item_def_id.is_local() {
             let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-            err.span_label(span, format!("definition of `{}` from trait", item_name));
+            err.span_label(
+                self.tcx.def_span(trait_item_def_id),
+                format!("definition of `{}` from trait", item_name),
+            );
         }
 
         err.span_label(sp, format!("impl has extra requirement {}", requirement));
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index b84ed3dc689..5d22f9f972e 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
     pub err: ty::error::TypeError<'tcx>,
 }
 
-#[derive(Clone, TypeFoldable)]
+#[derive(Clone, TypeFoldable, TypeVisitable)]
 pub struct Normalized<'tcx, T> {
     pub value: T,
     pub obligations: Vec<PredicateObligation<'tcx>>,
@@ -203,7 +203,7 @@ impl<'tcx> ProjectionCache<'_, 'tcx> {
             Some(&ProjectionCacheEntry::NormalizedTy { ref ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
-                if result == EvaluationResult::EvaluatedToOk {
+                if result.must_apply_considering_regions() {
                     ty.obligations = vec![];
                 }
                 map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) });
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 82ee4bb29e8..573d2d1e330 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,7 +1,8 @@
 use crate::traits;
 use crate::traits::project::Normalized;
 use rustc_middle::ty;
-use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable};
+use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor};
 
 use std::fmt;
 use std::ops::ControlFlow;
@@ -68,7 +69,9 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
             param_env: self.param_env.try_fold_with(folder)?,
         })
     }
+}
 
+impl<'tcx, O: TypeVisitable<'tcx>> TypeVisitable<'tcx> for traits::Obligation<'tcx, O> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.predicate.visit_with(visitor)?;
         self.param_env.visit_with(visitor)
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 502afa493fe..b7d1d6edfaa 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -14,7 +14,6 @@ use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
-use rustc_hir::Crate;
 use rustc_lint::{EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_metadata::{encode_metadata, EncodedMetadata};
@@ -482,37 +481,6 @@ pub fn configure_and_expand(
     Ok(krate)
 }
 
-fn lower_to_hir<'tcx>(
-    sess: &Session,
-    definitions: &mut Definitions,
-    cstore: &CrateStoreDyn,
-    resolutions: &ty::ResolverOutputs,
-    resolver: ty::ResolverAstLowering,
-    krate: Rc<ast::Crate>,
-    arena: &'tcx rustc_ast_lowering::Arena<'tcx>,
-) -> &'tcx Crate<'tcx> {
-    // Lower AST to HIR.
-    let hir_crate = rustc_ast_lowering::lower_crate(
-        sess,
-        &krate,
-        definitions,
-        cstore,
-        resolutions,
-        resolver,
-        arena,
-    );
-
-    // Drop AST to free memory
-    sess.time("drop_ast", || std::mem::drop(krate));
-
-    // Discard hygiene data, which isn't required after lowering to HIR.
-    if !sess.opts.debugging_opts.keep_hygiene_data {
-        rustc_span::hygiene::clear_syntax_context_map();
-    }
-
-    hir_crate
-}
-
 // Returns all the paths that correspond to generated files.
 fn generated_output_paths(
     sess: &Session,
@@ -777,6 +745,7 @@ pub fn prepare_outputs(
 pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     let providers = &mut Providers::default();
     providers.analysis = analysis;
+    providers.hir_crate = rustc_ast_lowering::lower_to_hir;
     proc_macro_decls::provide(providers);
     rustc_const_eval::provide(providers);
     rustc_middle::hir::provide(providers);
@@ -823,7 +792,7 @@ impl<'tcx> QueryContext<'tcx> {
 pub fn create_global_ctxt<'tcx>(
     compiler: &'tcx Compiler,
     lint_store: Lrc<LintStore>,
-    krate: Rc<ast::Crate>,
+    krate: Lrc<ast::Crate>,
     dep_graph: DepGraph,
     resolver: Rc<RefCell<BoxedResolver>>,
     outputs: OutputFilenames,
@@ -831,29 +800,17 @@ pub fn create_global_ctxt<'tcx>(
     queries: &'tcx OnceCell<TcxQueries<'tcx>>,
     global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
-    hir_arena: &'tcx WorkerLocal<rustc_ast_lowering::Arena<'tcx>>,
+    hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
 ) -> QueryContext<'tcx> {
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
     // incr. comp. yet.
     dep_graph.assert_ignored();
 
-    let (mut definitions, cstore, resolver_outputs, resolver_for_lowering) =
+    let (definitions, cstore, resolver_outputs, resolver_for_lowering) =
         BoxedResolver::to_resolver_outputs(resolver);
 
     let sess = &compiler.session();
-
-    // Lower AST to HIR.
-    let krate = lower_to_hir(
-        sess,
-        &mut definitions,
-        &*cstore,
-        &resolver_outputs,
-        resolver_for_lowering,
-        krate,
-        hir_arena,
-    );
-
     let query_result_on_disk_cache = rustc_incremental::load_query_result_cache(sess);
 
     let codegen_backend = compiler.codegen_backend();
@@ -877,9 +834,11 @@ pub fn create_global_ctxt<'tcx>(
                 sess,
                 lint_store,
                 arena,
+                hir_arena,
                 definitions,
                 cstore,
                 resolver_outputs,
+                resolver_for_lowering,
                 krate,
                 dep_graph,
                 queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
@@ -972,6 +931,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
             if !tcx.sess.opts.debugging_opts.thir_unsafeck {
                 rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
             }
+            tcx.ensure().has_ffi_unwind_calls(def_id);
 
             if tcx.hir().body_const_context(def_id).is_some() {
                 tcx.ensure()
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 136f0443fa0..8ffb1ad0539 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -72,13 +72,13 @@ pub struct Queries<'tcx> {
     queries: OnceCell<TcxQueries<'tcx>>,
 
     arena: WorkerLocal<Arena<'tcx>>,
-    hir_arena: WorkerLocal<rustc_ast_lowering::Arena<'tcx>>,
+    hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
 
     dep_graph_future: Query<Option<DepGraphFuture>>,
     parse: Query<ast::Crate>,
     crate_name: Query<String>,
     register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
-    expansion: Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
+    expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
     prepare_outputs: Query<OutputFilenames>,
     global_ctxt: Query<QueryContext<'tcx>>,
@@ -92,7 +92,7 @@ impl<'tcx> Queries<'tcx> {
             gcx: OnceCell::new(),
             queries: OnceCell::new(),
             arena: WorkerLocal::new(|_| Arena::default()),
-            hir_arena: WorkerLocal::new(|_| rustc_ast_lowering::Arena::default()),
+            hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
             dep_graph_future: Default::default(),
             parse: Default::default(),
             crate_name: Default::default(),
@@ -164,7 +164,7 @@ impl<'tcx> Queries<'tcx> {
 
     pub fn expansion(
         &self,
-    ) -> Result<&Query<(Rc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
+    ) -> Result<&Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>> {
         tracing::trace!("expansion");
         self.expansion.compute(|| {
             let crate_name = self.crate_name()?.peek().clone();
@@ -180,7 +180,7 @@ impl<'tcx> Queries<'tcx> {
             let krate = resolver.access(|resolver| {
                 passes::configure_and_expand(sess, &lint_store, krate, &crate_name, resolver)
             })?;
-            Ok((Rc::new(krate), Rc::new(RefCell::new(resolver)), lint_store))
+            Ok((Lrc::new(krate), Rc::new(RefCell::new(resolver)), lint_store))
         })
     }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 30a29ed6ed3..55827ff583a 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -649,6 +649,7 @@ fn test_debugging_options_tracking_hash() {
     untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
+    untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
     untracked!(dump_mir, Some(String::from("abc")));
     untracked!(dump_mir_dataflow, true);
     untracked!(dump_mir_dir, String::from("abc"));
@@ -689,7 +690,6 @@ fn test_debugging_options_tracking_hash() {
     untracked!(span_debug, true);
     untracked!(span_free_formats, true);
     untracked!(temps_dir, Some(String::from("abc")));
-    untracked!(terminal_width, Some(80));
     untracked!(threads, 99);
     untracked!(time, true);
     untracked!(time_llvm_passes, true);
@@ -733,6 +733,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(dep_info_omit_d_target, true);
     tracked!(drop_tracking, true);
     tracked!(dual_proc_macros, true);
+    tracked!(dwarf_version, Some(5));
     tracked!(fewer_names, Some(true));
     tracked!(force_unstable_if_unmarked, true);
     tracked!(fuel, Some(("abc".to_string(), 99)));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index fb9258eb4a9..8796ad5a33c 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -10,7 +10,7 @@ use rustc_errors::registry::Registry;
 use rustc_middle::ty::tls;
 use rustc_parse::validate_attr;
 #[cfg(parallel_compiler)]
-use rustc_query_impl::QueryCtxt;
+use rustc_query_impl::{QueryContext, QueryCtxt};
 use rustc_session as session;
 use rustc_session::config::CheckCfg;
 use rustc_session::config::{self, CrateType};
@@ -166,20 +166,12 @@ pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
 unsafe fn handle_deadlock() {
     let registry = rustc_rayon_core::Registry::current();
 
-    let context = tls::get_tlv();
-    assert!(context != 0);
-    rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
-    let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
-
-    let session_globals = rustc_span::with_session_globals(|sg| sg as *const _);
-    let session_globals = &*session_globals;
-    thread::spawn(move || {
-        tls::enter_context(icx, |_| {
-            rustc_span::set_session_globals_then(session_globals, || {
-                tls::with(|tcx| QueryCtxt::from_tcx(tcx).deadlock(&registry))
-            })
-        });
+    let query_map = tls::with(|tcx| {
+        QueryCtxt::from_tcx(tcx)
+            .try_collect_active_jobs()
+            .expect("active jobs shouldn't be locked in deadlock handler")
     });
+    thread::spawn(move || rustc_query_impl::deadlock(query_map, &registry));
 }
 
 #[cfg(parallel_compiler)]
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index fab60b6f609..7c0f2c440d5 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -22,3 +22,4 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_infer = { path = "../rustc_infer" }
 rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index b33ab40eb39..121fefdc620 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -1,5 +1,5 @@
 use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
@@ -120,31 +120,30 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
                 _ => bug!("array type coerced to something other than array or slice"),
             };
             cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
-                let mut diag = lint.build(&format!(
-                    "this method call resolves to `<&{} as IntoIterator>::into_iter` \
-                    (due to backwards compatibility), \
-                    but will resolve to <{} as IntoIterator>::into_iter in Rust 2021",
-                    target, target,
-                ));
+                let mut diag = lint.build(fluent::lint::array_into_iter);
+                diag.set_arg("target", target);
                 diag.span_suggestion(
                     call.ident.span,
-                    "use `.iter()` instead of `.into_iter()` to avoid ambiguity",
+                    fluent::lint::use_iter_suggestion,
                     "iter",
                     Applicability::MachineApplicable,
                 );
                 if self.for_expr_span == expr.span {
                     diag.span_suggestion(
                         receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                        "or remove `.into_iter()` to iterate by value",
+                        fluent::lint::remove_into_iter_suggestion,
                         "",
                         Applicability::MaybeIncorrect,
                     );
                 } else if receiver_ty.is_array() {
                     diag.multipart_suggestion(
-                        "or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
+                        fluent::lint::use_explicit_into_iter_suggestion,
                         vec![
                             (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
-                            (receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()), ")".into()),
+                            (
+                                receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                                ")".into(),
+                            ),
                         ],
                         Applicability::MaybeIncorrect,
                     );
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c0cf8c6b76b..a0472f98d72 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -31,14 +31,17 @@ use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::{self, expr_to_string};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_errors::{Applicability, Diagnostic, DiagnosticStyledString, MultiSpan};
+use rustc_errors::{
+    fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
+    LintDiagnosticBuilder, MultiSpan,
+};
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
 use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
 use rustc_index::vec::Idx;
-use rustc_middle::lint::{in_external_macro, LintDiagnosticBuilder};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -99,13 +102,12 @@ impl EarlyLintPass for WhileTrue {
             if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
                 if let ast::LitKind::Bool(true) = lit.kind {
                     if !lit.span.from_expansion() {
-                        let msg = "denote infinite loops with `loop { ... }`";
                         let condition_span = e.span.with_hi(cond.span.hi());
                         cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
-                            lint.build(msg)
+                            lint.build(fluent::lint::builtin_while_true)
                                 .span_suggestion_short(
                                     condition_span,
-                                    "use `loop`",
+                                    fluent::lint::suggestion,
                                     format!(
                                         "{}loop",
                                         label.map_or_else(String::new, |label| format!(
@@ -156,7 +158,7 @@ impl BoxPointers {
             if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
                 if leaf_ty.is_box() {
                     cx.struct_span_lint(BOX_POINTERS, span, |lint| {
-                        lint.build(&format!("type uses owned (Box type) pointers: {}", ty)).emit();
+                        lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
                     });
                 }
             }
@@ -257,26 +259,26 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
                         == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
                     {
                         cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
-                            let mut err = lint
-                                .build(&format!("the `{}:` in this pattern is redundant", ident));
                             let binding = match binding_annot {
                                 hir::BindingAnnotation::Unannotated => None,
                                 hir::BindingAnnotation::Mutable => Some("mut"),
                                 hir::BindingAnnotation::Ref => Some("ref"),
                                 hir::BindingAnnotation::RefMut => Some("ref mut"),
                             };
-                            let ident = if let Some(binding) = binding {
+                            let suggested_ident = if let Some(binding) = binding {
                                 format!("{} {}", binding, ident)
                             } else {
                                 ident.to_string()
                             };
-                            err.span_suggestion(
-                                fieldpat.span,
-                                "use shorthand field pattern",
-                                ident,
-                                Applicability::MachineApplicable,
-                            );
-                            err.emit();
+                            lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
+                                .set_arg("ident", ident.clone())
+                                .span_suggestion(
+                                    fieldpat.span,
+                                    fluent::lint::suggestion,
+                                    suggested_ident,
+                                    Applicability::MachineApplicable,
+                                )
+                                .emit();
                         });
                     }
                 }
@@ -327,26 +329,25 @@ impl UnsafeCode {
         cx.struct_span_lint(UNSAFE_CODE, span, decorate);
     }
 
-    fn report_overridden_symbol_name(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) {
+    fn report_overridden_symbol_name(
+        &self,
+        cx: &EarlyContext<'_>,
+        span: Span,
+        msg: DiagnosticMessage,
+    ) {
         self.report_unsafe(cx, span, |lint| {
-            lint.build(msg)
-                .note(
-                    "the linker's behavior with multiple libraries exporting duplicate symbol \
-                    names is undefined and Rust cannot provide guarantees when you manually \
-                    override them",
-                )
-                .emit();
+            lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
         })
     }
 
-    fn report_overridden_symbol_section(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) {
+    fn report_overridden_symbol_section(
+        &self,
+        cx: &EarlyContext<'_>,
+        span: Span,
+        msg: DiagnosticMessage,
+    ) {
         self.report_unsafe(cx, span, |lint| {
-            lint.build(msg)
-                .note(
-                    "the program's behavior with overridden link sections on items is unpredictable \
-                    and Rust cannot provide guarantees when you manually override them",
-                )
-                .emit();
+            lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
         })
     }
 }
@@ -355,12 +356,7 @@ impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::allow_internal_unsafe) {
             self.report_unsafe(cx, attr.span, |lint| {
-                lint.build(
-                    "`allow_internal_unsafe` allows defining \
-                                               macros using unsafe without triggering \
-                                               the `unsafe_code` lint at their call site",
-                )
-                .emit();
+                lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
             });
         }
     }
@@ -370,7 +366,7 @@ impl EarlyLintPass for UnsafeCode {
             // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
                 self.report_unsafe(cx, blk.span, |lint| {
-                    lint.build("usage of an `unsafe` block").emit();
+                    lint.build(fluent::lint::builtin_unsafe_block).emit();
                 });
             }
         }
@@ -380,12 +376,12 @@ impl EarlyLintPass for UnsafeCode {
         match it.kind {
             ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
                 .report_unsafe(cx, it.span, |lint| {
-                    lint.build("declaration of an `unsafe` trait").emit();
+                    lint.build(fluent::lint::builtin_unsafe_trait).emit();
                 }),
 
             ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
                 .report_unsafe(cx, it.span, |lint| {
-                    lint.build("implementation of an `unsafe` trait").emit();
+                    lint.build(fluent::lint::builtin_unsafe_impl).emit();
                 }),
 
             ast::ItemKind::Fn(..) => {
@@ -393,7 +389,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        "declaration of a `no_mangle` function",
+                        fluent::lint::builtin_no_mangle_fn,
                     );
                 }
 
@@ -401,7 +397,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        "declaration of a function with `export_name`",
+                        fluent::lint::builtin_export_name_fn,
                     );
                 }
 
@@ -409,7 +405,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        "declaration of a function with `link_section`",
+                        fluent::lint::builtin_link_section_fn,
                     );
                 }
             }
@@ -419,7 +415,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        "declaration of a `no_mangle` static",
+                        fluent::lint::builtin_no_mangle_static,
                     );
                 }
 
@@ -427,7 +423,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_name(
                         cx,
                         attr.span,
-                        "declaration of a static with `export_name`",
+                        fluent::lint::builtin_export_name_static,
                     );
                 }
 
@@ -435,7 +431,7 @@ impl EarlyLintPass for UnsafeCode {
                     self.report_overridden_symbol_section(
                         cx,
                         attr.span,
-                        "declaration of a static with `link_section`",
+                        fluent::lint::builtin_link_section_static,
                     );
                 }
             }
@@ -450,14 +446,14 @@ impl EarlyLintPass for UnsafeCode {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    "declaration of a `no_mangle` method",
+                    fluent::lint::builtin_no_mangle_method,
                 );
             }
             if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
                 self.report_overridden_symbol_name(
                     cx,
                     attr.span,
-                    "declaration of a method with `export_name`",
+                    fluent::lint::builtin_export_name_method,
                 );
             }
         }
@@ -475,9 +471,9 @@ impl EarlyLintPass for UnsafeCode {
         {
             let msg = match ctxt {
                 FnCtxt::Foreign => return,
-                FnCtxt::Free => "declaration of an `unsafe` function",
-                FnCtxt::Assoc(_) if body.is_none() => "declaration of an `unsafe` method",
-                FnCtxt::Assoc(_) => "implementation of an `unsafe` method",
+                FnCtxt::Free => fluent::lint::builtin_decl_unsafe_fn,
+                FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
+                FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
             };
             self.report_unsafe(cx, span, |lint| {
                 lint.build(msg).emit();
@@ -556,7 +552,6 @@ impl MissingDoc {
         &self,
         cx: &LateContext<'_>,
         def_id: LocalDefId,
-        sp: Span,
         article: &'static str,
         desc: &'static str,
     ) {
@@ -583,13 +578,12 @@ impl MissingDoc {
         let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
         let has_doc = attrs.iter().any(has_doc);
         if !has_doc {
-            cx.struct_span_lint(
-                MISSING_DOCS,
-                cx.tcx.sess.source_map().guess_head_span(sp),
-                |lint| {
-                    lint.build(&format!("missing documentation for {} {}", article, desc)).emit();
-                },
-            );
+            cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
+                lint.build(fluent::lint::builtin_missing_doc)
+                    .set_arg("article", article)
+                    .set_arg("desc", desc)
+                    .emit();
+            });
         }
     }
 }
@@ -612,13 +606,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_crate(&mut self, cx: &LateContext<'_>) {
-        self.check_missing_docs_attrs(
-            cx,
-            CRATE_DEF_ID,
-            cx.tcx.def_span(CRATE_DEF_ID),
-            "the",
-            "crate",
-        );
+        self.check_missing_docs_attrs(cx, CRATE_DEF_ID, "the", "crate");
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
@@ -648,13 +636,13 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, it.def_id, it.span, article, desc);
+        self.check_missing_docs_attrs(cx, it.def_id, article, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, trait_item.def_id, article, desc);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -682,23 +670,23 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, impl_item.def_id, article, desc);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
-        self.check_missing_docs_attrs(cx, foreign_item.def_id, foreign_item.span, article, desc);
+        self.check_missing_docs_attrs(cx, foreign_item.def_id, article, desc);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
         if !sf.is_positional() {
             let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
-            self.check_missing_docs_attrs(cx, def_id, sf.span, "a", "struct field")
+            self.check_missing_docs_attrs(cx, def_id, "a", "struct field")
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
-        self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), v.span, "a", "variant");
+        self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), "a", "variant");
     }
 }
 
@@ -783,11 +771,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         .is_ok()
         {
             cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
-                lint.build(
-                    "type could implement `Copy`; consider adding `impl \
-                          Copy`",
-                )
-                .emit();
+                lint.build(fluent::lint::builtin_missing_copy_impl).emit();
             })
         }
     }
@@ -863,12 +847,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
 
         if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
             cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
-                lint.build(&format!(
-                    "type does not implement `{}`; consider adding `#[derive(Debug)]` \
-                     or a manual implementation",
-                    cx.tcx.def_path_str(debug)
-                ))
-                .emit();
+                lint.build(fluent::lint::builtin_missing_debug_impl)
+                    .set_arg("debug", cx.tcx.def_path_str(debug))
+                    .emit();
             });
         }
     }
@@ -946,18 +927,14 @@ impl EarlyLintPass for AnonymousParameters {
                                 ("<type>", Applicability::HasPlaceholders)
                             };
 
-                            lint.build(
-                                "anonymous parameters are deprecated and will be \
-                                     removed in the next edition",
-                            )
-                            .span_suggestion(
-                                arg.pat.span,
-                                "try naming the parameter or explicitly \
-                                            ignoring it",
-                                format!("_: {}", ty_snip),
-                                appl,
-                            )
-                            .emit();
+                            lint.build(fluent::lint::builtin_anonymous_params)
+                                .span_suggestion(
+                                    arg.pat.span,
+                                    fluent::lint::suggestion,
+                                    format!("_: {}", ty_snip),
+                                    appl,
+                                )
+                                .emit();
                         })
                     }
                 }
@@ -982,24 +959,6 @@ impl DeprecatedAttr {
     }
 }
 
-fn lint_deprecated_attr(
-    cx: &EarlyContext<'_>,
-    attr: &ast::Attribute,
-    msg: &str,
-    suggestion: Option<&str>,
-) {
-    cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
-        lint.build(msg)
-            .span_suggestion_short(
-                attr.span,
-                suggestion.unwrap_or("remove this attribute"),
-                "",
-                Applicability::MachineApplicable,
-            )
-            .emit();
-    })
-}
-
 impl EarlyLintPass for DeprecatedAttr {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
@@ -1011,17 +970,38 @@ impl EarlyLintPass for DeprecatedAttr {
                     _,
                 ) = gate
                 {
-                    let msg =
-                        format!("use of deprecated attribute `{}`: {}. See {}", name, reason, link);
-                    lint_deprecated_attr(cx, attr, &msg, suggestion);
+                    cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
+                        // FIXME(davidtwco) translatable deprecated attr
+                        lint.build(fluent::lint::builtin_deprecated_attr_link)
+                            .set_arg("name", name)
+                            .set_arg("reason", reason)
+                            .set_arg("link", link)
+                            .span_suggestion_short(
+                                attr.span,
+                                suggestion.map(|s| s.into()).unwrap_or(
+                                    fluent::lint::builtin_deprecated_attr_default_suggestion,
+                                ),
+                                "",
+                                Applicability::MachineApplicable,
+                            )
+                            .emit();
+                    });
                 }
                 return;
             }
         }
         if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
-            let path_str = pprust::path_to_string(&attr.get_normal_item().path);
-            let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
-            lint_deprecated_attr(cx, attr, &msg, None);
+            cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
+                lint.build(fluent::lint::builtin_deprecated_attr_used)
+                    .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
+                    .span_suggestion_short(
+                        attr.span,
+                        fluent::lint::builtin_deprecated_attr_default_suggestion,
+                        "",
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            });
         }
     }
 }
@@ -1049,17 +1029,15 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
 
         if is_doc_comment || attr.has_name(sym::doc) {
             cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
-                let mut err = lint.build("unused doc comment");
-                err.span_label(
-                    node_span,
-                    format!("rustdoc does not generate documentation for {}", node_kind),
-                );
+                let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
+                err.set_arg("kind", node_kind);
+                err.span_label(node_span, fluent::lint::label);
                 match attr.kind {
                     AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
-                        err.help("use `//` for a plain comment");
+                        err.help(fluent::lint::plain_help);
                     }
                     AttrKind::DocComment(CommentKind::Block, _) => {
-                        err.help("use `/* */` for a plain comment");
+                        err.help(fluent::lint::block_help);
                     }
                 }
                 err.emit();
@@ -1178,10 +1156,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     GenericParamKind::Lifetime { .. } => {}
                     GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                         cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
-                            lint.build("functions generic over types or consts must be mangled")
+                            lint.build(fluent::lint::builtin_no_mangle_generic)
                                 .span_suggestion_short(
                                     no_mangle_attr.span,
-                                    "remove this attribute",
+                                    fluent::lint::suggestion,
                                     "",
                                     // Use of `#[no_mangle]` suggests FFI intent; correct
                                     // fix may be to monomorphize source by hand
@@ -1205,8 +1183,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
                     cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
-                        let msg = "const items should never be `#[no_mangle]`";
-                        let mut err = lint.build(msg);
+                        let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
 
                         // account for "pub const" (#45562)
                         let start = cx
@@ -1220,7 +1197,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                         let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
                         err.span_suggestion(
                             const_span,
-                            "try a static value",
+                            fluent::lint::suggestion,
                             "pub static",
                             Applicability::MachineApplicable,
                         );
@@ -1285,10 +1262,8 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
             if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
-                let msg = "transmuting &T to &mut T is undefined behavior, \
-                    even if the reference is unused, consider instead using an UnsafeCell";
                 cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
-                    lint.build(msg).emit();
+                    lint.build(fluent::lint::builtin_mutable_transmutes).emit();
                 });
             }
         }
@@ -1338,7 +1313,7 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
             if let Some(items) = attr.meta_item_list() {
                 for item in items {
                     cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
-                        lint.build("unstable feature").emit();
+                        lint.build(fluent::lint::builtin_unstable_features).emit();
                     });
                 }
             }
@@ -1400,16 +1375,17 @@ impl UnreachablePub {
             }
             let def_span = cx.tcx.sess.source_map().guess_head_span(span);
             cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
-                let mut err = lint.build(&format!("unreachable `pub` {}", what));
+                let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
+                err.set_arg("what", what);
 
                 err.span_suggestion(
                     vis_span,
-                    "consider restricting its visibility",
+                    fluent::lint::suggestion,
                     "pub(crate)",
                     applicability,
                 );
                 if exportable {
-                    err.help("or consider exporting it for use by other crates");
+                    err.help(fluent::lint::help);
                 }
                 err.emit();
             });
@@ -1513,11 +1489,7 @@ impl TypeAliasBounds {
         impl Visitor<'_> for WalkAssocTypes<'_> {
             fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) {
                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
-                    self.err.span_help(
-                        span,
-                        "use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to \
-                         associated types in type aliases",
-                    );
+                    self.err.span_help(span, fluent::lint::builtin_type_alias_bounds_help);
                 }
                 intravisit::walk_qpath(self, qpath, id, span)
             }
@@ -1561,11 +1533,11 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
         let mut suggested_changing_assoc_types = false;
         if !where_spans.is_empty() {
             cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
-                let mut err = lint.build("where clauses are not enforced in type aliases");
+                let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
                 err.set_span(where_spans);
                 err.span_suggestion(
                     type_alias_generics.where_clause_span,
-                    "the clause will not be checked when the type alias is used, and should be removed",
+                    fluent::lint::suggestion,
                     "",
                     Applicability::MachineApplicable,
                 );
@@ -1579,11 +1551,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
 
         if !inline_spans.is_empty() {
             cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
-                let mut err =
-                    lint.build("bounds on generic parameters are not enforced in type aliases");
+                let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
                 err.set_span(inline_spans);
                 err.multipart_suggestion(
-                    "the bound will not be checked when the type alias is used, and should be removed",
+                    fluent::lint::suggestion,
                     inline_sugg,
                     Applicability::MachineApplicable,
                 );
@@ -1664,7 +1635,7 @@ declare_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        use rustc_middle::ty::fold::TypeFoldable;
+        use rustc_middle::ty::visit::TypeVisitable;
         use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
@@ -1690,12 +1661,10 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                 };
                 if predicate.is_global() {
                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
-                        lint.build(&format!(
-                            "{} bound {} does not depend on any type \
-                                or lifetime parameters",
-                            predicate_kind_name, predicate
-                        ))
-                        .emit();
+                        lint.build(fluent::lint::builtin_trivial_bounds)
+                            .set_arg("predicate_kind_name", predicate_kind_name)
+                            .set_arg("predicate", predicate)
+                            .emit();
                     });
                 }
             }
@@ -1796,8 +1765,8 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
         };
 
         if let Some((start, end, join)) = endpoints {
-            let msg = "`...` range patterns are deprecated";
-            let suggestion = "use `..=` for an inclusive range";
+            let msg = fluent::lint::builtin_ellipsis_inclusive_range_patterns;
+            let suggestion = fluent::lint::suggestion;
             if parenthesise {
                 self.node_id = Some(pat.id);
                 let end = expr_to_string(&end);
@@ -1806,8 +1775,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                     None => format!("&(..={})", end),
                 };
                 if join.edition() >= Edition::Edition2021 {
-                    let mut err =
-                        rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
+                    let mut err = cx.sess().struct_span_err_with_code(
+                        pat.span,
+                        msg,
+                        rustc_errors::error_code!(E0783),
+                    );
                     err.span_suggestion(
                         pat.span,
                         suggestion,
@@ -1830,8 +1802,11 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
             } else {
                 let replace = "..=";
                 if join.edition() >= Edition::Edition2021 {
-                    let mut err =
-                        rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
+                    let mut err = cx.sess().struct_span_err_with_code(
+                        pat.span,
+                        msg,
+                        rustc_errors::error_code!(E0783),
+                    );
                     err.span_suggestion_short(
                         join,
                         suggestion,
@@ -1930,7 +1905,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
             cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
-                lint.build("cannot test inner items").emit();
+                lint.build(fluent::lint::builtin_unnameable_test_items).emit();
             });
         }
     }
@@ -2048,10 +2023,12 @@ impl KeywordIdents {
         }
 
         cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
-            lint.build(&format!("`{}` is a keyword in the {} edition", ident, next_edition))
+            lint.build(fluent::lint::builtin_keyword_idents)
+                .set_arg("kw", ident.clone())
+                .set_arg("next", next_edition)
                 .span_suggestion(
                     ident.span,
-                    "you can use a raw identifier to stay compatible",
+                    fluent::lint::suggestion,
                     format!("r#{}", ident),
                     Applicability::MachineApplicable,
                 )
@@ -2301,13 +2278,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
 
             if !lint_spans.is_empty() {
                 cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
-                    lint.build("outlives requirements can be inferred")
+                    lint.build(fluent::lint::builtin_explicit_outlives)
+                        .set_arg("count", bound_count)
                         .multipart_suggestion(
-                            if bound_count == 1 {
-                                "remove this bound"
-                            } else {
-                                "remove these bounds"
-                            },
+                            fluent::lint::suggestion,
                             lint_spans
                                 .into_iter()
                                 .map(|span| (span, String::new()))
@@ -2363,23 +2337,14 @@ impl EarlyLintPass for IncompleteFeatures {
             .filter(|(&name, _)| features.incomplete(name))
             .for_each(|(&name, &span)| {
                 cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
-                    let mut builder = lint.build(&format!(
-                        "the feature `{}` is incomplete and may not be safe to use \
-                         and/or cause compiler crashes",
-                        name,
-                    ));
+                    let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
+                    builder.set_arg("name", name);
                     if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
-                        builder.note(&format!(
-                            "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
-                             for more information",
-                            n, n,
-                        ));
+                        builder.set_arg("n", n);
+                        builder.note(fluent::lint::note);
                     }
                     if HAS_MIN_FEATURES.contains(&name) {
-                        builder.help(&format!(
-                            "consider using `min_{}` instead, which is more stable and complete",
-                            name,
-                        ));
+                        builder.help(fluent::lint::help);
                     }
                     builder.emit();
                 })
@@ -2620,6 +2585,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
             if let Some((msg, span)) =
                 with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
             {
+                // FIXME(davidtwco): make translatable
                 cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
                     let mut err = lint.build(&format!(
                         "the type `{}` does not permit {}",
@@ -2996,23 +2962,19 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
                             let mut found_str = DiagnosticStyledString::new();
                             found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
 
-                            lint.build(&format!(
-                                "`{}` redeclare{} with a different signature",
-                                this_fi.ident.name,
-                                if orig.get_name() == this_fi.ident.name {
-                                    "d".to_string()
-                                } else {
-                                    format!("s `{}`", orig.get_name())
-                                }
-                            ))
+                            lint.build(if orig.get_name() == this_fi.ident.name {
+                                fluent::lint::builtin_clashing_extern_same_name
+                            } else {
+                                fluent::lint::builtin_clashing_extern_diff_name
+                            })
+                            .set_arg("this_fi", this_fi.ident.name)
+                            .set_arg("orig", orig.get_name())
                             .span_label(
                                 get_relevant_span(orig_fi),
-                                &format!("`{}` previously declared here", orig.get_name()),
-                            )
-                            .span_label(
-                                get_relevant_span(this_fi),
-                                "this signature doesn't match the previous declaration",
+                                fluent::lint::previous_decl_label,
                             )
+                            .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
+                            // FIXME(davidtwco): translatable expected/found
                             .note_expected_found(&"", expected_str, &"", found_str)
                             .emit();
                         },
@@ -3096,8 +3058,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
         if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
             if is_null_ptr(cx, expr_deref) {
                 cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
-                    let mut err = lint.build("dereferencing a null pointer");
-                    err.span_label(expr.span, "this code causes undefined behavior when executed");
+                    let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
+                    err.span_label(expr.span, fluent::lint::label);
                     err.emit();
                 });
             }
@@ -3210,9 +3172,7 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
                             NAMED_ASM_LABELS,
                             Some(target_spans),
                             |diag| {
-                                let mut err =
-                                    diag.build("avoid using named labels in inline assembly");
-                                err.emit();
+                                diag.build(fluent::lint::builtin_asm_labels).emit();
                             },
                             BuiltinLintDiagnostics::NamedAsmLabel(
                                 "only local labels of the form `<number>:` should be used in inline asm"
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index eeb66f2d738..5725c240320 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -22,18 +22,19 @@ use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
 use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err};
-use rustc_errors::{Applicability, MultiSpan, SuggestionStyle};
+use rustc_errors::{
+    Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle,
+};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
-use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -871,6 +872,17 @@ pub trait LintContext: Sized {
         decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
     );
 
+    /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
+    /// typically generated by `#[derive(LintDiagnostic)]`).
+    fn emit_spanned_lint<S: Into<MultiSpan>>(
+        &self,
+        lint: &'static Lint,
+        span: S,
+        decorator: impl for<'a> DecorateLint<'a, ()>,
+    ) {
+        self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag));
+    }
+
     fn struct_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
@@ -879,6 +891,13 @@ pub trait LintContext: Sized {
     ) {
         self.lookup(lint, Some(span), decorate);
     }
+
+    /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
+    /// generated by `#[derive(LintDiagnostic)]`).
+    fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) {
+        self.lookup(lint, None as Option<Span>, |diag| decorator.decorate_lint(diag));
+    }
+
     /// Emit a lint at the appropriate level, with no associated span.
     fn lint(
         &self,
@@ -887,6 +906,29 @@ pub trait LintContext: Sized {
     ) {
         self.lookup(lint, None as Option<Span>, decorate);
     }
+
+    /// This returns the lint level for the given lint at the current location.
+    fn get_lint_level(&self, lint: &'static Lint) -> Level;
+
+    /// This function can be used to manually fulfill an expectation. This can
+    /// be used for lints which contain several spans, and should be suppressed,
+    /// if either location was marked with an expectation.
+    ///
+    /// Note that this function should only be called for [`LintExpectationId`]s
+    /// retrieved from the current lint pass. Buffered or manually created ids can
+    /// cause ICEs.
+    fn fulfill_expectation(&self, expectation: LintExpectationId) {
+        // We need to make sure that submitted expectation ids are correctly fulfilled suppressed
+        // and stored between compilation sessions. To not manually do these steps, we simply create
+        // a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal
+        // expected lint diagnostic.
+        self.sess()
+            .struct_expect(
+                "this is a dummy diagnostic, to submit and store an expectation",
+                expectation,
+            )
+            .emit();
+    }
 }
 
 impl<'a> EarlyContext<'a> {
@@ -934,6 +976,10 @@ impl LintContext for LateContext<'_> {
             None => self.tcx.struct_lint_node(lint, hir_id, decorate),
         }
     }
+
+    fn get_lint_level(&self, lint: &'static Lint) -> Level {
+        self.tcx.lint_level_at_node(lint, self.last_node_with_lint_attrs).0
+    }
 }
 
 impl LintContext for EarlyContext<'_> {
@@ -956,6 +1002,10 @@ impl LintContext for EarlyContext<'_> {
     ) {
         self.builder.struct_lint(lint, span.map(|s| s.into()), decorate)
     }
+
+    fn get_lint_level(&self, lint: &'static Lint) -> Level {
+        self.builder.lint_level(lint).0
+    }
 }
 
 impl<'tcx> LateContext<'tcx> {
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index c5e15a88fdf..f41ee640499 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -1,6 +1,7 @@
 use crate::{context::LintContext, LateContext, LateLintPass};
+use rustc_errors::fluent;
 use rustc_hir as hir;
-use rustc_middle::ty::{fold::TypeFoldable, Ty};
+use rustc_middle::ty::{visit::TypeVisitable, Ty};
 use rustc_span::{symbol::sym, Span};
 
 declare_lint! {
@@ -51,19 +52,9 @@ fn enforce_mem_discriminant(
     if is_non_enum(ty_param) {
         cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
             builder
-                .build(
-                    "the return value of `mem::discriminant` is \
-                        unspecified when called with a non-enum type",
-                )
-                .span_note(
-                    args_span,
-                    &format!(
-                        "the argument to `discriminant` should be a \
-                            reference to an enum, but it was passed \
-                            a reference to a `{}`, which is not an enum.",
-                        ty_param,
-                    ),
-                )
+                .build(fluent::lint::enum_intrinsics_mem_discriminant)
+                .set_arg("ty_param", ty_param)
+                .span_note(args_span, fluent::lint::note)
                 .emit();
         });
     }
@@ -74,16 +65,9 @@ fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, sp
     if is_non_enum(ty_param) {
         cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
             builder
-                .build(
-                    "the return value of `mem::variant_count` is \
-                        unspecified when called with a non-enum type",
-                )
-                .note(&format!(
-                    "the type parameter of `variant_count` should \
-                            be an enum, but it was instantiated with \
-                            the type `{}`, which is not an enum.",
-                    ty_param,
-                ))
+                .build(fluent::lint::enum_intrinsics_mem_variant)
+                .set_arg("ty_param", ty_param)
+                .note(fluent::lint::note)
                 .emit();
         });
     }
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 95e3125045d..699e8154318 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,4 +1,5 @@
 use crate::builtin;
+use rustc_errors::fluent;
 use rustc_hir::HirId;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::{lint::LintExpectation, ty::TyCtxt};
@@ -43,13 +44,13 @@ fn emit_unfulfilled_expectation_lint(
         hir_id,
         expectation.emission_span,
         |diag| {
-            let mut diag = diag.build("this lint expectation is unfulfilled");
+            let mut diag = diag.build(fluent::lint::expectation);
             if let Some(rationale) = expectation.reason {
                 diag.note(rationale.as_str());
             }
 
             if expectation.is_unfulfilled_lint_expectations {
-                diag.note("the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message");
+                diag.note(fluent::lint::note);
             }
 
             diag.emit();
diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
index fc99d759a03..fe2712525ee 100644
--- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
+++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs
@@ -1,7 +1,7 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
 use rustc_ast as ast;
-use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_errors::{fluent, Applicability, SuggestionStyle};
 use rustc_span::{BytePos, Span, Symbol};
 
 declare_lint! {
@@ -61,41 +61,25 @@ impl HiddenUnicodeCodepoints {
             .collect();
 
         cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
-            let mut err = lint.build(&format!(
-                "unicode codepoint changing visible direction of text present in {}",
-                label
-            ));
-            let (an, s) = match spans.len() {
-                1 => ("an ", ""),
-                _ => ("", "s"),
-            };
-            err.span_label(
-                span,
-                &format!(
-                    "this {} contains {}invisible unicode text flow control codepoint{}",
-                    label, an, s,
-                ),
-            );
+            let mut err = lint.build(fluent::lint::hidden_unicode_codepoints);
+            err.set_arg("label", label);
+            err.set_arg("count", spans.len());
+            err.span_label(span, fluent::lint::label);
+            err.note(fluent::lint::note);
             if point_at_inner_spans {
                 for (c, span) in &spans {
                     err.span_label(*span, format!("{:?}", c));
                 }
             }
-            err.note(
-                "these kind of unicode codepoints change the way text flows on applications that \
-                 support them, but can cause confusion because they change the order of \
-                 characters on the screen",
-            );
             if point_at_inner_spans && !spans.is_empty() {
                 err.multipart_suggestion_with_style(
-                    "if their presence wasn't intentional, you can remove them",
+                    fluent::lint::suggestion_remove,
                     spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
                     Applicability::MachineApplicable,
                     SuggestionStyle::HideCodeAlways,
                 );
                 err.multipart_suggestion(
-                    "if you want to keep them but make them visible in your source code, you can \
-                    escape them",
+                    fluent::lint::suggestion_escape,
                     spans
                         .into_iter()
                         .map(|(c, span)| {
@@ -109,16 +93,16 @@ impl HiddenUnicodeCodepoints {
                 // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
                 // should do the same here to provide the same good suggestions as we do for
                 // literals above.
-                err.note("if their presence wasn't intentional, you can remove them");
-                err.note(&format!(
-                    "if you want to keep them but make them visible in your source code, you can \
-                     escape them: {}",
+                err.set_arg(
+                    "escaped",
                     spans
                         .into_iter()
-                        .map(|(c, _)| { format!("{:?}", c) })
+                        .map(|(c, _)| format!("{:?}", c))
                         .collect::<Vec<String>>()
                         .join(", "),
-                ));
+                );
+                err.note(fluent::lint::suggestion_remove);
+                err.note(fluent::lint::no_suggestion_note_escape);
             }
             err.emit();
         });
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 56c8635a189..738f475983e 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -3,7 +3,7 @@
 
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_hir::def::Res;
 use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
 use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
@@ -36,13 +36,10 @@ impl LateLintPass<'_> for DefaultHashTypes {
             _ => return,
         };
         cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
-            let msg = format!(
-                "prefer `{}` over `{}`, it has better performance",
-                replace,
-                cx.tcx.item_name(def_id)
-            );
-            lint.build(&msg)
-                .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
+            lint.build(fluent::lint::default_hash_types)
+                .set_arg("preferred", replace)
+                .set_arg("used", cx.tcx.item_name(def_id))
+                .note(fluent::lint::note)
                 .emit();
         });
     }
@@ -99,12 +96,9 @@ impl LateLintPass<'_> for QueryStability {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                 cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
-                    let msg = format!(
-                        "using `{}` can result in unstable query results",
-                        cx.tcx.item_name(def_id)
-                    );
-                    lint.build(&msg)
-                        .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
+                    lint.build(fluent::lint::query_instability)
+                        .set_arg("query", cx.tcx.item_name(def_id))
+                        .note(fluent::lint::note)
                         .emit();
                 })
             }
@@ -146,10 +140,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
             cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                lint.build("usage of `ty::TyKind::<kind>`")
+                lint.build(fluent::lint::tykind_kind)
                     .span_suggestion(
                         span,
-                        "try using `ty::<kind>` directly",
+                        fluent::lint::suggestion,
                         "ty",
                         Applicability::MaybeIncorrect, // ty maybe needs an import
                     )
@@ -175,10 +169,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -193,10 +187,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -213,10 +207,10 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                     && qpath_ty.hir_id == ty.hir_id
                                 {
-                                    lint.build("usage of `ty::TyKind::<kind>`")
+                                    lint.build(fluent::lint::tykind_kind)
                                         .span_suggestion(
                                             path.span,
-                                            "try using `ty::<kind>` directly",
+                                            fluent::lint::suggestion,
                                             "ty",
                                             Applicability::MaybeIncorrect, // ty maybe needs an import
                                         )
@@ -226,15 +220,16 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                             }
                             _ => {}
                         }
-                        lint.build("usage of `ty::TyKind`").help("try using `Ty` instead").emit();
+                        lint.build(fluent::lint::tykind).help(fluent::lint::help).emit();
                     })
                 } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
                     if path.segments.len() > 1 {
                         cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
-                            lint.build(&format!("usage of qualified `ty::{}`", t))
+                            lint.build(fluent::lint::ty_qualified)
+                                .set_arg("ty", t.clone())
                                 .span_suggestion(
                                     path.span,
-                                    "try importing it and using it unqualified",
+                                    fluent::lint::suggestion,
                                     t,
                                     // The import probably needs to be changed
                                     Applicability::MaybeIncorrect,
@@ -330,8 +325,8 @@ impl EarlyLintPass for LintPassImpl {
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
                             |lint| {
-                                lint.build("implementing `LintPass` by hand")
-                                    .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
+                                lint.build(fluent::lint::lintpass_by_hand)
+                                    .help(fluent::lint::help)
                                     .emit();
                             },
                         )
@@ -371,13 +366,10 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
                             return;
                         }
                         cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
-                            lint.build(&format!(
-                                "Found non-existing keyword `{}` used in \
-                                     `#[doc(keyword = \"...\")]`",
-                                v,
-                            ))
-                            .help("only existing keywords are allowed in core/std")
-                            .emit();
+                            lint.build(fluent::lint::non_existant_doc_keyword)
+                                .set_arg("keyword", v)
+                                .help(fluent::lint::help)
+                                .emit();
                         });
                     }
                 }
@@ -422,7 +414,7 @@ impl LateLintPass<'_> for Diagnostics {
                 let Impl { of_trait: Some(of_trait), .. } = impl_ &&
                 let Some(def_id) = of_trait.trait_def_id() &&
                 let Some(name) = cx.tcx.get_diagnostic_name(def_id) &&
-                matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic)
+                matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic | sym::DecorateLint)
             {
                 found_impl = true;
                 break;
@@ -431,8 +423,7 @@ impl LateLintPass<'_> for Diagnostics {
         debug!(?found_impl);
         if !found_impl {
             cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
-                lint.build("diagnostics should only be created in `SessionDiagnostic`/`AddSubdiagnostic` impls")
-                    .emit();
+                lint.build(fluent::lint::diag_out_of_impl).emit();
             })
         }
 
@@ -450,7 +441,7 @@ impl LateLintPass<'_> for Diagnostics {
         debug!(?found_diagnostic_message);
         if !found_diagnostic_message {
             cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
-                lint.build("diagnostics should be created using translatable messages").emit();
+                lint.build(fluent::lint::untranslatable_diag).emit();
             })
         }
     }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index c1d8d76c975..27f67207209 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -34,7 +34,7 @@ use tracing::debug;
 
 /// Extract the `LintStore` from the query context.
 /// This function exists because we've erased `LintStore` as `dyn Any` in the context.
-pub(crate) fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
+pub fn unerased_lint_store(tcx: TyCtxt<'_>) -> &LintStore {
     let store: &dyn Any = &*tcx.lint_store;
     store.downcast_ref().unwrap()
 }
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 4773feded12..00e96f20d1a 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -3,13 +3,13 @@ use crate::late::unerased_lint_store;
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, MultiSpan};
+use rustc_errors::{struct_span_err, Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::{
-    struct_lint_level, LevelAndSource, LintDiagnosticBuilder, LintExpectation, LintLevelMap,
-    LintLevelSets, LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE,
+    struct_lint_level, LevelAndSource, LintExpectation, LintLevelMap, LintLevelSets,
+    LintLevelSource, LintSet, LintStackIndex, COMMAND_LINE,
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
@@ -521,7 +521,7 @@ impl<'s> LintLevelsBuilder<'s> {
                             src,
                             Some(sp.into()),
                             |lint| {
-                                let mut err = lint.build(&msg);
+                                let mut err = lint.build(msg);
                                 if let Some(new_name) = &renamed {
                                     err.span_suggestion(
                                         sp,
@@ -548,7 +548,7 @@ impl<'s> LintLevelsBuilder<'s> {
                             } else {
                                 name.to_string()
                             };
-                            let mut db = lint.build(&format!("unknown lint: `{}`", name));
+                            let mut db = lint.build(format!("unknown lint: `{}`", name));
                             if let Some(suggestion) = suggestion {
                                 db.span_suggestion(
                                     sp,
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c1255ae5056..aaee0caa070 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -99,7 +99,7 @@ pub use builtin::SoftLints;
 pub use context::{CheckLintNameResult, FindLintError, LintStore};
 pub use context::{EarlyContext, LateContext, LintContext};
 pub use early::{check_ast_node, EarlyCheckNode};
-pub use late::check_crate;
+pub use late::{check_crate, unerased_lint_store};
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_session::lint::Level::{self, *};
 pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId};
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
index b6a45676a30..ff5a01749c1 100644
--- a/compiler/rustc_lint/src/methods.rs
+++ b/compiler/rustc_lint/src/methods.rs
@@ -1,6 +1,7 @@
 use crate::LateContext;
 use crate::LateLintPass;
 use crate::LintContext;
+use rustc_errors::fluent;
 use rustc_hir::{Expr, ExprKind, PathSegment};
 use rustc_middle::ty;
 use rustc_span::{symbol::sym, ExpnKind, Span};
@@ -88,16 +89,12 @@ fn lint_cstring_as_ptr(
             if let ty::Adt(adt, _) = substs.type_at(0).kind() {
                 if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
                     cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
-                        let mut diag = diag
-                            .build("getting the inner pointer of a temporary `CString`");
-                        diag.span_label(as_ptr_span, "this pointer will be invalid");
-                        diag.span_label(
-                            unwrap.span,
-                            "this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime",
-                        );
-                        diag.note("pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned");
-                        diag.help("for more information, see https://doc.rust-lang.org/reference/destructors.html");
-                        diag.emit();
+                        diag.build(fluent::lint::cstring_ptr)
+                            .span_label(as_ptr_span, fluent::lint::as_ptr_label)
+                            .span_label(unwrap.span, fluent::lint::unwrap_label)
+                            .note(fluent::lint::note)
+                            .help(fluent::lint::help)
+                            .emit();
                     });
                 }
             }
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 6182d2b10ed..764003e61a6 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -1,6 +1,7 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::fluent;
 use rustc_span::symbol::Symbol;
 
 declare_lint! {
@@ -180,13 +181,13 @@ impl EarlyLintPass for NonAsciiIdents {
             }
             has_non_ascii_idents = true;
             cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
-                lint.build("identifier contains non-ASCII characters").emit();
+                lint.build(fluent::lint::identifier_non_ascii_char).emit();
             });
             if check_uncommon_codepoints
                 && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
             {
                 cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
-                    lint.build("identifier contains uncommon Unicode codepoints").emit();
+                    lint.build(fluent::lint::identifier_uncommon_codepoints).emit();
                 })
             }
         }
@@ -216,15 +217,11 @@ impl EarlyLintPass for NonAsciiIdents {
                     .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
                         if !*existing_is_ascii || !is_ascii {
                             cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
-                                lint.build(&format!(
-                                    "identifier pair considered confusable between `{}` and `{}`",
-                                    existing_symbol, symbol
-                                ))
-                                .span_label(
-                                    *existing_span,
-                                    "this is where the previous identifier occurred",
-                                )
-                                .emit();
+                                lint.build(fluent::lint::confusable_identifier_pair)
+                                    .set_arg("existing_sym", *existing_symbol)
+                                    .set_arg("sym", symbol)
+                                    .span_label(*existing_span, fluent::lint::label)
+                                    .emit();
                             });
                         }
                         if *existing_is_ascii && !is_ascii {
@@ -326,18 +323,20 @@ impl EarlyLintPass for NonAsciiIdents {
 
                 for ((sp, ch_list), script_set) in lint_reports {
                     cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
-                        let message = format!(
-                            "the usage of Script Group `{}` in this crate consists solely of mixed script confusables",
-                            script_set);
-                        let mut note = "the usage includes ".to_string();
+                        let mut includes = String::new();
                         for (idx, ch) in ch_list.into_iter().enumerate() {
                             if idx != 0 {
-                                note += ", ";
+                                includes += ", ";
                             }
                             let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
-                            note += &char_info;
+                            includes += &char_info;
                         }
-                        lint.build(&message).note(&note).note("please recheck to make sure their usages are indeed what you want").emit();
+                        lint.build(fluent::lint::mixed_script_confusables)
+                            .set_arg("set", script_set.to_string())
+                            .set_arg("includes", includes)
+                            .note(fluent::lint::includes_note)
+                            .note(fluent::lint::note)
+                            .emit();
                     });
                 }
             }
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 4e7aeca9ce1..cdad2d2e8f9 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -1,6 +1,6 @@
 use crate::{LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
-use rustc_errors::{pluralize, Applicability};
+use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::lint::in_external_macro;
@@ -120,9 +120,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
     }
 
     cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
-        let mut l = lint.build("panic message is not a string literal");
-        l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol));
-        l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
+        let mut l = lint.build(fluent::lint::non_fmt_panic);
+        l.set_arg("name", symbol);
+        l.note(fluent::lint::note);
+        l.note(fluent::lint::more_info_note);
         if !is_arg_inside_call(arg_span, span) {
             // No clue where this argument is coming from.
             l.emit();
@@ -130,10 +131,10 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         }
         if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
             // A case of `panic!(format!(..))`.
-            l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol).as_str());
+            l.note(fluent::lint::supports_fmt_note);
             if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                 l.multipart_suggestion(
-                    "remove the `format!(..)` macro call",
+                    fluent::lint::supports_fmt_suggestion,
                     vec![
                         (arg_span.until(open.shrink_to_hi()), "".into()),
                         (close.until(arg_span.shrink_to_hi()), "".into()),
@@ -153,12 +154,18 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             );
 
             let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
-                let display = is_str || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
-                    infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
-                }) == Some(true);
-                let debug = !display && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
-                    infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
-                }) == Some(true);
+                let display = is_str
+                    || cx.tcx.get_diagnostic_item(sym::Display).map(|t| {
+                        infcx
+                            .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
+                            .may_apply()
+                    }) == Some(true);
+                let debug = !display
+                    && cx.tcx.get_diagnostic_item(sym::Debug).map(|t| {
+                        infcx
+                            .type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env)
+                            .may_apply()
+                    }) == Some(true);
                 (display, debug)
             });
 
@@ -175,17 +182,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             if suggest_display {
                 l.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    "add a \"{}\" format string to Display the message",
+                    fluent::lint::display_suggestion,
                     "\"{}\", ",
                     fmt_applicability,
                 );
             } else if suggest_debug {
+                l.set_arg("ty", ty);
                 l.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
-                    &format!(
-                        "add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
-                        ty,
-                    ),
+                    fluent::lint::debug_suggestion,
                     "\"{:?}\", ",
                     fmt_applicability,
                 );
@@ -193,15 +198,9 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
 
             if suggest_panic_any {
                 if let Some((open, close, del)) = find_delimiters(cx, span) {
+                    l.set_arg("already_suggested", suggest_display || suggest_debug);
                     l.multipart_suggestion(
-                        &format!(
-                            "{}use std::panic::panic_any instead",
-                            if suggest_display || suggest_debug {
-                                "or "
-                            } else {
-                                ""
-                            },
-                        ),
+                        fluent::lint::panic_suggestion,
                         if del == '(' {
                             vec![(span.until(open), "std::panic::panic_any".into())]
                         } else {
@@ -260,21 +259,19 @@ fn check_panic_str<'tcx>(
                 .collect(),
         };
         cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
-            let mut l = lint.build(match n_arguments {
-                1 => "panic message contains an unused formatting placeholder",
-                _ => "panic message contains unused formatting placeholders",
-            });
-            l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
+            let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
+            l.set_arg("count", n_arguments);
+            l.note(fluent::lint::note);
             if is_arg_inside_call(arg.span, span) {
                 l.span_suggestion(
                     arg.span.shrink_to_hi(),
-                    &format!("add the missing argument{}", pluralize!(n_arguments)),
+                    fluent::lint::add_args_suggestion,
                     ", ...",
                     Applicability::HasPlaceholders,
                 );
                 l.span_suggestion(
                     arg.span.shrink_to_lo(),
-                    "or add a \"{}\" format string to use the message literally",
+                    fluent::lint::add_fmt_suggestion,
                     "\"{}\", ",
                     Applicability::MachineApplicable,
                 );
@@ -289,17 +286,15 @@ fn check_panic_str<'tcx>(
                     .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
                     .collect()
             });
-        let msg = match &brace_spans {
-            Some(v) if v.len() == 1 => "panic message contains a brace",
-            _ => "panic message contains braces",
-        };
+        let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
         cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
-            let mut l = lint.build(msg);
-            l.note("this message is not used as a format string, but will be in Rust 2021");
+            let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
+            l.set_arg("count", count);
+            l.note(fluent::lint::note);
             if is_arg_inside_call(arg.span, span) {
                 l.span_suggestion(
                     arg.span.shrink_to_lo(),
-                    "add a \"{}\" format string to use the message literally",
+                    fluent::lint::suggestion,
                     "\"{}\", ",
                     Applicability::MachineApplicable,
                 );
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index e1507d0fbb4..33ac2ed02aa 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,7 +1,7 @@
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
@@ -137,22 +137,23 @@ impl NonCamelCaseTypes {
 
         if !is_camel_case(name) {
             cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
-                let msg = format!("{} `{}` should have an upper camel case name", sort, name);
-                let mut err = lint.build(&msg);
+                let mut err = lint.build(fluent::lint::non_camel_case_type);
                 let cc = to_camel_case(name);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Lowercase Letter".
                 if *name != cc {
                     err.span_suggestion(
                         ident.span,
-                        "convert the identifier to upper camel case",
+                        fluent::lint::suggestion,
                         to_camel_case(name),
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    err.span_label(ident.span, "should have an UpperCamelCase name");
+                    err.span_label(ident.span, fluent::lint::label);
                 }
 
+                err.set_arg("sort", sort);
+                err.set_arg("name", name);
                 err.emit();
             })
         }
@@ -281,11 +282,10 @@ impl NonSnakeCase {
         if !is_snake_case(name) {
             cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
                 let sc = NonSnakeCase::to_snake_case(name);
-                let msg = format!("{} `{}` should have a snake case name", sort, name);
-                let mut err = lint.build(&msg);
+                let mut err = lint.build(fluent::lint::non_snake_case);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Uppercase Letter".
-                if *name != sc {
+                if name != sc {
                     // We have a valid span in almost all cases, but we don't have one when linting a crate
                     // name provided via the command line.
                     if !ident.span.is_dummy() {
@@ -295,13 +295,13 @@ impl NonSnakeCase {
                             // Instead, recommend renaming the identifier entirely or, if permitted,
                             // escaping it to create a raw identifier.
                             if sc_ident.name.can_be_raw() {
-                                ("rename the identifier or convert it to a snake case raw identifier", sc_ident.to_string())
+                                (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
                             } else {
-                                err.note(&format!("`{}` cannot be used as a raw identifier", sc));
-                                ("rename the identifier", String::new())
+                                err.note(fluent::lint::cannot_convert_note);
+                                (fluent::lint::rename_suggestion, String::new())
                             }
                         } else {
-                            ("convert the identifier to snake case", sc)
+                            (fluent::lint::convert_suggestion, sc.clone())
                         };
 
                         err.span_suggestion(
@@ -311,12 +311,15 @@ impl NonSnakeCase {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        err.help(&format!("convert the identifier to snake case: `{}`", sc));
+                        err.help(fluent::lint::help);
                     }
                 } else {
-                    err.span_label(ident.span, "should have a snake_case name");
+                    err.span_label(ident.span, fluent::lint::label);
                 }
 
+                err.set_arg("sort", sort);
+                err.set_arg("name", name);
+                err.set_arg("sc", sc);
                 err.emit();
             });
         }
@@ -488,21 +491,22 @@ impl NonUpperCaseGlobals {
         if name.chars().any(|c| c.is_lowercase()) {
             cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
                 let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
-                let mut err =
-                    lint.build(&format!("{} `{}` should have an upper case name", sort, name));
+                let mut err = lint.build(fluent::lint::non_upper_case_global);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Lowercase Letter".
                 if *name != uc {
                     err.span_suggestion(
                         ident.span,
-                        "convert the identifier to upper case",
+                        fluent::lint::suggestion,
                         uc,
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    err.span_label(ident.span, "should have an UPPER_CASE name");
+                    err.span_label(ident.span, fluent::lint::label);
                 }
 
+                err.set_arg("sort", sort);
+                err.set_arg("name", name);
                 err.emit();
             })
         }
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 675bee738a6..11a752ff097 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,7 +1,8 @@
 use crate::context::LintContext;
-use crate::rustc_middle::ty::TypeFoldable;
+use crate::rustc_middle::ty::TypeVisitable;
 use crate::LateContext;
 use crate::LateLintPass;
+use rustc_errors::fluent;
 use rustc_hir::def::DefKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_middle::ty;
@@ -80,7 +81,6 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
         ) {
             return;
         }
-        let method = &call.ident.name;
         let receiver = &elements[0];
         let receiver_ty = cx.typeck_results().expr_ty(receiver);
         let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
@@ -90,19 +90,14 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
             return;
         }
         let expr_span = expr.span;
-        let note = format!(
-            "the type `{:?}` which `{}` is being called on is the same as \
-             the type returned from `{}`, so the method call does not do \
-             anything and can be removed",
-            receiver_ty, method, method,
-        );
-
         let span = expr_span.with_lo(receiver.span.hi());
         cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
-            let method = &call.ident.name;
-            let message =
-                format!("call to `.{}()` on a reference in this situation does nothing", &method,);
-            lint.build(&message).span_label(span, "unnecessary method call").note(&note).emit();
+            lint.build(fluent::lint::noop_method_call)
+                .set_arg("method", call.ident.name)
+                .set_arg("receiver_ty", receiver_ty)
+                .span_label(span, fluent::lint::label)
+                .note(fluent::lint::note)
+                .emit();
         });
     }
 }
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 2c8b41d7214..af5e5faf1f5 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -1,5 +1,5 @@
 use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
@@ -30,10 +30,11 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue {
                 }
                 if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
                     cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
-                        lint.build(&format!("passing `{}` by reference", t))
+                        lint.build(fluent::lint::pass_by_value)
+                            .set_arg("ty", t.clone())
                             .span_suggestion(
                                 ty.span,
-                                "try passing by value",
+                                fluent::lint::suggestion,
                                 t,
                                 // Changing type of function argument
                                 Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index f06a8b8f4b0..26f41345383 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -1,6 +1,6 @@
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_ast::{Block, StmtKind};
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability};
 use rustc_span::Span;
 
 declare_lint! {
@@ -49,12 +49,10 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
         }
 
         cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
-            let (msg, rem) = if multiple {
-                ("unnecessary trailing semicolons", "remove these semicolons")
-            } else {
-                ("unnecessary trailing semicolon", "remove this semicolon")
-            };
-            lint.build(msg).span_suggestion(span, rem, "", Applicability::MaybeIncorrect).emit();
+            lint.build(fluent::lint::redundant_semicolons)
+                .set_arg("multiple", multiple)
+                .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
+                .emit();
         });
     }
 }
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index 81d308ee347..df1587c5948 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -1,6 +1,7 @@
 use crate::LateContext;
 use crate::LateLintPass;
 use crate::LintContext;
+use rustc_errors::fluent;
 use rustc_hir as hir;
 use rustc_span::symbol::sym;
 
@@ -103,13 +104,10 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                     let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
                         return
                     };
-                    let msg = format!(
-                        "bounds on `{}` are most likely incorrect, consider instead \
-                         using `{}` to detect whether a type can be trivially dropped",
-                        predicate,
-                        cx.tcx.def_path_str(needs_drop)
-                    );
-                    lint.build(&msg).emit();
+                    lint.build(fluent::lint::drop_trait_constraints)
+                        .set_arg("predicate", predicate)
+                        .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
+                        .emit();
                 });
             }
         }
@@ -126,12 +124,9 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
                     let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
                         return
                     };
-                    let msg = format!(
-                        "types that do not implement `Drop` can still have drop glue, consider \
-                        instead using `{}` to detect whether a type is trivially dropped",
-                        cx.tcx.def_path_str(needs_drop)
-                    );
-                    lint.build(&msg).emit();
+                    lint.build(fluent::lint::drop_glue)
+                        .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
+                        .emit();
                 });
             }
         }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 5579e4d19cf..be4843c7ff1 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -2,12 +2,13 @@ use crate::{LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::Applicability;
+use rustc_errors::{fluent, Applicability, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
+use rustc_macros::LintDiagnostic;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol, DUMMY_SP};
@@ -139,7 +140,8 @@ fn lint_overflowing_range_endpoint<'tcx>(
         // overflowing and only by 1.
         if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
             cx.struct_span_lint(OVERFLOWING_LITERALS, parent_expr.span, |lint| {
-                let mut err = lint.build(&format!("range endpoint is out of range for `{}`", ty));
+                let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
+                err.set_arg("ty", ty);
                 if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
                     use ast::{LitIntType, LitKind};
                     // We need to preserve the literal's suffix,
@@ -153,7 +155,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
                     let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
                     err.span_suggestion(
                         parent_expr.span,
-                        "use an inclusive range instead",
+                        fluent::lint::suggestion,
                         suggestion,
                         Applicability::MachineApplicable,
                     );
@@ -229,38 +231,35 @@ fn report_bin_hex_error(
                 (t.name_str(), actually.to_string())
             }
         };
-        let mut err = lint.build(&format!("literal out of range for `{}`", t));
+        let mut err = lint.build(fluent::lint::overflowing_bin_hex);
         if negative {
             // If the value is negative,
             // emits a note about the value itself, apart from the literal.
-            err.note(&format!(
-                "the literal `{}` (decimal `{}`) does not fit into \
-                 the type `{}`",
-                repr_str, val, t
-            ));
-            err.note(&format!("and the value `-{}` will become `{}{}`", repr_str, actually, t));
+            err.note(fluent::lint::negative_note);
+            err.note(fluent::lint::negative_becomes_note);
         } else {
-            err.note(&format!(
-                "the literal `{}` (decimal `{}`) does not fit into \
-                 the type `{}` and will become `{}{}`",
-                repr_str, val, t, actually, t
-            ));
+            err.note(fluent::lint::positive_note);
         }
         if let Some(sugg_ty) =
             get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
         {
+            err.set_arg("suggestion_ty", sugg_ty);
             if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
                 let (sans_suffix, _) = repr_str.split_at(pos);
                 err.span_suggestion(
                     expr.span,
-                    &format!("consider using the type `{}` instead", sugg_ty),
+                    fluent::lint::suggestion,
                     format!("{}{}", sans_suffix, sugg_ty),
                     Applicability::MachineApplicable,
                 );
             } else {
-                err.help(&format!("consider using the type `{}` instead", sugg_ty));
+                err.help(fluent::lint::help);
             }
         }
+        err.set_arg("ty", t);
+        err.set_arg("lit", repr_str);
+        err.set_arg("dec", val);
+        err.set_arg("actually", actually);
         err.emit();
     });
 }
@@ -353,21 +352,23 @@ fn lint_int_literal<'tcx>(
         }
 
         cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-            let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str()));
-            err.note(&format!(
-                "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
+            let mut err = lint.build(fluent::lint::overflowing_int);
+            err.set_arg("ty", t.name_str());
+            err.set_arg(
+                "lit",
                 cx.sess()
                     .source_map()
                     .span_to_snippet(lit.span)
                     .expect("must get snippet from literal"),
-                t.name_str(),
-                min,
-                max,
-            ));
+            );
+            err.set_arg("min", min);
+            err.set_arg("max", max);
+            err.note(fluent::lint::note);
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             {
-                err.help(&format!("consider using the type `{}` instead", sugg_ty));
+                err.set_arg("suggestion_ty", sugg_ty);
+                err.help(fluent::lint::help);
             }
             err.emit();
         });
@@ -395,10 +396,10 @@ fn lint_uint_literal<'tcx>(
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
                         cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
-                            lint.build("only `u8` can be cast into `char`")
+                            lint.build(fluent::lint::only_cast_u8_to_char)
                                 .span_suggestion(
                                     par_e.span,
-                                    "use a `char` literal instead",
+                                    fluent::lint::suggestion,
                                     format!("'\\u{{{:X}}}'", lit_val),
                                     Applicability::MachineApplicable,
                                 )
@@ -429,17 +430,18 @@ fn lint_uint_literal<'tcx>(
             return;
         }
         cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-            lint.build(&format!("literal out of range for `{}`", t.name_str()))
-                .note(&format!(
-                    "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
+            lint.build(fluent::lint::overflowing_uint)
+                .set_arg("ty", t.name_str())
+                .set_arg(
+                    "lit",
                     cx.sess()
                         .source_map()
                         .span_to_snippet(lit.span)
                         .expect("must get snippet from literal"),
-                    t.name_str(),
-                    min,
-                    max,
-                ))
+                )
+                .set_arg("min", min)
+                .set_arg("max", max)
+                .note(fluent::lint::note)
                 .emit();
         });
     }
@@ -471,16 +473,16 @@ fn lint_literal<'tcx>(
             };
             if is_infinite == Ok(true) {
                 cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-                    lint.build(&format!("literal out of range for `{}`", t.name_str()))
-                        .note(&format!(
-                            "the literal `{}` does not fit into the type `{}` and will be converted to `{}::INFINITY`",
+                    lint.build(fluent::lint::overflowing_literal)
+                        .set_arg("ty", t.name_str())
+                        .set_arg(
+                            "lit",
                             cx.sess()
                                 .source_map()
                                 .span_to_snippet(lit.span)
                                 .expect("must get snippet from literal"),
-                            t.name_str(),
-                            t.name_str(),
-                        ))
+                        )
+                        .note(fluent::lint::note)
                         .emit();
                 });
             }
@@ -501,7 +503,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
             hir::ExprKind::Binary(binop, ref l, ref r) => {
                 if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
                     cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| {
-                        lint.build("comparison is useless due to type limits").emit();
+                        lint.build(fluent::lint::unused_comparisons).emit();
                     });
                 }
             }
@@ -663,7 +665,7 @@ struct ImproperCTypesVisitor<'a, 'tcx> {
 enum FfiResult<'tcx> {
     FfiSafe,
     FfiPhantom(Ty<'tcx>),
-    FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
+    FfiUnsafe { ty: Ty<'tcx>, reason: DiagnosticMessage, help: Option<DiagnosticMessage> },
 }
 
 pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
@@ -823,8 +825,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             self.emit_ffi_unsafe_type_lint(
                 ty,
                 sp,
-                "passing raw arrays by value is not FFI-safe",
-                Some("consider passing a pointer to the array"),
+                fluent::lint::improper_ctypes_array_reason,
+                Some(fluent::lint::improper_ctypes_array_help),
             );
             true
         } else {
@@ -867,11 +869,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             } else {
                 // All fields are ZSTs; this means that the type should behave
                 // like (), which is FFI-unsafe
-                FfiUnsafe {
-                    ty,
-                    reason: "this struct contains only zero-sized fields".into(),
-                    help: None,
-                }
+                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_struct_zst, help: None }
             }
         } else {
             // We can't completely trust repr(C) markings; make sure the fields are
@@ -885,7 +883,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     FfiPhantom(..) if def.is_enum() => {
                         return FfiUnsafe {
                             ty,
-                            reason: "this enum contains a PhantomData field".into(),
+                            reason: fluent::lint::improper_ctypes_enum_phantomdata,
                             help: None,
                         };
                     }
@@ -921,7 +919,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     } else {
                         return FfiUnsafe {
                             ty,
-                            reason: "box cannot be represented as a single pointer".to_string(),
+                            reason: fluent::lint::improper_ctypes_box,
                             help: None,
                         };
                     }
@@ -931,17 +929,19 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 }
                 match def.adt_kind() {
                     AdtKind::Struct | AdtKind::Union => {
-                        let kind = if def.is_struct() { "struct" } else { "union" };
-
                         if !def.repr().c() && !def.repr().transparent() {
                             return FfiUnsafe {
                                 ty,
-                                reason: format!("this {} has unspecified layout", kind),
-                                help: Some(format!(
-                                    "consider adding a `#[repr(C)]` or \
-                                             `#[repr(transparent)]` attribute to this {}",
-                                    kind
-                                )),
+                                reason: if def.is_struct() {
+                                    fluent::lint::improper_ctypes_struct_layout_reason
+                                } else {
+                                    fluent::lint::improper_ctypes_union_layout_reason
+                                },
+                                help: if def.is_struct() {
+                                    Some(fluent::lint::improper_ctypes_struct_layout_help)
+                                } else {
+                                    Some(fluent::lint::improper_ctypes_union_layout_help)
+                                },
                             };
                         }
 
@@ -950,7 +950,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if is_non_exhaustive && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: format!("this {} is non-exhaustive", kind),
+                                reason: if def.is_struct() {
+                                    fluent::lint::improper_ctypes_struct_non_exhaustive
+                                } else {
+                                    fluent::lint::improper_ctypes_union_non_exhaustive
+                                },
                                 help: None,
                             };
                         }
@@ -958,8 +962,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if def.non_enum_variant().fields.is_empty() {
                             return FfiUnsafe {
                                 ty,
-                                reason: format!("this {} has no fields", kind),
-                                help: Some(format!("consider adding a member to this {}", kind)),
+                                reason: if def.is_struct() {
+                                    fluent::lint::improper_ctypes_struct_fieldless_reason
+                                } else {
+                                    fluent::lint::improper_ctypes_union_fieldless_reason
+                                },
+                                help: if def.is_struct() {
+                                    Some(fluent::lint::improper_ctypes_struct_fieldless_help)
+                                } else {
+                                    Some(fluent::lint::improper_ctypes_union_fieldless_help)
+                                },
                             };
                         }
 
@@ -979,13 +991,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if repr_nullable_ptr(self.cx, ty, self.mode).is_none() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: "enum has no representation hint".into(),
-                                    help: Some(
-                                        "consider adding a `#[repr(C)]`, \
-                                                `#[repr(transparent)]`, or integer `#[repr(...)]` \
-                                                attribute to this enum"
-                                            .into(),
-                                    ),
+                                    reason: fluent::lint::improper_ctypes_enum_repr_reason,
+                                    help: Some(fluent::lint::improper_ctypes_enum_repr_help),
                                 };
                             }
                         }
@@ -993,7 +1000,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if def.is_variant_list_non_exhaustive() && !def.did().is_local() {
                             return FfiUnsafe {
                                 ty,
-                                reason: "this enum is non-exhaustive".into(),
+                                reason: fluent::lint::improper_ctypes_non_exhaustive,
                                 help: None,
                             };
                         }
@@ -1004,7 +1011,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             if is_non_exhaustive && !variant.def_id.is_local() {
                                 return FfiUnsafe {
                                     ty,
-                                    reason: "this enum has non-exhaustive variants".into(),
+                                    reason: fluent::lint::improper_ctypes_non_exhaustive_variant,
                                     help: None,
                                 };
                             }
@@ -1022,39 +1029,37 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
             ty::Char => FfiUnsafe {
                 ty,
-                reason: "the `char` type has no C equivalent".into(),
-                help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
+                reason: fluent::lint::improper_ctypes_char_reason,
+                help: Some(fluent::lint::improper_ctypes_char_help),
             },
 
-            ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe {
-                ty,
-                reason: "128-bit integers don't currently have a known stable ABI".into(),
-                help: None,
-            },
+            ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => {
+                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_128bit, help: None }
+            }
 
             // Primitive types with a stable representation.
             ty::Bool | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Never => FfiSafe,
 
             ty::Slice(_) => FfiUnsafe {
                 ty,
-                reason: "slices have no C equivalent".into(),
-                help: Some("consider using a raw pointer instead".into()),
+                reason: fluent::lint::improper_ctypes_slice_reason,
+                help: Some(fluent::lint::improper_ctypes_slice_help),
             },
 
             ty::Dynamic(..) => {
-                FfiUnsafe { ty, reason: "trait objects have no C equivalent".into(), help: None }
+                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_dyn, help: None }
             }
 
             ty::Str => FfiUnsafe {
                 ty,
-                reason: "string slices have no C equivalent".into(),
-                help: Some("consider using `*const u8` and a length instead".into()),
+                reason: fluent::lint::improper_ctypes_str_reason,
+                help: Some(fluent::lint::improper_ctypes_str_help),
             },
 
             ty::Tuple(..) => FfiUnsafe {
                 ty,
-                reason: "tuples have unspecified layout".into(),
-                help: Some("consider using a struct instead".into()),
+                reason: fluent::lint::improper_ctypes_tuple_reason,
+                help: Some(fluent::lint::improper_ctypes_tuple_help),
             },
 
             ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
@@ -1085,12 +1090,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 if self.is_internal_abi(sig.abi()) {
                     return FfiUnsafe {
                         ty,
-                        reason: "this function pointer has Rust-specific calling convention".into(),
-                        help: Some(
-                            "consider using an `extern fn(...) -> ...` \
-                                    function pointer instead"
-                                .into(),
-                        ),
+                        reason: fluent::lint::improper_ctypes_fnptr_reason,
+                        help: Some(fluent::lint::improper_ctypes_fnptr_help),
                     };
                 }
 
@@ -1121,7 +1122,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             // While opaque types are checked for earlier, if a projection in a struct field
             // normalizes to an opaque type, then it will reach this branch.
             ty::Opaque(..) => {
-                FfiUnsafe { ty, reason: "opaque types have no C equivalent".into(), help: None }
+                FfiUnsafe { ty, reason: fluent::lint::improper_ctypes_opaque, help: None }
             }
 
             // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
@@ -1147,8 +1148,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         &mut self,
         ty: Ty<'tcx>,
         sp: Span,
-        note: &str,
-        help: Option<&str>,
+        note: DiagnosticMessage,
+        help: Option<DiagnosticMessage>,
     ) {
         let lint = match self.mode {
             CItemKind::Declaration => IMPROPER_CTYPES,
@@ -1160,18 +1161,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                 CItemKind::Declaration => "block",
                 CItemKind::Definition => "fn",
             };
-            let mut diag = lint.build(&format!(
-                "`extern` {} uses type `{}`, which is not FFI-safe",
-                item_description, ty
-            ));
-            diag.span_label(sp, "not FFI-safe");
+            let mut diag = lint.build(fluent::lint::improper_ctypes);
+            diag.set_arg("ty", ty);
+            diag.set_arg("desc", item_description);
+            diag.span_label(sp, fluent::lint::label);
             if let Some(help) = help {
                 diag.help(help);
             }
             diag.note(note);
             if let ty::Adt(def, _) = ty.kind() {
                 if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
-                    diag.span_note(sp, "the type is defined here");
+                    diag.span_note(sp, fluent::lint::note);
                 }
             }
             diag.emit();
@@ -1183,7 +1183,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             cx: &'a LateContext<'tcx>,
         }
 
-        impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
+        impl<'a, 'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             type BreakTy = Ty<'tcx>;
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -1208,7 +1208,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() {
-            self.emit_ffi_unsafe_type_lint(ty, sp, "opaque types have no C equivalent", None);
+            self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint::improper_ctypes_opaque, None);
             true
         } else {
             false
@@ -1250,13 +1250,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
             FfiResult::FfiSafe => {}
             FfiResult::FfiPhantom(ty) => {
-                self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
+                self.emit_ffi_unsafe_type_lint(
+                    ty,
+                    sp,
+                    fluent::lint::improper_ctypes_only_phantomdata,
+                    None,
+                );
             }
             // If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
             // argument, which after substitution, is `()`, then this branch can be hit.
             FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
             FfiResult::FfiUnsafe { ty, reason, help } => {
-                self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
+                self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
             }
         }
     }
@@ -1383,12 +1388,9 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
                     VARIANT_SIZE_DIFFERENCES,
                     enum_definition.variants[largest_index].span,
                     |lint| {
-                        lint.build(&format!(
-                            "enum variant is more than three times \
-                                          larger ({} bytes) than the next largest",
-                            largest
-                        ))
-                        .emit();
+                        lint.build(fluent::lint::variant_size_differences)
+                            .set_arg("largest", largest)
+                            .emit();
                     },
                 );
             }
@@ -1511,13 +1513,13 @@ impl InvalidAtomicOrdering {
         {
             cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
                 if method == sym::load {
-                    diag.build("atomic loads cannot have `Release` or `AcqRel` ordering")
-                        .help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`")
+                    diag.build(fluent::lint::atomic_ordering_load)
+                        .help(fluent::lint::help)
                         .emit()
                 } else {
                     debug_assert_eq!(method, sym::store);
-                    diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering")
-                        .help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`")
+                    diag.build(fluent::lint::atomic_ordering_store)
+                        .help(fluent::lint::help)
                         .emit();
                 }
             });
@@ -1532,8 +1534,8 @@ impl InvalidAtomicOrdering {
             && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
         {
             cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
-                diag.build("memory fences cannot have `Relaxed` ordering")
-                    .help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`")
+                diag.build(fluent::lint::atomic_ordering_fence)
+                    .help(fluent::lint::help)
                     .emit();
             });
         }
@@ -1552,15 +1554,20 @@ impl InvalidAtomicOrdering {
         let Some(fail_ordering) = Self::match_ordering(cx, fail_order_arg) else { return };
 
         if matches!(fail_ordering, sym::Release | sym::AcqRel) {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg.span, |diag| {
-                diag.build(&format!(
-                    "`{method}`'s failure ordering may not be `Release` or `AcqRel`, \
-                    since a failed `{method}` does not result in a write",
-                ))
-                .span_label(fail_order_arg.span, "invalid failure ordering")
-                .help("consider using `Acquire` or `Relaxed` failure ordering instead")
-                .emit();
-            });
+            #[derive(LintDiagnostic)]
+            #[lint(lint::atomic_ordering_invalid)]
+            #[help]
+            struct InvalidAtomicOrderingDiag {
+                method: Symbol,
+                #[label]
+                fail_order_arg_span: Span,
+            }
+
+            cx.emit_spanned_lint(
+                INVALID_ATOMIC_ORDERING,
+                fail_order_arg.span,
+                InvalidAtomicOrderingDiag { method, fail_order_arg_span: fail_order_arg.span },
+            );
         }
 
         let Some(success_ordering) = Self::match_ordering(cx, success_order_arg) else { return };
@@ -1577,18 +1584,20 @@ impl InvalidAtomicOrdering {
                     fail_ordering
                 };
             cx.struct_span_lint(INVALID_ATOMIC_ORDERING, success_order_arg.span, |diag| {
-                diag.build(&format!(
-                    "`{method}`'s success ordering must be at least as strong as its failure ordering"
-                ))
-                .span_label(fail_order_arg.span, format!("`{fail_ordering}` failure ordering"))
-                .span_label(success_order_arg.span, format!("`{success_ordering}` success ordering"))
-                .span_suggestion_short(
-                    success_order_arg.span,
-                    format!("consider using `{success_suggestion}` success ordering instead"),
-                    format!("std::sync::atomic::Ordering::{success_suggestion}"),
-                    Applicability::MaybeIncorrect,
-                )
-                .emit();
+                diag.build(fluent::lint::atomic_ordering_invalid_fail_success)
+                    .set_arg("method", method)
+                    .set_arg("fail_ordering", fail_ordering)
+                    .set_arg("success_ordering", success_ordering)
+                    .set_arg("success_suggestion", success_suggestion)
+                    .span_label(fail_order_arg.span, fluent::lint::fail_label)
+                    .span_label(success_order_arg.span, fluent::lint::success_label)
+                    .span_suggestion_short(
+                        success_order_arg.span,
+                        fluent::lint::suggestion,
+                        format!("std::sync::atomic::Ordering::{success_suggestion}"),
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
             });
         }
     }
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 73f353e62c1..53269d18527 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -3,7 +3,7 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}
 use rustc_ast as ast;
 use rustc_ast::util::{classify, parser};
 use rustc_ast::{ExprKind, StmtKind};
-use rustc_errors::{pluralize, Applicability, MultiSpan};
+use rustc_errors::{fluent, pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -155,22 +155,23 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
 
         if let Some(must_use_op) = must_use_op {
             cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
-                let mut lint = lint.build(&format!("unused {} that must be used", must_use_op));
-                lint.span_label(expr.span, &format!("the {} produces a value", must_use_op));
-                lint.span_suggestion_verbose(
-                    expr.span.shrink_to_lo(),
-                    "use `let _ = ...` to ignore the resulting value",
-                    "let _ = ",
-                    Applicability::MachineApplicable,
-                );
-                lint.emit();
+                lint.build(fluent::lint::unused_op)
+                    .set_arg("op", must_use_op)
+                    .span_label(expr.span, fluent::lint::label)
+                    .span_suggestion_verbose(
+                        expr.span.shrink_to_lo(),
+                        fluent::lint::suggestion,
+                        "let _ = ",
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
             });
             op_warned = true;
         }
 
         if !(type_permits_lack_of_use || fn_warned || op_warned) {
             cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
-                lint.build(&format!("unused result of type `{}`", ty)).emit();
+                lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit();
             });
         }
 
@@ -267,23 +268,27 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 },
                 ty::Closure(..) => {
                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        let mut err = lint.build(&format!(
-                            "unused {}closure{}{} that must be used",
-                            descr_pre, plural_suffix, descr_post,
-                        ));
-                        err.note("closures are lazy and do nothing unless called");
-                        err.emit();
+                        // FIXME(davidtwco): this isn't properly translatable becauses of the
+                        // pre/post strings
+                        lint.build(fluent::lint::unused_closure)
+                            .set_arg("count", plural_len)
+                            .set_arg("pre", descr_pre)
+                            .set_arg("post", descr_post)
+                            .note(fluent::lint::note)
+                            .emit();
                     });
                     true
                 }
                 ty::Generator(..) => {
                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        let mut err = lint.build(&format!(
-                            "unused {}generator{}{} that must be used",
-                            descr_pre, plural_suffix, descr_post,
-                        ));
-                        err.note("generators are lazy and do nothing unless resumed");
-                        err.emit();
+                        // FIXME(davidtwco): this isn't properly translatable becauses of the
+                        // pre/post strings
+                        lint.build(fluent::lint::unused_generator)
+                            .set_arg("count", plural_len)
+                            .set_arg("pre", descr_pre)
+                            .set_arg("post", descr_post)
+                            .note(fluent::lint::note)
+                            .emit();
                     });
                     true
                 }
@@ -305,13 +310,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
         ) -> bool {
             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
                 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                    let msg = format!(
-                        "unused {}`{}`{} that must be used",
-                        descr_pre_path,
-                        cx.tcx.def_path_str(def_id),
-                        descr_post_path
-                    );
-                    let mut err = lint.build(&msg);
+                    // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
+                    // strings
+                    let mut err = lint.build(fluent::lint::unused_def);
+                    err.set_arg("pre", descr_pre_path);
+                    err.set_arg("post", descr_post_path);
+                    err.set_arg("def", cx.tcx.def_path_str(def_id));
                     // check for #[must_use = "..."]
                     if let Some(note) = attr.value_str() {
                         err.note(note.as_str());
@@ -356,20 +360,20 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
                 cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
                     let ty = cx.typeck_results().expr_ty(expr);
                     if ty.needs_drop(cx.tcx, cx.param_env) {
-                        let mut lint = lint.build("path statement drops value");
+                        let mut lint = lint.build(fluent::lint::path_statement_drop);
                         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
                             lint.span_suggestion(
                                 s.span,
-                                "use `drop` to clarify the intent",
+                                fluent::lint::suggestion,
                                 format!("drop({});", snippet),
                                 Applicability::MachineApplicable,
                             );
                         } else {
-                            lint.span_help(s.span, "use `drop` to clarify the intent");
+                            lint.span_help(s.span, fluent::lint::suggestion);
                         }
                         lint.emit();
                     } else {
-                        lint.build("path statement with no effect").emit();
+                        lint.build(fluent::lint::path_statement_no_effect).emit();
                     }
                 });
             }
@@ -540,15 +544,19 @@ trait UnusedDelimLint {
         }
 
         cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
-            let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg);
-            let mut err = lint.build(&span_msg);
             let replacement = vec![
                 (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
                 (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
             ];
-            let suggestion = format!("remove these {}", Self::DELIM_STR);
-            err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable);
-            err.emit();
+            lint.build(fluent::lint::unused_delim)
+                .set_arg("delim", Self::DELIM_STR)
+                .set_arg("item", msg)
+                .multipart_suggestion(
+                    fluent::lint::suggestion,
+                    replacement,
+                    Applicability::MachineApplicable,
+                )
+                .emit();
         });
     }
 
@@ -1110,7 +1118,7 @@ impl UnusedImportBraces {
             };
 
             cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
-                lint.build(&format!("braces around {} is unnecessary", node_name)).emit();
+                lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit();
             });
         }
     }
@@ -1161,15 +1169,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
         for adj in cx.typeck_results().expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
                 cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
-                    let msg = match m {
-                        adjustment::AutoBorrowMutability::Not => {
-                            "unnecessary allocation, use `&` instead"
-                        }
+                    lint.build(match m {
+                        adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
                         adjustment::AutoBorrowMutability::Mut { .. } => {
-                            "unnecessary allocation, use `&mut` instead"
+                            fluent::lint::unused_allocation_mut
                         }
-                    };
-                    lint.build(msg).emit();
+                    })
+                    .emit();
                 });
             }
         }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index d52455e2576..9fc2249b290 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -520,6 +520,11 @@ declare_lint! {
     /// The `expect` attribute can be removed if this is intended behavior otherwise
     /// it should be investigated why the expected lint is no longer issued.
     ///
+    /// In rare cases, the expectation might be emitted at a different location than
+    /// shown in the shown code snippet. In most cases, the `#[expect]` attribute
+    /// works when added to the outer scope. A few lints can only be expected
+    /// on a crate level.
+    ///
     /// Part of RFC 2383. The progress is being tracked in [#54503]
     ///
     /// [#54503]: https://github.com/rust-lang/rust/issues/54503
@@ -3231,6 +3236,7 @@ declare_lint_pass! {
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         TEST_UNSTABLE_LINT,
+        FFI_UNWIND_CALLS,
     ]
 }
 
@@ -3896,3 +3902,42 @@ declare_lint! {
     "this unstable lint is only for testing",
     @feature_gate = sym::test_unstable_lint;
 }
+
+declare_lint! {
+    /// The `ffi_unwind_calls` lint detects calls to foreign functions or function pointers with
+    /// `C-unwind` or other FFI-unwind ABIs.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (need FFI)
+    /// #![feature(ffi_unwind_calls)]
+    /// #![feature(c_unwind)]
+    ///
+    /// # mod impl {
+    /// #     #[no_mangle]
+    /// #     pub fn "C-unwind" fn foo() {}
+    /// # }
+    ///
+    /// extern "C-unwind" {
+    ///     fn foo();
+    /// }
+    ///
+    /// fn bar() {
+    ///     unsafe { foo(); }
+    ///     let ptr: unsafe extern "C-unwind" fn() = foo;
+    ///     unsafe { ptr(); }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// For crates containing such calls, if they are compiled with `-C panic=unwind` then the
+    /// produced library cannot be linked with crates compiled with `-C panic=abort`. For crates
+    /// that desire this ability it is therefore necessary to avoid such calls.
+    pub FFI_UNWIND_CALLS,
+    Allow,
+    "call to foreign functions or function pointers with FFI-unwind ABI",
+    @feature_gate = sym::c_unwind;
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 1cd19c7eaab..48f441e69d6 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -232,6 +232,13 @@ impl Level {
             Level::Deny | Level::Forbid => true,
         }
     }
+
+    pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
+        match self {
+            Level::Expect(id) | Level::ForceWarn(Some(id)) => Some(*id),
+            _ => None,
+        }
+    }
 }
 
 /// Specification of a single lint.
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index d0c86527189..027f377b0ac 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -1,125 +1,54 @@
 #![deny(unused_must_use)]
 
-use crate::diagnostics::error::{
-    invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
-    SessionDiagnosticDeriveError,
-};
-use crate::diagnostics::utils::{
-    report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
-    Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
-};
-use proc_macro2::{Ident, TokenStream};
-use quote::{format_ident, quote};
-use std::collections::HashMap;
-use std::str::FromStr;
-use syn::{
-    parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
-};
-use synstructure::{BindingInfo, Structure};
+use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind};
+use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
+use crate::diagnostics::utils::{build_field_mapping, SetOnce};
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::spanned::Spanned;
+use synstructure::Structure;
 
 /// The central struct for constructing the `into_diagnostic` method from an annotated struct.
 pub(crate) struct SessionDiagnosticDerive<'a> {
     structure: Structure<'a>,
-    builder: SessionDiagnosticDeriveBuilder,
+    sess: syn::Ident,
+    builder: DiagnosticDeriveBuilder,
 }
 
 impl<'a> SessionDiagnosticDerive<'a> {
     pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self {
-        // Build the mapping of field names to fields. This allows attributes to peek values from
-        // other fields.
-        let mut fields_map = HashMap::new();
-
-        // Convenience bindings.
-        let ast = structure.ast();
-
-        if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
-            for field in fields.iter() {
-                if let Some(ident) = &field.ident {
-                    fields_map.insert(ident.to_string(), quote! { &self.#ident });
-                }
-            }
-        }
-
         Self {
-            builder: SessionDiagnosticDeriveBuilder {
+            builder: DiagnosticDeriveBuilder {
                 diag,
-                sess,
-                fields: fields_map,
+                fields: build_field_mapping(&structure),
                 kind: None,
                 code: None,
                 slug: None,
             },
+            sess,
             structure,
         }
     }
 
     pub(crate) fn into_tokens(self) -> TokenStream {
-        let SessionDiagnosticDerive { mut structure, mut builder } = self;
+        let SessionDiagnosticDerive { mut structure, sess, mut builder } = self;
 
         let ast = structure.ast();
-        let attrs = &ast.attrs;
-
         let (implementation, param_ty) = {
             if let syn::Data::Struct(..) = ast.data {
-                let preamble = {
-                    let preamble = attrs.iter().map(|attr| {
-                        builder
-                            .generate_structure_code(attr)
-                            .unwrap_or_else(|v| v.to_compile_error())
-                    });
-
-                    quote! {
-                        #(#preamble)*;
-                    }
-                };
-
-                // Keep track of which fields are subdiagnostics or have no attributes.
-                let mut subdiagnostics_or_empty = std::collections::HashSet::new();
-
-                // Generates calls to `span_label` and similar functions based on the attributes
-                // on fields. Code for suggestions uses formatting machinery and the value of
-                // other fields - because any given field can be referenced multiple times, it
-                // should be accessed through a borrow. When passing fields to `add_subdiagnostic`
-                // or `set_arg` (which happens below) for Fluent, we want to move the data, so that
-                // has to happen in a separate pass over the fields.
-                let attrs = structure
-                    .clone()
-                    .filter(|field_binding| {
-                        let attrs = &field_binding.ast().attrs;
-
-                        (!attrs.is_empty()
-                            && attrs.iter().all(|attr| {
-                                "subdiagnostic"
-                                    != attr.path.segments.last().unwrap().ident.to_string()
-                            }))
-                            || {
-                                subdiagnostics_or_empty.insert(field_binding.binding.clone());
-                                false
-                            }
-                    })
-                    .each(|field_binding| builder.generate_field_attrs_code(field_binding));
-
-                structure.bind_with(|_| synstructure::BindStyle::Move);
-                // When a field has attributes like `#[label]` or `#[note]` then it doesn't
-                // need to be passed as an argument to the diagnostic. But when a field has no
-                // attributes or a `#[subdiagnostic]` attribute then it must be passed as an
-                // argument to the diagnostic so that it can be referred to by Fluent messages.
-                let args = structure
-                    .filter(|field_binding| {
-                        subdiagnostics_or_empty.contains(&field_binding.binding)
-                    })
-                    .each(|field_binding| builder.generate_field_attrs_code(field_binding));
+                let preamble = builder.preamble(&structure);
+                let (attrs, args) = builder.body(&mut structure);
 
                 let span = ast.span().unwrap();
-                let (diag, sess) = (&builder.diag, &builder.sess);
-                let init = match (builder.kind, builder.slug) {
+                let diag = &builder.diag;
+                let init = match (builder.kind.value(), builder.slug.value()) {
                     (None, _) => {
                         span_err(span, "diagnostic kind not specified")
                             .help("use the `#[error(...)]` attribute to create an error")
                             .emit();
-                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some((kind, _)), None) => {
+                    (Some(kind), None) => {
                         span_err(span, "diagnostic slug not specified")
                             .help(&format!(
                                 "specify the slug as the first argument to the attribute, such as \
@@ -127,14 +56,20 @@ impl<'a> SessionDiagnosticDerive<'a> {
                                 kind.descr()
                             ))
                             .emit();
-                        return SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some((SessionDiagnosticKind::Error, _)), Some((slug, _))) => {
+                    (Some(DiagnosticDeriveKind::Lint), _) => {
+                        span_err(span, "only `#[error(..)]` and `#[warn(..)]` are supported")
+                            .help("use the `#[error(...)]` attribute to create a error")
+                            .emit();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    }
+                    (Some(DiagnosticDeriveKind::Error), Some(slug)) => {
                         quote! {
                             let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug);
                         }
                     }
-                    (Some((SessionDiagnosticKind::Warn, _)), Some((slug, _))) => {
+                    (Some(DiagnosticDeriveKind::Warn), Some(slug)) => {
                         quote! {
                             let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug);
                         }
@@ -153,10 +88,12 @@ impl<'a> SessionDiagnosticDerive<'a> {
                     #diag
                 };
                 let param_ty = match builder.kind {
-                    Some((SessionDiagnosticKind::Error, _)) => {
+                    Some((DiagnosticDeriveKind::Error, _)) => {
                         quote! { rustc_errors::ErrorGuaranteed }
                     }
-                    Some((SessionDiagnosticKind::Warn, _)) => quote! { () },
+                    Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => {
+                        quote! { () }
+                    }
                     _ => unreachable!(),
                 };
 
@@ -168,13 +105,12 @@ impl<'a> SessionDiagnosticDerive<'a> {
                 )
                 .emit();
 
-                let implementation = SessionDiagnosticDeriveError::ErrorHandled.to_compile_error();
+                let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error();
                 let param_ty = quote! { rustc_errors::ErrorGuaranteed };
                 (implementation, param_ty)
             }
         };
 
-        let sess = &builder.sess;
         structure.gen_impl(quote! {
             gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty>
                     for @Self
@@ -191,525 +127,99 @@ impl<'a> SessionDiagnosticDerive<'a> {
     }
 }
 
-/// What kind of session diagnostic is being derived - an error or a warning?
-#[derive(Copy, Clone)]
-enum SessionDiagnosticKind {
-    /// `#[error(..)]`
-    Error,
-    /// `#[warn(..)]`
-    Warn,
+/// The central struct for constructing the `decorate_lint` method from an annotated struct.
+pub(crate) struct LintDiagnosticDerive<'a> {
+    structure: Structure<'a>,
+    builder: DiagnosticDeriveBuilder,
 }
 
-impl SessionDiagnosticKind {
-    /// Returns human-readable string corresponding to the kind.
-    fn descr(&self) -> &'static str {
-        match self {
-            SessionDiagnosticKind::Error => "error",
-            SessionDiagnosticKind::Warn => "warning",
+impl<'a> LintDiagnosticDerive<'a> {
+    pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self {
+        Self {
+            builder: DiagnosticDeriveBuilder {
+                diag,
+                fields: build_field_mapping(&structure),
+                kind: None,
+                code: None,
+                slug: None,
+            },
+            structure,
         }
     }
-}
-
-/// Tracks persistent information required for building up the individual calls to diagnostic
-/// methods for the final generated method. This is a separate struct to `SessionDiagnosticDerive`
-/// only to be able to destructure and split `self.builder` and the `self.structure` up to avoid a
-/// double mut borrow later on.
-struct SessionDiagnosticDeriveBuilder {
-    /// Name of the session parameter that's passed in to the `as_error` method.
-    sess: syn::Ident,
-    /// The identifier to use for the generated `DiagnosticBuilder` instance.
-    diag: syn::Ident,
-
-    /// Store a map of field name to its corresponding field. This is built on construction of the
-    /// derive builder.
-    fields: HashMap<String, TokenStream>,
-
-    /// Kind of diagnostic requested via the struct attribute.
-    kind: Option<(SessionDiagnosticKind, proc_macro::Span)>,
-    /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
-    /// has the actual diagnostic message.
-    slug: Option<(Path, proc_macro::Span)>,
-    /// Error codes are a optional part of the struct attribute - this is only set to detect
-    /// multiple specifications.
-    code: Option<(String, proc_macro::Span)>,
-}
-
-impl HasFieldMap for SessionDiagnosticDeriveBuilder {
-    fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
-        self.fields.get(field)
-    }
-}
-
-impl SessionDiagnosticDeriveBuilder {
-    /// Establishes state in the `SessionDiagnosticDeriveBuilder` resulting from the struct
-    /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
-    /// diagnostic builder calls for setting error code and creating note/help messages.
-    fn generate_structure_code(
-        &mut self,
-        attr: &Attribute,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        let diag = &self.diag;
-        let span = attr.span().unwrap();
-
-        let name = attr.path.segments.last().unwrap().ident.to_string();
-        let name = name.as_str();
-        let meta = attr.parse_meta()?;
-
-        let is_help_or_note = matches!(name, "help" | "note");
-
-        let nested = match meta {
-            // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
-            // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
-            Meta::List(MetaList { ref nested, .. }) => nested,
-            // Subdiagnostics without spans can be applied to the type too, and these are just
-            // paths: `#[help]` and `#[note]`
-            Meta::Path(_) if is_help_or_note => {
-                let fn_name = proc_macro2::Ident::new(name, attr.span());
-                return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
-            }
-            _ => throw_invalid_attr!(attr, &meta),
-        };
-
-        // Check the kind before doing any further processing so that there aren't misleading
-        // "no kind specified" errors if there are failures later.
-        match name {
-            "error" => self.kind.set_once((SessionDiagnosticKind::Error, span)),
-            "warning" => self.kind.set_once((SessionDiagnosticKind::Warn, span)),
-            "help" | "note" => (),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help("only `error`, `warning`, `help` and `note` are valid attributes")
-            }),
-        }
 
-        // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or
-        // `#[help(typeck::another_help)]`.
-        let mut nested_iter = nested.into_iter();
-        if let Some(nested_attr) = nested_iter.next() {
-            // Report an error if there are any other list items after the path.
-            if is_help_or_note && nested_iter.next().is_some() {
-                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    diag.help("`help` and `note` struct attributes can only have one argument")
-                });
-            }
-
-            match nested_attr {
-                NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => {
-                    let fn_name = proc_macro2::Ident::new(name, attr.span());
-                    return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
-                }
-                NestedMeta::Meta(Meta::Path(path)) => {
-                    self.slug.set_once((path.clone(), span));
-                }
-                NestedMeta::Meta(meta @ Meta::NameValue(_))
-                    if !is_help_or_note
-                        && meta.path().segments.last().unwrap().ident.to_string() == "code" =>
-                {
-                    // don't error for valid follow-up attributes
-                }
-                nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    diag.help("first argument of the attribute should be the diagnostic slug")
-                }),
-            };
-        }
+    pub(crate) fn into_tokens(self) -> TokenStream {
+        let LintDiagnosticDerive { mut structure, mut builder } = self;
 
-        // Remaining attributes are optional, only `code = ".."` at the moment.
-        let mut tokens = Vec::new();
-        for nested_attr in nested_iter {
-            let meta = match nested_attr {
-                syn::NestedMeta::Meta(meta) => meta,
-                _ => throw_invalid_nested_attr!(attr, &nested_attr),
-            };
+        let ast = structure.ast();
+        let implementation = {
+            if let syn::Data::Struct(..) = ast.data {
+                let preamble = builder.preamble(&structure);
+                let (attrs, args) = builder.body(&mut structure);
 
-            let path = meta.path();
-            let nested_name = path.segments.last().unwrap().ident.to_string();
-            // Struct attributes are only allowed to be applied once, and the diagnostic
-            // changes will be set in the initialisation code.
-            if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta {
-                let span = s.span().unwrap();
-                match nested_name.as_str() {
-                    "code" => {
-                        self.code.set_once((s.value(), span));
-                        let code = &self.code.as_ref().map(|(v, _)| v);
-                        tokens.push(quote! {
-                            #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
-                        });
+                let diag = &builder.diag;
+                let span = ast.span().unwrap();
+                let init = match (builder.kind.value(), builder.slug.value()) {
+                    (None, _) => {
+                        span_err(span, "diagnostic kind not specified")
+                            .help("use the `#[error(...)]` attribute to create an error")
+                            .emit();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    _ => invalid_nested_attr(attr, &nested_attr)
-                        .help("only `code` is a valid nested attributes following the slug")
-                        .emit(),
-                }
-            } else {
-                invalid_nested_attr(attr, &nested_attr).emit()
-            }
-        }
-
-        Ok(tokens.drain(..).collect())
-    }
-
-    fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
-        let field = binding_info.ast();
-        let field_binding = &binding_info.binding;
-
-        let inner_ty = FieldInnerTy::from_type(&field.ty);
-
-        // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than
-        // borrow it to avoid requiring clones - this must therefore be the last use of
-        // each field (for example, any formatting machinery that might refer to a field
-        // should be generated already).
-        if field.attrs.is_empty() {
-            let diag = &self.diag;
-            let ident = field.ident.as_ref().unwrap();
-            quote! {
-                #diag.set_arg(
-                    stringify!(#ident),
-                    #field_binding
-                );
-            }
-        } else {
-            field
-                .attrs
-                .iter()
-                .map(move |attr| {
-                    let name = attr.path.segments.last().unwrap().ident.to_string();
-                    let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
-                        // `primary_span` can accept a `Vec<Span>` so don't destructure that.
-                        ("primary_span", FieldInnerTy::Vec(_)) => {
-                            (quote! { #field_binding.clone() }, false)
+                    (Some(kind), None) => {
+                        span_err(span, "diagnostic slug not specified")
+                            .help(&format!(
+                                "specify the slug as the first argument to the attribute, such as \
+                                 `#[{}(typeck::example_error)]`",
+                                kind.descr()
+                            ))
+                            .emit();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    }
+                    (Some(DiagnosticDeriveKind::Error | DiagnosticDeriveKind::Warn), _) => {
+                        span_err(span, "only `#[lint(..)]` is supported")
+                            .help("use the `#[lint(...)]` attribute to create a lint")
+                            .emit();
+                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
+                    }
+                    (Some(DiagnosticDeriveKind::Lint), Some(slug)) => {
+                        quote! {
+                            let mut #diag = #diag.build(rustc_errors::fluent::#slug);
                         }
-                        // `subdiagnostics` are not derefed because they are bound by value.
-                        ("subdiagnostic", _) => (quote! { #field_binding }, true),
-                        _ => (quote! { *#field_binding }, true),
-                    };
-
-                    let generated_code = self
-                        .generate_inner_field_code(
-                            attr,
-                            FieldInfo {
-                                binding: binding_info,
-                                ty: inner_ty.inner_type().unwrap_or(&field.ty),
-                                span: &field.span(),
-                            },
-                            binding,
-                        )
-                        .unwrap_or_else(|v| v.to_compile_error());
-
-                    if needs_destructure {
-                        inner_ty.with(field_binding, generated_code)
-                    } else {
-                        generated_code
                     }
-                })
-                .collect()
-        }
-    }
-
-    fn generate_inner_field_code(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-        binding: TokenStream,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        let meta = attr.parse_meta()?;
-        match meta {
-            Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding),
-            Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding),
-            _ => throw_invalid_attr!(attr, &meta),
-        }
-    }
-
-    fn generate_inner_field_code_path(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-        binding: TokenStream,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        assert!(matches!(attr.parse_meta()?, Meta::Path(_)));
-        let diag = &self.diag;
-
-        let meta = attr.parse_meta()?;
-
-        let ident = &attr.path.segments.last().unwrap().ident;
-        let name = ident.to_string();
-        let name = name.as_str();
-        match name {
-            "skip_arg" => {
-                // Don't need to do anything - by virtue of the attribute existing, the
-                // `set_arg` call will not be generated.
-                Ok(quote! {})
-            }
-            "primary_span" => {
-                report_error_if_not_applied_to_span(attr, &info)?;
-                Ok(quote! {
-                    #diag.set_span(#binding);
-                })
-            }
-            "label" => {
-                report_error_if_not_applied_to_span(attr, &info)?;
-                Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
-            }
-            "note" | "help" => {
-                let path = match name {
-                    "note" => parse_quote! { _subdiag::note },
-                    "help" => parse_quote! { _subdiag::help },
-                    _ => unreachable!(),
                 };
-                if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
-                    Ok(self.add_spanned_subdiagnostic(binding, ident, path))
-                } else if type_is_unit(&info.ty) {
-                    Ok(self.add_subdiagnostic(ident, path))
-                } else {
-                    report_type_error(attr, "`Span` or `()`")?;
-                }
-            }
-            "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \
-                     are valid field attributes",
-                )
-            }),
-        }
-    }
-
-    fn generate_inner_field_code_list(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-        binding: TokenStream,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        let meta = attr.parse_meta()?;
-        let Meta::List(MetaList { ref path, ref nested, .. }) = meta  else { unreachable!() };
-
-        let ident = &attr.path.segments.last().unwrap().ident;
-        let name = path.segments.last().unwrap().ident.to_string();
-        let name = name.as_ref();
-        match name {
-            "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
-                return self.generate_inner_field_code_suggestion(attr, info);
-            }
-            "label" | "help" | "note" => (),
-            _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \
-                     valid field attributes",
-                )
-            }),
-        }
 
-        // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a
-        // path, e.g. `#[label(typeck::label)]`.
-        let mut nested_iter = nested.into_iter();
-        let msg = match nested_iter.next() {
-            Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(),
-            Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr),
-            None => throw_invalid_attr!(attr, &meta),
-        };
-
-        // None of these attributes should have anything following the slug.
-        if nested_iter.next().is_some() {
-            throw_invalid_attr!(attr, &meta);
-        }
-
-        match name {
-            "label" => {
-                report_error_if_not_applied_to_span(attr, &info)?;
-                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
-            }
-            "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => {
-                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
-            }
-            "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
-            "note" | "help" => {
-                report_type_error(attr, "`Span` or `()`")?;
-            }
-            _ => unreachable!(),
-        }
-    }
-
-    fn generate_inner_field_code_suggestion(
-        &mut self,
-        attr: &Attribute,
-        info: FieldInfo<'_>,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
-        let diag = &self.diag;
-
-        let mut meta = attr.parse_meta()?;
-        let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta  else { unreachable!() };
-
-        let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
-
-        let mut msg = None;
-        let mut code = None;
-
-        let mut nested_iter = nested.into_iter().peekable();
-        if let Some(nested_attr) = nested_iter.peek() {
-            if let NestedMeta::Meta(Meta::Path(path)) = nested_attr {
-                msg = Some(path.clone());
-            }
-        };
-        // Move the iterator forward if a path was found (don't otherwise so that
-        // code/applicability can be found or an error emitted).
-        if msg.is_some() {
-            let _ = nested_iter.next();
-        }
-
-        for nested_attr in nested_iter {
-            let meta = match nested_attr {
-                syn::NestedMeta::Meta(ref meta) => meta,
-                syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
-            };
-
-            let nested_name = meta.path().segments.last().unwrap().ident.to_string();
-            let nested_name = nested_name.as_str();
-            match meta {
-                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
-                    let span = meta.span().unwrap();
-                    match nested_name {
-                        "code" => {
-                            let formatted_str = self.build_format(&s.value(), s.span());
-                            code = Some(formatted_str);
-                        }
-                        "applicability" => {
-                            applicability = match applicability {
-                                Some(v) => {
-                                    span_err(
-                                        span,
-                                        "applicability cannot be set in both the field and \
-                                         attribute",
-                                    )
-                                    .emit();
-                                    Some(v)
-                                }
-                                None => match Applicability::from_str(&s.value()) {
-                                    Ok(v) => Some(quote! { #v }),
-                                    Err(()) => {
-                                        span_err(span, "invalid applicability").emit();
-                                        None
-                                    }
-                                },
-                            }
-                        }
-                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                            diag.help(
-                                "only `message`, `code` and `applicability` are valid field \
-                                 attributes",
-                            )
-                        }),
+                let implementation = quote! {
+                    #init
+                    #preamble
+                    match self {
+                        #attrs
                     }
-                }
-                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
-                    if matches!(meta, Meta::Path(_)) {
-                        diag.help("a diagnostic slug must be the first argument to the attribute")
-                    } else {
-                        diag
+                    match self {
+                        #args
                     }
-                }),
-            }
-        }
-
-        let applicability =
-            applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
-
-        let name = path.segments.last().unwrap().ident.to_string();
-        let method = format_ident!("span_{}", name);
-
-        let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion });
-        let msg = quote! { rustc_errors::fluent::#msg };
-        let code = code.unwrap_or_else(|| quote! { String::new() });
-
-        Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
-    }
-
-    /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
-    /// and `fluent_attr_identifier`.
-    fn add_spanned_subdiagnostic(
-        &self,
-        field_binding: TokenStream,
-        kind: &Ident,
-        fluent_attr_identifier: Path,
-    ) -> TokenStream {
-        let diag = &self.diag;
-        let fn_name = format_ident!("span_{}", kind);
-        quote! {
-            #diag.#fn_name(
-                #field_binding,
-                rustc_errors::fluent::#fluent_attr_identifier
-            );
-        }
-    }
+                    #diag.emit();
+                };
 
-    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
-    /// and `fluent_attr_identifier`.
-    fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
-        let diag = &self.diag;
-        quote! {
-            #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
-        }
-    }
+                implementation
+            } else {
+                span_err(
+                    ast.span().unwrap(),
+                    "`#[derive(LintDiagnostic)]` can only be used on structs",
+                )
+                .emit();
 
-    fn span_and_applicability_of_ty(
-        &self,
-        info: FieldInfo<'_>,
-    ) -> Result<(TokenStream, Option<TokenStream>), SessionDiagnosticDeriveError> {
-        match &info.ty {
-            // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
-            ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
-                let binding = &info.binding.binding;
-                Ok((quote!(*#binding), None))
+                DiagnosticDeriveError::ErrorHandled.to_compile_error()
             }
-            // If `ty` is `(Span, Applicability)` then return tokens accessing those.
-            Type::Tuple(tup) => {
-                let mut span_idx = None;
-                let mut applicability_idx = None;
-
-                for (idx, elem) in tup.elems.iter().enumerate() {
-                    if type_matches_path(elem, &["rustc_span", "Span"]) {
-                        if span_idx.is_none() {
-                            span_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more \
-                                 than one `Span`"
-                            );
-                        }
-                    } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
-                        if applicability_idx.is_none() {
-                            applicability_idx = Some(syn::Index::from(idx));
-                        } else {
-                            throw_span_err!(
-                                info.span.unwrap(),
-                                "type of field annotated with `#[suggestion(...)]` contains more \
-                                 than one Applicability"
-                            );
-                        }
-                    }
-                }
-
-                if let Some(span_idx) = span_idx {
-                    let binding = &info.binding.binding;
-                    let span = quote!(#binding.#span_idx);
-                    let applicability = applicability_idx
-                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
-                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+        };
 
-                    return Ok((span, Some(applicability)));
+        let diag = &builder.diag;
+        structure.gen_impl(quote! {
+            gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
+                fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) {
+                    use rustc_errors::IntoDiagnosticArg;
+                    #implementation
                 }
-
-                throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
-                    diag.help(
-                        "`#[suggestion(...)]` on a tuple field must be applied to fields of type \
-                         `(Span, Applicability)`",
-                    )
-                });
             }
-            // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
-            _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
-                diag.help(
-                    "`#[suggestion(...)]` should be applied to fields of type `Span` or \
-                     `(Span, Applicability)`",
-                )
-            }),
-        }
+        })
     }
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
new file mode 100644
index 00000000000..74ce1ab08c2
--- /dev/null
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -0,0 +1,590 @@
+#![deny(unused_must_use)]
+
+use crate::diagnostics::error::{
+    invalid_nested_attr, span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
+    DiagnosticDeriveError,
+};
+use crate::diagnostics::utils::{
+    report_error_if_not_applied_to_span, report_type_error, type_is_unit, type_matches_path,
+    Applicability, FieldInfo, FieldInnerTy, HasFieldMap, SetOnce,
+};
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+use std::collections::HashMap;
+use std::str::FromStr;
+use syn::{
+    parse_quote, spanned::Spanned, Attribute, Meta, MetaList, MetaNameValue, NestedMeta, Path, Type,
+};
+use synstructure::{BindingInfo, Structure};
+
+/// What kind of diagnostic is being derived - an error, a warning or a lint?
+#[derive(Copy, Clone)]
+pub(crate) enum DiagnosticDeriveKind {
+    /// `#[error(..)]`
+    Error,
+    /// `#[warn(..)]`
+    Warn,
+    /// `#[lint(..)]`
+    Lint,
+}
+
+impl DiagnosticDeriveKind {
+    /// Returns human-readable string corresponding to the kind.
+    pub fn descr(&self) -> &'static str {
+        match self {
+            DiagnosticDeriveKind::Error => "error",
+            DiagnosticDeriveKind::Warn => "warning",
+            DiagnosticDeriveKind::Lint => "lint",
+        }
+    }
+}
+
+/// Tracks persistent information required for building up individual calls to diagnostic methods
+/// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and
+/// `LintDiagnostic` for lints.
+pub(crate) struct DiagnosticDeriveBuilder {
+    /// The identifier to use for the generated `DiagnosticBuilder` instance.
+    pub diag: syn::Ident,
+
+    /// Store a map of field name to its corresponding field. This is built on construction of the
+    /// derive builder.
+    pub fields: HashMap<String, TokenStream>,
+
+    /// Kind of diagnostic requested via the struct attribute.
+    pub kind: Option<(DiagnosticDeriveKind, proc_macro::Span)>,
+    /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
+    /// has the actual diagnostic message.
+    pub slug: Option<(Path, proc_macro::Span)>,
+    /// Error codes are a optional part of the struct attribute - this is only set to detect
+    /// multiple specifications.
+    pub code: Option<(String, proc_macro::Span)>,
+}
+
+impl HasFieldMap for DiagnosticDeriveBuilder {
+    fn get_field_binding(&self, field: &String) -> Option<&TokenStream> {
+        self.fields.get(field)
+    }
+}
+
+impl DiagnosticDeriveBuilder {
+    pub fn preamble<'s>(&mut self, structure: &Structure<'s>) -> TokenStream {
+        let ast = structure.ast();
+        let attrs = &ast.attrs;
+        let preamble = attrs.iter().map(|attr| {
+            self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error())
+        });
+
+        quote! {
+            #(#preamble)*;
+        }
+    }
+
+    pub fn body<'s>(&mut self, structure: &mut Structure<'s>) -> (TokenStream, TokenStream) {
+        // Keep track of which fields are subdiagnostics or have no attributes.
+        let mut subdiagnostics_or_empty = std::collections::HashSet::new();
+
+        // Generates calls to `span_label` and similar functions based on the attributes
+        // on fields. Code for suggestions uses formatting machinery and the value of
+        // other fields - because any given field can be referenced multiple times, it
+        // should be accessed through a borrow. When passing fields to `add_subdiagnostic`
+        // or `set_arg` (which happens below) for Fluent, we want to move the data, so that
+        // has to happen in a separate pass over the fields.
+        let attrs = structure
+            .clone()
+            .filter(|field_binding| {
+                let attrs = &field_binding.ast().attrs;
+
+                (!attrs.is_empty()
+                    && attrs.iter().all(|attr| {
+                        "subdiagnostic" != attr.path.segments.last().unwrap().ident.to_string()
+                    }))
+                    || {
+                        subdiagnostics_or_empty.insert(field_binding.binding.clone());
+                        false
+                    }
+            })
+            .each(|field_binding| self.generate_field_attrs_code(field_binding));
+
+        structure.bind_with(|_| synstructure::BindStyle::Move);
+        // When a field has attributes like `#[label]` or `#[note]` then it doesn't
+        // need to be passed as an argument to the diagnostic. But when a field has no
+        // attributes or a `#[subdiagnostic]` attribute then it must be passed as an
+        // argument to the diagnostic so that it can be referred to by Fluent messages.
+        let args = structure
+            .filter(|field_binding| subdiagnostics_or_empty.contains(&field_binding.binding))
+            .each(|field_binding| self.generate_field_attrs_code(field_binding));
+
+        (attrs, args)
+    }
+
+    /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
+    /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
+    /// diagnostic builder calls for setting error code and creating note/help messages.
+    fn generate_structure_code_for_attr(
+        &mut self,
+        attr: &Attribute,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let diag = &self.diag;
+        let span = attr.span().unwrap();
+
+        let name = attr.path.segments.last().unwrap().ident.to_string();
+        let name = name.as_str();
+        let meta = attr.parse_meta()?;
+
+        let is_help_or_note = matches!(name, "help" | "note");
+
+        let nested = match meta {
+            // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
+            // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
+            Meta::List(MetaList { ref nested, .. }) => nested,
+            // Subdiagnostics without spans can be applied to the type too, and these are just
+            // paths: `#[help]` and `#[note]`
+            Meta::Path(_) if is_help_or_note => {
+                let fn_name = proc_macro2::Ident::new(name, attr.span());
+                return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::_subdiag::#fn_name); });
+            }
+            _ => throw_invalid_attr!(attr, &meta),
+        };
+
+        // Check the kind before doing any further processing so that there aren't misleading
+        // "no kind specified" errors if there are failures later.
+        match name {
+            "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)),
+            "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)),
+            "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)),
+            "help" | "note" => (),
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help("only `error`, `warning`, `help` and `note` are valid attributes")
+            }),
+        }
+
+        // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or
+        // `#[help(typeck::another_help)]`.
+        let mut nested_iter = nested.into_iter();
+        if let Some(nested_attr) = nested_iter.next() {
+            // Report an error if there are any other list items after the path.
+            if is_help_or_note && nested_iter.next().is_some() {
+                throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    diag.help("`help` and `note` struct attributes can only have one argument")
+                });
+            }
+
+            match nested_attr {
+                NestedMeta::Meta(Meta::Path(path)) if is_help_or_note => {
+                    let fn_name = proc_macro2::Ident::new(name, attr.span());
+                    return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
+                }
+                NestedMeta::Meta(Meta::Path(path)) => {
+                    self.slug.set_once((path.clone(), span));
+                }
+                NestedMeta::Meta(meta @ Meta::NameValue(_))
+                    if !is_help_or_note
+                        && meta.path().segments.last().unwrap().ident.to_string() == "code" =>
+                {
+                    // don't error for valid follow-up attributes
+                }
+                nested_attr => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    diag.help("first argument of the attribute should be the diagnostic slug")
+                }),
+            };
+        }
+
+        // Remaining attributes are optional, only `code = ".."` at the moment.
+        let mut tokens = Vec::new();
+        for nested_attr in nested_iter {
+            let meta = match nested_attr {
+                syn::NestedMeta::Meta(meta) => meta,
+                _ => throw_invalid_nested_attr!(attr, &nested_attr),
+            };
+
+            let path = meta.path();
+            let nested_name = path.segments.last().unwrap().ident.to_string();
+            // Struct attributes are only allowed to be applied once, and the diagnostic
+            // changes will be set in the initialisation code.
+            if let Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) = &meta {
+                let span = s.span().unwrap();
+                match nested_name.as_str() {
+                    "code" => {
+                        self.code.set_once((s.value(), span));
+                        let code = &self.code.as_ref().map(|(v, _)| v);
+                        tokens.push(quote! {
+                            #diag.code(rustc_errors::DiagnosticId::Error(#code.to_string()));
+                        });
+                    }
+                    _ => invalid_nested_attr(attr, &nested_attr)
+                        .help("only `code` is a valid nested attributes following the slug")
+                        .emit(),
+                }
+            } else {
+                invalid_nested_attr(attr, &nested_attr).emit()
+            }
+        }
+
+        Ok(tokens.drain(..).collect())
+    }
+
+    fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
+        let field = binding_info.ast();
+        let field_binding = &binding_info.binding;
+
+        let inner_ty = FieldInnerTy::from_type(&field.ty);
+
+        // When generating `set_arg` or `add_subdiagnostic` calls, move data rather than
+        // borrow it to avoid requiring clones - this must therefore be the last use of
+        // each field (for example, any formatting machinery that might refer to a field
+        // should be generated already).
+        if field.attrs.is_empty() {
+            let diag = &self.diag;
+            let ident = field.ident.as_ref().unwrap();
+            quote! {
+                #diag.set_arg(
+                    stringify!(#ident),
+                    #field_binding
+                );
+            }
+        } else {
+            field
+                .attrs
+                .iter()
+                .map(move |attr| {
+                    let name = attr.path.segments.last().unwrap().ident.to_string();
+                    let (binding, needs_destructure) = match (name.as_str(), &inner_ty) {
+                        // `primary_span` can accept a `Vec<Span>` so don't destructure that.
+                        ("primary_span", FieldInnerTy::Vec(_)) => {
+                            (quote! { #field_binding.clone() }, false)
+                        }
+                        // `subdiagnostics` are not derefed because they are bound by value.
+                        ("subdiagnostic", _) => (quote! { #field_binding }, true),
+                        _ => (quote! { *#field_binding }, true),
+                    };
+
+                    let generated_code = self
+                        .generate_inner_field_code(
+                            attr,
+                            FieldInfo {
+                                binding: binding_info,
+                                ty: inner_ty.inner_type().unwrap_or(&field.ty),
+                                span: &field.span(),
+                            },
+                            binding,
+                        )
+                        .unwrap_or_else(|v| v.to_compile_error());
+
+                    if needs_destructure {
+                        inner_ty.with(field_binding, generated_code)
+                    } else {
+                        generated_code
+                    }
+                })
+                .collect()
+        }
+    }
+
+    fn generate_inner_field_code(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        binding: TokenStream,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let meta = attr.parse_meta()?;
+        match meta {
+            Meta::Path(_) => self.generate_inner_field_code_path(attr, info, binding),
+            Meta::List(MetaList { .. }) => self.generate_inner_field_code_list(attr, info, binding),
+            _ => throw_invalid_attr!(attr, &meta),
+        }
+    }
+
+    fn generate_inner_field_code_path(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        binding: TokenStream,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        assert!(matches!(attr.parse_meta()?, Meta::Path(_)));
+        let diag = &self.diag;
+
+        let meta = attr.parse_meta()?;
+
+        let ident = &attr.path.segments.last().unwrap().ident;
+        let name = ident.to_string();
+        let name = name.as_str();
+        match name {
+            "skip_arg" => {
+                // Don't need to do anything - by virtue of the attribute existing, the
+                // `set_arg` call will not be generated.
+                Ok(quote! {})
+            }
+            "primary_span" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(quote! {
+                    #diag.set_span(#binding);
+                })
+            }
+            "label" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(self.add_spanned_subdiagnostic(binding, ident, parse_quote! { _subdiag::label }))
+            }
+            "note" | "help" => {
+                let path = match name {
+                    "note" => parse_quote! { _subdiag::note },
+                    "help" => parse_quote! { _subdiag::help },
+                    _ => unreachable!(),
+                };
+                if type_matches_path(&info.ty, &["rustc_span", "Span"]) {
+                    Ok(self.add_spanned_subdiagnostic(binding, ident, path))
+                } else if type_is_unit(&info.ty) {
+                    Ok(self.add_subdiagnostic(ident, path))
+                } else {
+                    report_type_error(attr, "`Span` or `()`")?
+                }
+            }
+            "subdiagnostic" => Ok(quote! { #diag.subdiagnostic(#binding); }),
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help(
+                    "only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` \
+                     are valid field attributes",
+                )
+            }),
+        }
+    }
+
+    fn generate_inner_field_code_list(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+        binding: TokenStream,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let meta = attr.parse_meta()?;
+        let Meta::List(MetaList { ref path, ref nested, .. }) = meta  else { unreachable!() };
+
+        let ident = &attr.path.segments.last().unwrap().ident;
+        let name = path.segments.last().unwrap().ident.to_string();
+        let name = name.as_ref();
+        match name {
+            "suggestion" | "suggestion_short" | "suggestion_hidden" | "suggestion_verbose" => {
+                return self.generate_inner_field_code_suggestion(attr, info);
+            }
+            "label" | "help" | "note" => (),
+            _ => throw_invalid_attr!(attr, &meta, |diag| {
+                diag.help(
+                    "only `label`, `note`, `help` or `suggestion{,_short,_hidden,_verbose}` are \
+                     valid field attributes",
+                )
+            }),
+        }
+
+        // For `#[label(..)]`, `#[note(..)]` and `#[help(..)]`, the first nested element must be a
+        // path, e.g. `#[label(typeck::label)]`.
+        let mut nested_iter = nested.into_iter();
+        let msg = match nested_iter.next() {
+            Some(NestedMeta::Meta(Meta::Path(path))) => path.clone(),
+            Some(nested_attr) => throw_invalid_nested_attr!(attr, &nested_attr),
+            None => throw_invalid_attr!(attr, &meta),
+        };
+
+        // None of these attributes should have anything following the slug.
+        if nested_iter.next().is_some() {
+            throw_invalid_attr!(attr, &meta);
+        }
+
+        match name {
+            "label" => {
+                report_error_if_not_applied_to_span(attr, &info)?;
+                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
+            }
+            "note" | "help" if type_matches_path(&info.ty, &["rustc_span", "Span"]) => {
+                Ok(self.add_spanned_subdiagnostic(binding, ident, msg))
+            }
+            "note" | "help" if type_is_unit(&info.ty) => Ok(self.add_subdiagnostic(ident, msg)),
+            "note" | "help" => report_type_error(attr, "`Span` or `()`")?,
+            _ => unreachable!(),
+        }
+    }
+
+    fn generate_inner_field_code_suggestion(
+        &mut self,
+        attr: &Attribute,
+        info: FieldInfo<'_>,
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
+        let diag = &self.diag;
+
+        let mut meta = attr.parse_meta()?;
+        let Meta::List(MetaList { ref path, ref mut nested, .. }) = meta  else { unreachable!() };
+
+        let (span_field, mut applicability) = self.span_and_applicability_of_ty(info)?;
+
+        let mut msg = None;
+        let mut code = None;
+
+        let mut nested_iter = nested.into_iter().peekable();
+        if let Some(nested_attr) = nested_iter.peek() {
+            if let NestedMeta::Meta(Meta::Path(path)) = nested_attr {
+                msg = Some(path.clone());
+            }
+        };
+        // Move the iterator forward if a path was found (don't otherwise so that
+        // code/applicability can be found or an error emitted).
+        if msg.is_some() {
+            let _ = nested_iter.next();
+        }
+
+        for nested_attr in nested_iter {
+            let meta = match nested_attr {
+                syn::NestedMeta::Meta(ref meta) => meta,
+                syn::NestedMeta::Lit(_) => throw_invalid_nested_attr!(attr, &nested_attr),
+            };
+
+            let nested_name = meta.path().segments.last().unwrap().ident.to_string();
+            let nested_name = nested_name.as_str();
+            match meta {
+                Meta::NameValue(MetaNameValue { lit: syn::Lit::Str(s), .. }) => {
+                    let span = meta.span().unwrap();
+                    match nested_name {
+                        "code" => {
+                            let formatted_str = self.build_format(&s.value(), s.span());
+                            code = Some(formatted_str);
+                        }
+                        "applicability" => {
+                            applicability = match applicability {
+                                Some(v) => {
+                                    span_err(
+                                        span,
+                                        "applicability cannot be set in both the field and \
+                                         attribute",
+                                    )
+                                    .emit();
+                                    Some(v)
+                                }
+                                None => match Applicability::from_str(&s.value()) {
+                                    Ok(v) => Some(quote! { #v }),
+                                    Err(()) => {
+                                        span_err(span, "invalid applicability").emit();
+                                        None
+                                    }
+                                },
+                            }
+                        }
+                        _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                            diag.help(
+                                "only `message`, `code` and `applicability` are valid field \
+                                 attributes",
+                            )
+                        }),
+                    }
+                }
+                _ => throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
+                    if matches!(meta, Meta::Path(_)) {
+                        diag.help("a diagnostic slug must be the first argument to the attribute")
+                    } else {
+                        diag
+                    }
+                }),
+            }
+        }
+
+        let applicability =
+            applicability.unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
+        let name = path.segments.last().unwrap().ident.to_string();
+        let method = format_ident!("span_{}", name);
+
+        let msg = msg.unwrap_or_else(|| parse_quote! { _subdiag::suggestion });
+        let msg = quote! { rustc_errors::fluent::#msg };
+        let code = code.unwrap_or_else(|| quote! { String::new() });
+
+        Ok(quote! { #diag.#method(#span_field, #msg, #code, #applicability); })
+    }
+
+    /// Adds a spanned subdiagnostic by generating a `diag.span_$kind` call with the current slug
+    /// and `fluent_attr_identifier`.
+    fn add_spanned_subdiagnostic(
+        &self,
+        field_binding: TokenStream,
+        kind: &Ident,
+        fluent_attr_identifier: Path,
+    ) -> TokenStream {
+        let diag = &self.diag;
+        let fn_name = format_ident!("span_{}", kind);
+        quote! {
+            #diag.#fn_name(
+                #field_binding,
+                rustc_errors::fluent::#fluent_attr_identifier
+            );
+        }
+    }
+
+    /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug
+    /// and `fluent_attr_identifier`.
+    fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream {
+        let diag = &self.diag;
+        quote! {
+            #diag.#kind(rustc_errors::fluent::#fluent_attr_identifier);
+        }
+    }
+
+    fn span_and_applicability_of_ty(
+        &self,
+        info: FieldInfo<'_>,
+    ) -> Result<(TokenStream, Option<TokenStream>), DiagnosticDeriveError> {
+        match &info.ty {
+            // If `ty` is `Span` w/out applicability, then use `Applicability::Unspecified`.
+            ty @ Type::Path(..) if type_matches_path(ty, &["rustc_span", "Span"]) => {
+                let binding = &info.binding.binding;
+                Ok((quote!(*#binding), None))
+            }
+            // If `ty` is `(Span, Applicability)` then return tokens accessing those.
+            Type::Tuple(tup) => {
+                let mut span_idx = None;
+                let mut applicability_idx = None;
+
+                for (idx, elem) in tup.elems.iter().enumerate() {
+                    if type_matches_path(elem, &["rustc_span", "Span"]) {
+                        if span_idx.is_none() {
+                            span_idx = Some(syn::Index::from(idx));
+                        } else {
+                            throw_span_err!(
+                                info.span.unwrap(),
+                                "type of field annotated with `#[suggestion(...)]` contains more \
+                                 than one `Span`"
+                            );
+                        }
+                    } else if type_matches_path(elem, &["rustc_errors", "Applicability"]) {
+                        if applicability_idx.is_none() {
+                            applicability_idx = Some(syn::Index::from(idx));
+                        } else {
+                            throw_span_err!(
+                                info.span.unwrap(),
+                                "type of field annotated with `#[suggestion(...)]` contains more \
+                                 than one Applicability"
+                            );
+                        }
+                    }
+                }
+
+                if let Some(span_idx) = span_idx {
+                    let binding = &info.binding.binding;
+                    let span = quote!(#binding.#span_idx);
+                    let applicability = applicability_idx
+                        .map(|applicability_idx| quote!(#binding.#applicability_idx))
+                        .unwrap_or_else(|| quote!(rustc_errors::Applicability::Unspecified));
+
+                    return Ok((span, Some(applicability)));
+                }
+
+                throw_span_err!(info.span.unwrap(), "wrong types for suggestion", |diag| {
+                    diag.help(
+                        "`#[suggestion(...)]` on a tuple field must be applied to fields of type \
+                         `(Span, Applicability)`",
+                    )
+                });
+            }
+            // If `ty` isn't a `Span` or `(Span, Applicability)` then emit an error.
+            _ => throw_span_err!(info.span.unwrap(), "wrong field type for suggestion", |diag| {
+                diag.help(
+                    "`#[suggestion(...)]` should be applied to fields of type `Span` or \
+                     `(Span, Applicability)`",
+                )
+            }),
+        }
+    }
+}
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index d088402abc6..0b1ededa775 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -4,16 +4,16 @@ use quote::quote;
 use syn::{spanned::Spanned, Attribute, Error as SynError, Meta, NestedMeta};
 
 #[derive(Debug)]
-pub(crate) enum SessionDiagnosticDeriveError {
+pub(crate) enum DiagnosticDeriveError {
     SynError(SynError),
     ErrorHandled,
 }
 
-impl SessionDiagnosticDeriveError {
+impl DiagnosticDeriveError {
     pub(crate) fn to_compile_error(self) -> TokenStream {
         match self {
-            SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(),
-            SessionDiagnosticDeriveError::ErrorHandled => {
+            DiagnosticDeriveError::SynError(e) => e.to_compile_error(),
+            DiagnosticDeriveError::ErrorHandled => {
                 // Return ! to avoid having to create a blank DiagnosticBuilder to return when an
                 // error has already been emitted to the compiler.
                 quote! {
@@ -24,9 +24,9 @@ impl SessionDiagnosticDeriveError {
     }
 }
 
-impl From<SynError> for SessionDiagnosticDeriveError {
+impl From<SynError> for DiagnosticDeriveError {
     fn from(e: SynError) -> Self {
-        SessionDiagnosticDeriveError::SynError(e)
+        DiagnosticDeriveError::SynError(e)
     }
 }
 
@@ -34,9 +34,9 @@ impl From<SynError> for SessionDiagnosticDeriveError {
 pub(crate) fn _throw_err(
     diag: Diagnostic,
     f: impl FnOnce(Diagnostic) -> Diagnostic,
-) -> SessionDiagnosticDeriveError {
+) -> DiagnosticDeriveError {
     f(diag).emit();
-    SessionDiagnosticDeriveError::ErrorHandled
+    DiagnosticDeriveError::ErrorHandled
 }
 
 /// Helper function for printing `syn::Path` - doesn't handle arguments in paths and these are
@@ -60,7 +60,7 @@ pub(crate) fn span_err(span: impl MultiSpan, msg: &str) -> Diagnostic {
 /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
 ///
-/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+/// For methods that return a `Result<_, DiagnosticDeriveError>`:
 macro_rules! throw_span_err {
     ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }};
     ($span:expr, $msg:expr, $f:expr) => {{
@@ -87,7 +87,7 @@ pub(crate) fn invalid_attr(attr: &Attribute, meta: &Meta) -> Diagnostic {
 /// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
 /// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
 ///
-/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+/// For methods that return a `Result<_, DiagnosticDeriveError>`:
 macro_rules! throw_invalid_attr {
     ($attr:expr, $meta:expr) => {{ throw_invalid_attr!($attr, $meta, |diag| diag) }};
     ($attr:expr, $meta:expr, $f:expr) => {{
@@ -129,7 +129,7 @@ pub(crate) fn invalid_nested_attr(attr: &Attribute, nested: &NestedMeta) -> Diag
 /// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
 /// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
 ///
-/// For methods that return a `Result<_, SessionDiagnosticDeriveError>`:
+/// For methods that return a `Result<_, DiagnosticDeriveError>`:
 macro_rules! throw_invalid_nested_attr {
     ($attr:expr, $nested_attr:expr) => {{ throw_invalid_nested_attr!($attr, $nested_attr, |diag| diag) }};
     ($attr:expr, $nested_attr:expr, $f:expr) => {{
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_macros/src/diagnostics/fluent.rs
index 2317186e655..2758fcd1310 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_macros/src/diagnostics/fluent.rs
@@ -189,9 +189,13 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
             if let Entry::Message(Message { id: Identifier { name }, attributes, .. }) = entry {
                 let _ = previous_defns.entry(name.to_string()).or_insert(ident_span);
 
-                // `typeck-foo-bar` => `foo_bar`
+                // `typeck-foo-bar` => `foo_bar` (in `typeck.ftl`)
+                // `const-eval-baz` => `baz` (in `const_eval.ftl`)
                 let snake_name = Ident::new(
-                    &name.replace(&format!("{}-", res.ident), "").replace("-", "_"),
+                    // FIXME: should probably trim prefix, not replace all occurrences
+                    &name
+                        .replace(&format!("{}-", res.ident).replace("_", "-"), "")
+                        .replace("-", "_"),
                     span,
                 );
                 constants.extend(quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 2eee4bfb5dd..39979002666 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -1,10 +1,11 @@
 mod diagnostic;
+mod diagnostic_builder;
 mod error;
 mod fluent;
 mod subdiagnostic;
 mod utils;
 
-use diagnostic::SessionDiagnosticDerive;
+use diagnostic::{LintDiagnosticDerive, SessionDiagnosticDerive};
 pub(crate) use fluent::fluent_messages;
 use proc_macro2::TokenStream;
 use quote::format_ident;
@@ -56,13 +57,55 @@ use synstructure::Structure;
 /// ```
 ///
 /// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
-/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
 pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
-    // Names for the diagnostic we build and the session we build it from.
-    let diag = format_ident!("diag");
-    let sess = format_ident!("sess");
+    SessionDiagnosticDerive::new(format_ident!("diag"), format_ident!("sess"), s).into_tokens()
+}
 
-    SessionDiagnosticDerive::new(diag, sess, s).into_tokens()
+/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
+/// independent from the actual lint emitting code.
+///
+/// ```ignore (rust)
+/// #[derive(LintDiagnostic)]
+/// #[lint(lint::atomic_ordering_invalid_fail_success)]
+/// pub struct AtomicOrderingInvalidLint {
+///     method: Symbol,
+///     success_ordering: Symbol,
+///     fail_ordering: Symbol,
+///     #[label(lint::fail_label)]
+///     fail_order_arg_span: Span,
+///     #[label(lint::success_label)]
+///     #[suggestion(
+///         code = "std::sync::atomic::Ordering::{success_suggestion}",
+///         applicability = "maybe-incorrect"
+///     )]
+///     success_order_arg_span: Span,
+/// }
+/// ```
+///
+/// ```fluent
+/// lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering
+///     .fail-label = `{$fail_ordering}` failure ordering
+///     .success-label = `{$success_ordering}` success ordering
+///     .suggestion = consider using `{$success_suggestion}` success ordering instead
+/// ```
+///
+/// Then, later, to emit the error:
+///
+/// ```ignore (rust)
+/// cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
+///     method,
+///     success_ordering,
+///     fail_ordering,
+///     fail_order_arg_span,
+///     success_order_arg_span,
+/// });
+/// ```
+///
+/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
+/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
+pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
+    LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens()
 }
 
 /// Implements `#[derive(SessionSubdiagnostic)]`, which allows for labels, notes, helps and
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index eab954a9c1b..2a5b6beba94 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -1,8 +1,7 @@
 #![deny(unused_must_use)]
 
 use crate::diagnostics::error::{
-    span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err,
-    SessionDiagnosticDeriveError,
+    span_err, throw_invalid_attr, throw_invalid_nested_attr, throw_span_err, DiagnosticDeriveError,
 };
 use crate::diagnostics::utils::{
     report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
@@ -214,7 +213,7 @@ impl<'a> HasFieldMap for SessionSubdiagnosticDeriveBuilder<'a> {
 }
 
 impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
-    fn identify_kind(&mut self) -> Result<(), SessionDiagnosticDeriveError> {
+    fn identify_kind(&mut self) -> Result<(), DiagnosticDeriveError> {
         for attr in self.variant.ast().attrs {
             let span = attr.span().unwrap();
 
@@ -351,7 +350,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         &mut self,
         binding: &BindingInfo<'_>,
         is_suggestion: bool,
-    ) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+    ) -> Result<TokenStream, DiagnosticDeriveError> {
         let ast = binding.ast();
 
         let inner_ty = FieldInnerTy::from_type(&ast.ty);
@@ -411,7 +410,7 @@ impl<'a> SessionSubdiagnosticDeriveBuilder<'a> {
         Ok(inner_ty.with(binding, generated))
     }
 
-    fn into_tokens(&mut self) -> Result<TokenStream, SessionDiagnosticDeriveError> {
+    fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveError> {
         self.identify_kind()?;
         let Some(kind) = self.kind.map(|(kind, _)| kind) else {
             throw_span_err!(
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 636bcf1f7b1..8977db4606c 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -1,11 +1,11 @@
-use crate::diagnostics::error::{span_err, throw_span_err, SessionDiagnosticDeriveError};
+use crate::diagnostics::error::{span_err, throw_span_err, DiagnosticDeriveError};
 use proc_macro::Span;
 use proc_macro2::TokenStream;
 use quote::{format_ident, quote, ToTokens};
-use std::collections::BTreeSet;
+use std::collections::{BTreeSet, HashMap};
 use std::str::FromStr;
 use syn::{spanned::Spanned, Attribute, Meta, Type, TypeTuple};
-use synstructure::BindingInfo;
+use synstructure::{BindingInfo, Structure};
 
 /// Checks whether the type name of `ty` matches `name`.
 ///
@@ -34,7 +34,7 @@ pub(crate) fn type_is_unit(ty: &Type) -> bool {
 pub(crate) fn report_type_error(
     attr: &Attribute,
     ty_name: &str,
-) -> Result<!, SessionDiagnosticDeriveError> {
+) -> Result<!, DiagnosticDeriveError> {
     let name = attr.path.segments.last().unwrap().ident.to_string();
     let meta = attr.parse_meta()?;
 
@@ -59,7 +59,7 @@ fn report_error_if_not_applied_to_ty(
     info: &FieldInfo<'_>,
     path: &[&str],
     ty_name: &str,
-) -> Result<(), SessionDiagnosticDeriveError> {
+) -> Result<(), DiagnosticDeriveError> {
     if !type_matches_path(&info.ty, path) {
         report_type_error(attr, ty_name)?;
     }
@@ -71,7 +71,7 @@ fn report_error_if_not_applied_to_ty(
 pub(crate) fn report_error_if_not_applied_to_applicability(
     attr: &Attribute,
     info: &FieldInfo<'_>,
-) -> Result<(), SessionDiagnosticDeriveError> {
+) -> Result<(), DiagnosticDeriveError> {
     report_error_if_not_applied_to_ty(
         attr,
         info,
@@ -84,7 +84,7 @@ pub(crate) fn report_error_if_not_applied_to_applicability(
 pub(crate) fn report_error_if_not_applied_to_span(
     attr: &Attribute,
     info: &FieldInfo<'_>,
-) -> Result<(), SessionDiagnosticDeriveError> {
+) -> Result<(), DiagnosticDeriveError> {
     report_error_if_not_applied_to_ty(attr, info, &["rustc_span", "Span"], "`Span`")
 }
 
@@ -166,10 +166,12 @@ pub(crate) struct FieldInfo<'a> {
 /// Small helper trait for abstracting over `Option` fields that contain a value and a `Span`
 /// for error reporting if they are set more than once.
 pub(crate) trait SetOnce<T> {
-    fn set_once(&mut self, value: T);
+    fn set_once(&mut self, _: (T, Span));
+
+    fn value(self) -> Option<T>;
 }
 
-impl<T> SetOnce<(T, Span)> for Option<(T, Span)> {
+impl<T> SetOnce<T> for Option<(T, Span)> {
     fn set_once(&mut self, (value, span): (T, Span)) {
         match self {
             None => {
@@ -182,6 +184,10 @@ impl<T> SetOnce<(T, Span)> for Option<(T, Span)> {
             }
         }
     }
+
+    fn value(self) -> Option<T> {
+        self.map(|(v, _)| v)
+    }
 }
 
 pub(crate) trait HasFieldMap {
@@ -325,3 +331,20 @@ impl quote::ToTokens for Applicability {
         });
     }
 }
+
+/// Build the mapping of field names to fields. This allows attributes to peek values from
+/// other fields.
+pub(crate) fn build_field_mapping<'a>(structure: &Structure<'a>) -> HashMap<String, TokenStream> {
+    let mut fields_map = HashMap::new();
+
+    let ast = structure.ast();
+    if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data {
+        for field in fields.iter() {
+            if let Some(ident) = &field.ident {
+                fields_map.insert(ident.to_string(), quote! { &self.#ident });
+            }
+        }
+    }
+
+    fields_map
+}
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 7c8e3c6d140..168530c54b9 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -18,6 +18,7 @@ mod query;
 mod serialize;
 mod symbols;
 mod type_foldable;
+mod type_visitable;
 
 #[proc_macro]
 pub fn rustc_queries(input: TokenStream) -> TokenStream {
@@ -121,12 +122,14 @@ decl_derive!([TyEncodable] => serialize::type_encodable_derive);
 decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive);
 decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive);
 decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive);
+decl_derive!([TypeVisitable, attributes(type_visitable)] => type_visitable::type_visitable_derive);
 decl_derive!([Lift, attributes(lift)] => lift::lift_derive);
 decl_derive!(
     [SessionDiagnostic, attributes(
         // struct attributes
         warning,
         error,
+        lint,
         note,
         help,
         // field attributes
@@ -140,6 +143,24 @@ decl_derive!(
         suggestion_verbose)] => diagnostics::session_diagnostic_derive
 );
 decl_derive!(
+    [LintDiagnostic, attributes(
+        // struct attributes
+        warning,
+        error,
+        lint,
+        note,
+        help,
+        // field attributes
+        skip_arg,
+        primary_span,
+        label,
+        subdiagnostic,
+        suggestion,
+        suggestion_short,
+        suggestion_hidden,
+        suggestion_verbose)] => diagnostics::lint_diagnostic_derive
+);
+decl_derive!(
     [SessionSubdiagnostic, attributes(
         // struct/variant attributes
         label,
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index 9e834d3ba1c..23e619221aa 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -11,11 +11,6 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
     }
 
     s.add_bounds(synstructure::AddBounds::Generics);
-    let body_visit = s.each(|bind| {
-        quote! {
-            ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?;
-        }
-    });
     s.bind_with(|_| synstructure::BindStyle::Move);
     let body_fold = s.each_variant(|vi| {
         let bindings = vi.bindings();
@@ -36,14 +31,6 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
             ) -> Result<Self, __F::Error> {
                 Ok(match self { #body_fold })
             }
-
-            fn visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
-                &self,
-                __folder: &mut __F
-            ) -> ::std::ops::ControlFlow<__F::BreakTy> {
-                match *self { #body_visit }
-                ::std::ops::ControlFlow::CONTINUE
-            }
         },
     )
 }
diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs
new file mode 100644
index 00000000000..14e6aa6e0c1
--- /dev/null
+++ b/compiler/rustc_macros/src/type_visitable.rs
@@ -0,0 +1,33 @@
+use quote::quote;
+use syn::parse_quote;
+
+pub fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") {
+        s.add_impl_generic(parse_quote! { 'tcx });
+    }
+
+    s.add_bounds(synstructure::AddBounds::Generics);
+    let body_visit = s.each(|bind| {
+        quote! {
+            ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor)?;
+        }
+    });
+    s.bind_with(|_| synstructure::BindStyle::Move);
+
+    s.bound_impl(
+        quote!(::rustc_middle::ty::visit::TypeVisitable<'tcx>),
+        quote! {
+            fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<'tcx>>(
+                &self,
+                __visitor: &mut __V
+            ) -> ::std::ops::ControlFlow<__V::BreakTy> {
+                match *self { #body_visit }
+                ::std::ops::ControlFlow::CONTINUE
+            }
+        },
+    )
+}
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 555db5846ed..cb50c0fb738 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -748,7 +748,7 @@ impl<'a> CrateLoader<'a> {
         if !data.is_panic_runtime() {
             self.sess.err(&format!("the crate `{}` is not a panic runtime", name));
         }
-        if data.panic_strategy() != desired_strategy {
+        if data.required_panic_strategy() != Some(desired_strategy) {
             self.sess.err(&format!(
                 "the crate `{}` does not have the panic \
                                     strategy `{}`",
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 245b2076ebc..770d164894a 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -60,7 +60,6 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
-use rustc_target::spec::PanicStrategy;
 
 pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies {
     tcx.sess
@@ -367,14 +366,19 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                     prev_name, cur_name
                 ));
             }
-            panic_runtime = Some((cnum, tcx.panic_strategy(cnum)));
+            panic_runtime = Some((
+                cnum,
+                tcx.required_panic_strategy(cnum).unwrap_or_else(|| {
+                    bug!("cannot determine panic strategy of a panic runtime");
+                }),
+            ));
         }
     }
 
     // If we found a panic runtime, then we know by this point that it's the
     // only one, but we perform validation here that all the panic strategy
     // compilation modes for the whole DAG are valid.
-    if let Some((cnum, found_strategy)) = panic_runtime {
+    if let Some((runtime_cnum, found_strategy)) = panic_runtime {
         let desired_strategy = sess.panic_strategy();
 
         // First up, validate that our selected panic runtime is indeed exactly
@@ -384,7 +388,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
                 "the linked panic runtime `{}` is \
                                not compiled with this crate's \
                                panic strategy `{}`",
-                tcx.crate_name(cnum),
+                tcx.crate_name(runtime_cnum),
                 desired_strategy.desc()
             ));
         }
@@ -397,18 +401,14 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             if let Linkage::NotLinked = *linkage {
                 continue;
             }
-            if desired_strategy == PanicStrategy::Abort {
-                continue;
-            }
             let cnum = CrateNum::new(i + 1);
-            if tcx.is_compiler_builtins(cnum) {
+            if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
                 continue;
             }
 
-            let found_strategy = tcx.panic_strategy(cnum);
-            if desired_strategy != found_strategy {
+            if let Some(found_strategy) = tcx.required_panic_strategy(cnum) && desired_strategy != found_strategy {
                 sess.err(&format!(
-                    "the crate `{}` is compiled with the \
+                    "the crate `{}` requires \
                                panic strategy `{}` which is \
                                incompatible with this crate's \
                                strategy of `{}`",
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3280fd5c310..f0ccf02c9fa 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1758,8 +1758,8 @@ impl CrateMetadata {
         self.dep_kind.with_lock(|dep_kind| *dep_kind = f(*dep_kind))
     }
 
-    pub(crate) fn panic_strategy(&self) -> PanicStrategy {
-        self.root.panic_strategy
+    pub(crate) fn required_panic_strategy(&self) -> Option<PanicStrategy> {
+        self.root.required_panic_strategy
     }
 
     pub(crate) fn needs_panic_runtime(&self) -> bool {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 0bea2a10da8..565eec18ea9 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -246,7 +246,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     has_global_allocator => { cdata.root.has_global_allocator }
     has_panic_handler => { cdata.root.has_panic_handler }
     is_profiler_runtime => { cdata.root.profiler_runtime }
-    panic_strategy => { cdata.root.panic_strategy }
+    required_panic_strategy => { cdata.root.required_panic_strategy }
     panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
     extern_crate => {
         let r = *cdata.extern_crate.lock();
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 75286b89068..caf5965c3a4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -419,11 +419,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             return;
         }
 
-        self.tcx.hir().deep_visit_all_item_likes(self);
+        self.tcx.hir().visit_all_item_likes_in_crate(self);
     }
 
     fn encode_def_path_table(&mut self) {
-        let table = self.tcx.definitions_untracked().def_path_table();
+        let table = self.tcx.def_path_table();
         if self.is_proc_macro {
             for def_index in std::iter::once(CRATE_DEF_INDEX)
                 .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index))
@@ -443,9 +443,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     }
 
     fn encode_def_path_hash_map(&mut self) -> LazyValue<DefPathHashMapRef<'static>> {
-        self.lazy(DefPathHashMapRef::BorrowedFromTcx(
-            self.tcx.definitions_untracked().def_path_hash_to_def_index_map(),
-        ))
+        self.lazy(DefPathHashMapRef::BorrowedFromTcx(self.tcx.def_path_hash_to_def_index_map()))
     }
 
     fn encode_source_map(&mut self) -> LazyArray<rustc_span::SourceFile> {
@@ -614,7 +612,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let interpret_alloc_index_bytes = self.position() - i;
 
         // Encode the proc macro data. This affects 'tables',
-        // so we need to do this before we encode the tables
+        // so we need to do this before we encode the tables.
+        // This overwrites def_keys, so it must happen after encode_def_path_table.
         i = self.position();
         let proc_macro_data = self.encode_proc_macros();
         let proc_macro_data_bytes = self.position() - i;
@@ -665,7 +664,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             triple: tcx.sess.opts.target_triple.clone(),
             hash: tcx.crate_hash(LOCAL_CRATE),
             stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
-            panic_strategy: tcx.sess.panic_strategy(),
+            required_panic_strategy: tcx.required_panic_strategy(LOCAL_CRATE),
             panic_in_drop_strategy: tcx.sess.opts.debugging_opts.panic_in_drop,
             edition: tcx.sess.edition(),
             has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
@@ -992,8 +991,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             return;
         }
         let tcx = self.tcx;
-        let hir = tcx.hir();
-        for local_id in hir.iter_local_def_id() {
+        for local_id in tcx.iter_local_def_id() {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
@@ -1854,12 +1852,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         debug!("EncodeContext::encode_traits_and_impls()");
         empty_proc_macro!(self);
         let tcx = self.tcx;
-        let mut ctx = tcx.create_stable_hashing_context();
         let mut all_impls: Vec<_> = tcx.crate_inherent_impls(()).incoherent_impls.iter().collect();
-        all_impls.sort_by_cached_key(|&(&simp, _)| {
-            let mut hasher = StableHasher::new();
-            simp.hash_stable(&mut ctx, &mut hasher);
-            hasher.finish::<Fingerprint>();
+        tcx.with_stable_hashing_context(|mut ctx| {
+            all_impls.sort_by_cached_key(|&(&simp, _)| {
+                let mut hasher = StableHasher::new();
+                simp.hash_stable(&mut ctx, &mut hasher);
+                hasher.finish::<Fingerprint>()
+            })
         });
         let all_impls: Vec<_> = all_impls
             .into_iter()
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a58c0e68ee3..a50eb2a71cf 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -217,7 +217,7 @@ pub(crate) struct CrateRoot {
     extra_filename: String,
     hash: Svh,
     stable_crate_id: StableCrateId,
-    panic_strategy: PanicStrategy,
+    required_panic_strategy: Option<PanicStrategy>,
     panic_in_drop_strategy: PanicStrategy,
     edition: Edition,
     has_global_allocator: bool,
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 984c95b314b..661a9b1944c 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -96,6 +96,7 @@ macro_rules! arena_types {
             // (during lowering) and the `librustc_middle` arena (for decoding MIR)
             [decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
             [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+            [decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
             [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 555baae35f5..2d095438fc4 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -183,6 +183,9 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
     // We use this for most things when incr. comp. is turned off.
     [] Null,
 
+    // We use this to create a forever-red node.
+    [] Red,
+
     [anon] TraitSelect,
 
     // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below.
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index e335cb395f8..c8b3b52b0fb 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -23,6 +23,7 @@ pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
 
 impl rustc_query_system::dep_graph::DepKind for DepKind {
     const NULL: Self = DepKind::Null;
+    const RED: Self = DepKind::Red;
 
     fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}(", node.kind)?;
@@ -71,8 +72,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
     type DepKind = DepKind;
 
     #[inline]
-    fn create_stable_hashing_context(&self) -> StableHashingContext<'_> {
-        TyCtxt::create_stable_hashing_context(*self)
+    fn with_stable_hashing_context<R>(&self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R {
+        TyCtxt::with_stable_hashing_context(*self, f)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c3768d5b2d6..3e99ba5742a 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -218,14 +218,8 @@ impl<'hir> Map<'hir> {
         self.tcx.local_def_id_to_hir_id(def_id)
     }
 
-    pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'hir {
-        // Create a dependency to the crate to be sure we re-execute this when the amount of
-        // definitions change.
-        self.tcx.ensure().hir_crate(());
-        self.tcx.definitions_untracked().iter_local_def_id()
-    }
-
-    pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
+    /// Do not call this function directly. The query should be called.
+    pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
         let def_kind = match self.find(hir_id)? {
             Node::Item(item) => match item.kind {
@@ -302,7 +296,6 @@ impl<'hir> Map<'hir> {
             | Node::Infer(_)
             | Node::TraitRef(_)
             | Node::Pat(_)
-            | Node::Binding(_)
             | Node::Local(_)
             | Node::Param(_)
             | Node::Arm(_)
@@ -568,7 +561,7 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Walks the contents of a crate. See also `Crate::visit_all_items`.
+    /// Walks the contents of the local crate. See also `visit_all_item_likes_in_crate`.
     pub fn walk_toplevel_module(self, visitor: &mut impl Visitor<'hir>) {
         let (top_mod, span, hir_id) = self.get_module(CRATE_DEF_ID);
         visitor.visit_mod(top_mod, span, hir_id);
@@ -588,53 +581,61 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    /// Visits all items in the crate in some deterministic (but
-    /// unspecified) order. If you need to process every item,
-    /// and care about nesting -- usually because your algorithm
-    /// follows lexical scoping rules -- then this method is the best choice.
-    /// If you don't care about nesting, you should use the `tcx.hir_crate_items()` query
-    /// or `items()` instead.
+    /// Visits all item-likes in the crate in some deterministic (but unspecified) order. If you
+    /// need to process every item-like, and don't care about visiting nested items in a particular
+    /// order then this method is the best choice.  If you do care about this nesting, you should
+    /// use the `tcx.hir().walk_toplevel_module`.
+    ///
+    /// Note that this function will access HIR for all the item-likes in the crate.  If you only
+    /// need to access some of them, it is usually better to manually loop on the iterators
+    /// provided by `tcx.hir_crate_items(())`.
     ///
     /// Please see the notes in `intravisit.rs` for more information.
-    pub fn deep_visit_all_item_likes<V>(self, visitor: &mut V)
+    pub fn visit_all_item_likes_in_crate<V>(self, visitor: &mut V)
     where
         V: Visitor<'hir>,
     {
-        let krate = self.krate();
-        for owner in krate.owners.iter().filter_map(|i| i.as_owner()) {
-            match owner.node() {
-                OwnerNode::Item(item) => visitor.visit_item(item),
-                OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
-                OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
-                OwnerNode::TraitItem(item) => visitor.visit_trait_item(item),
-                OwnerNode::Crate(_) => {}
-            }
+        let krate = self.tcx.hir_crate_items(());
+
+        for id in krate.items() {
+            visitor.visit_item(self.item(id));
+        }
+
+        for id in krate.trait_items() {
+            visitor.visit_trait_item(self.trait_item(id));
+        }
+
+        for id in krate.impl_items() {
+            visitor.visit_impl_item(self.impl_item(id));
+        }
+
+        for id in krate.foreign_items() {
+            visitor.visit_foreign_item(self.foreign_item(id));
         }
     }
 
-    /// If you don't care about nesting, you should use the
-    /// `tcx.hir_module_items()` query or `module_items()` instead.
-    /// Please see notes in `deep_visit_all_item_likes`.
-    pub fn deep_visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
+    /// This method is the equivalent of `visit_all_item_likes_in_crate` but restricted to
+    /// item-likes in a single module.
+    pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
     where
         V: Visitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
 
-        for id in module.items.iter() {
-            visitor.visit_item(self.item(*id));
+        for id in module.items() {
+            visitor.visit_item(self.item(id));
         }
 
-        for id in module.trait_items.iter() {
-            visitor.visit_trait_item(self.trait_item(*id));
+        for id in module.trait_items() {
+            visitor.visit_trait_item(self.trait_item(id));
         }
 
-        for id in module.impl_items.iter() {
-            visitor.visit_impl_item(self.impl_item(*id));
+        for id in module.impl_items() {
+            visitor.visit_impl_item(self.impl_item(id));
         }
 
-        for id in module.foreign_items.iter() {
-            visitor.visit_foreign_item(self.foreign_item(*id));
+        for id in module.foreign_items() {
+            visitor.visit_foreign_item(self.foreign_item(id));
         }
     }
 
@@ -901,7 +902,7 @@ impl<'hir> Map<'hir> {
     #[inline]
     fn opt_ident(self, id: HirId) -> Option<Ident> {
         match self.get(id) {
-            Node::Binding(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
+            Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
             // A `Ctor` doesn't have an identifier itself, but its parent
             // struct/variant does. Compare with `hir::Map::opt_span`.
             Node::Ctor(..) => match self.find(self.get_parent_node(id))? {
@@ -1013,12 +1014,14 @@ impl<'hir> Map<'hir> {
                 ItemKind::Use(path, _) => path.span,
                 _ => named_span(item.span, item.ident, item.kind.generics()),
             },
+            Node::Variant(variant) => named_span(variant.span, variant.ident, None),
             Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)),
             Node::ForeignItem(item) => match item.kind {
                 ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
                 _ => named_span(item.span, item.ident, None),
             },
-            Node::Ctor(..) => return self.opt_span(self.get_parent_node(hir_id)),
+            Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
+            Node::Expr(Expr { kind: ExprKind::Closure { fn_decl_span, .. }, .. }) => *fn_decl_span,
             _ => self.span_with_body(hir_id),
         };
         Some(span)
@@ -1046,7 +1049,6 @@ impl<'hir> Map<'hir> {
             Node::Ty(ty) => ty.span,
             Node::TypeBinding(tb) => tb.span,
             Node::TraitRef(tr) => tr.path.span,
-            Node::Binding(pat) => pat.span,
             Node::Pat(pat) => pat.span,
             Node::Arm(arm) => arm.span,
             Node::Block(block) => block.span,
@@ -1142,34 +1144,35 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
 
     source_file_names.sort_unstable();
 
-    let mut hcx = tcx.create_stable_hashing_context();
-    let mut stable_hasher = StableHasher::new();
-    hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
-    upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
-    source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
-    if tcx.sess.opts.debugging_opts.incremental_relative_spans {
-        let definitions = &tcx.definitions_untracked();
-        let mut owner_spans: Vec<_> = krate
-            .owners
-            .iter_enumerated()
-            .filter_map(|(def_id, info)| {
-                let _ = info.as_owner()?;
-                let def_path_hash = definitions.def_path_hash(def_id);
-                let span = resolutions.source_span[def_id];
-                debug_assert_eq!(span.parent(), None);
-                Some((def_path_hash, span))
-            })
-            .collect();
-        owner_spans.sort_unstable_by_key(|bn| bn.0);
-        owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
-    }
-    tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
-    tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
-    // Hash visibility information since it does not appear in HIR.
-    resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
-    resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
+    let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
+        let mut stable_hasher = StableHasher::new();
+        hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
+        upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
+        source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+        if tcx.sess.opts.debugging_opts.incremental_relative_spans {
+            let definitions = tcx.definitions_untracked();
+            let mut owner_spans: Vec<_> = krate
+                .owners
+                .iter_enumerated()
+                .filter_map(|(def_id, info)| {
+                    let _ = info.as_owner()?;
+                    let def_path_hash = definitions.def_path_hash(def_id);
+                    let span = resolutions.source_span[def_id];
+                    debug_assert_eq!(span.parent(), None);
+                    Some((def_path_hash, span))
+                })
+                .collect();
+            owner_spans.sort_unstable_by_key(|bn| bn.0);
+            owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
+        }
+        tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
+        tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
+        // Hash visibility information since it does not appear in HIR.
+        resolutions.visibilities.hash_stable(&mut hcx, &mut stable_hasher);
+        resolutions.has_pub_restricted.hash_stable(&mut hcx, &mut stable_hasher);
+        stable_hasher.finish()
+    });
 
-    let crate_hash: Fingerprint = stable_hasher.finish();
     Svh::new(crate_hash.to_smaller_hash())
 }
 
@@ -1263,7 +1266,6 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
         Some(Node::Ty(_)) => node_str("type"),
         Some(Node::TypeBinding(_)) => node_str("type binding"),
         Some(Node::TraitRef(_)) => node_str("trait ref"),
-        Some(Node::Binding(_)) => node_str("local"),
         Some(Node::Pat(_)) => node_str("pat"),
         Some(Node::Param(_)) => node_str("param"),
         Some(Node::Arm(_)) => node_str("arm"),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 8622a620721..070a063c881 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -63,6 +63,15 @@ impl ModuleItems {
         self.foreign_items.iter().copied()
     }
 
+    pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+        self.items
+            .iter()
+            .map(|id| id.def_id)
+            .chain(self.trait_items.iter().map(|id| id.def_id))
+            .chain(self.impl_items.iter().map(|id| id.def_id))
+            .chain(self.foreign_items.iter().map(|id| id.def_id))
+    }
+
     pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
         par_for_each_in(&self.items[..], |&id| f(id))
     }
@@ -102,7 +111,6 @@ pub fn provide(providers: &mut Providers) {
         let hir = tcx.hir();
         hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
     };
-    providers.hir_crate = |tcx, ()| tcx.untracked_crate;
     providers.hir_crate_items = map::hir_crate_items;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
index d56e87bbb47..6896837aa91 100644
--- a/compiler/rustc_middle/src/hir/nested_filter.rs
+++ b/compiler/rustc_middle/src/hir/nested_filter.rs
@@ -8,7 +8,7 @@ use rustc_hir::intravisit::nested_filter::NestedFilter;
 /// constant arguments of types, e.g. in `let _: [(); /* HERE */];`.
 ///
 /// **This is the most common choice.** A very common pattern is
-/// to use `deep_visit_all_item_likes()` as an outer loop,
+/// to use `visit_all_item_likes_in_crate()` as an outer loop,
 /// and to have the visitor that visits the contents of each item
 /// using this setting.
 pub struct OnlyBodies(());
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 00db19019c4..83d3b0100b8 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -4,18 +4,8 @@ use crate::ty::Ty;
 use rustc_hir::HirId;
 use rustc_target::abi::VariantIdx;
 
-#[derive(
-    Clone,
-    Copy,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable,
-    HashStable
-)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum PlaceBase {
     /// A temporary variable.
     Rvalue,
@@ -27,18 +17,8 @@ pub enum PlaceBase {
     Upvar(ty::UpvarId),
 }
 
-#[derive(
-    Clone,
-    Copy,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable,
-    HashStable
-)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum ProjectionKind {
     /// A dereference of a pointer, reference or `Box<T>` of the given type.
     Deref,
@@ -58,18 +38,8 @@ pub enum ProjectionKind {
     Subslice,
 }
 
-#[derive(
-    Clone,
-    Copy,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable,
-    HashStable
-)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct Projection<'tcx> {
     /// Type after the projection is applied.
     pub ty: Ty<'tcx>,
@@ -81,7 +51,8 @@ pub struct Projection<'tcx> {
 /// A `Place` represents how a value is located in memory.
 ///
 /// This is an HIR version of [`rustc_middle::mir::Place`].
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct Place<'tcx> {
     /// The type of the `PlaceBase`
     pub base_ty: Ty<'tcx>,
@@ -94,7 +65,8 @@ pub struct Place<'tcx> {
 /// A `PlaceWithHirId` represents how a value is located in memory.
 ///
 /// This is an HIR version of [`rustc_middle::mir::Place`].
-#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct PlaceWithHirId<'tcx> {
     /// `HirId` of the expression or pattern producing this value.
     pub hir_id: HirId,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 79f94802d20..c6fe3e72103 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -34,7 +34,7 @@ use std::ops::Index;
 /// 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, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct Canonical<'tcx, V> {
     pub max_universe: ty::UniverseIndex,
     pub variables: CanonicalVarInfos<'tcx>,
@@ -53,7 +53,7 @@ pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 /// variables. You will need to supply it later to instantiate the
 /// canonicalized query response.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CanonicalVarValues<'tcx> {
     pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
 }
@@ -173,7 +173,7 @@ pub enum CanonicalTyVarKind {
 /// After we execute a query with a canonicalized key, we get back a
 /// `Canonical<QueryResponse<..>>`. You can use
 /// `instantiate_query_result` to access the data in this result.
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct QueryResponse<'tcx, R> {
     pub var_values: CanonicalVarValues<'tcx>,
     pub region_constraints: QueryRegionConstraints<'tcx>,
@@ -187,7 +187,7 @@ pub struct QueryResponse<'tcx, R> {
     pub value: R,
 }
 
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct QueryRegionConstraints<'tcx> {
     pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
     pub member_constraints: Vec<MemberConstraint<'tcx>>,
@@ -293,7 +293,7 @@ impl<'tcx, V> Canonical<'tcx, V> {
 pub type QueryOutlivesConstraint<'tcx> =
     ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     for <'tcx> {
         crate::infer::canonical::Certainty,
         crate::infer::canonical::CanonicalVarInfo<'tcx>,
@@ -301,7 +301,7 @@ TrivialTypeFoldableAndLiftImpls! {
     }
 }
 
-TrivialTypeFoldableImpls! {
+TrivialTypeTraversalImpls! {
     for <'tcx> {
         crate::infer::canonical::CanonicalVarInfos<'tcx>,
     }
diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs
index 2350a6ab155..55e00c4c0d8 100644
--- a/compiler/rustc_middle/src/infer/mod.rs
+++ b/compiler/rustc_middle/src/infer/mod.rs
@@ -13,7 +13,7 @@ use rustc_span::Span;
 /// ```text
 /// R0 member of [O1..On]
 /// ```
-#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)]
+#[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct MemberConstraint<'tcx> {
     /// The `DefId` of the opaque type causing this constraint: used for error reporting.
     pub opaque_type_def_id: DefId,
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 46c34247d40..ef06c457bf4 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -59,6 +59,7 @@
 #![feature(drain_filter)]
 #![feature(intra_doc_pointers)]
 #![feature(yeet_expr)]
+#![feature(const_option)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 215d8decf2a..4b156de410d 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -2,9 +2,7 @@ use std::cmp;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::{
-    Diagnostic, DiagnosticBuilder, DiagnosticId, EmissionGuarantee, ErrorGuaranteed, MultiSpan,
-};
+use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan};
 use rustc_hir::HirId;
 use rustc_index::vec::IndexVec;
 use rustc_query_system::ich::StableHashingContext;
@@ -227,28 +225,6 @@ impl LintExpectation {
     }
 }
 
-pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
-
-impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
-    /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
-    pub fn build(mut self, msg: &str) -> DiagnosticBuilder<'a, G> {
-        self.0.set_primary_message(msg);
-        self.0.set_is_lint();
-        self.0
-    }
-
-    /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
-    pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
-        LintDiagnosticBuilder(err)
-    }
-}
-
-impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
-    pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
-        LintDiagnosticBuilder(self.0.forget_guarantee())
-    }
-}
-
 pub fn explain_lint_level_source(
     lint: &'static Lint,
     level: Level,
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 33b4dff977e..0e85c60a363 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -18,7 +18,7 @@ macro_rules! span_bug {
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// Lift and TypeFoldable macros
+// Lift and TypeFoldable/TypeVisitable macros
 //
 // When possible, use one of these (relatively) convenient macros to write
 // the impls for you.
@@ -48,7 +48,7 @@ macro_rules! CloneLiftImpls {
 /// Used for types that are `Copy` and which **do not care arena
 /// allocated data** (i.e., don't need to be folded).
 #[macro_export]
-macro_rules! TrivialTypeFoldableImpls {
+macro_rules! TrivialTypeTraversalImpls {
     (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
         $(
             impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
@@ -58,8 +58,10 @@ macro_rules! TrivialTypeFoldableImpls {
                 ) -> ::std::result::Result<$ty, F::Error> {
                     Ok(self)
                 }
+            }
 
-                fn visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
+            impl<$tcx> $crate::ty::visit::TypeVisitable<$tcx> for $ty {
+                fn visit_with<F: $crate::ty::visit::TypeVisitor<$tcx>>(
                     &self,
                     _: &mut F)
                     -> ::std::ops::ControlFlow<F::BreakTy>
@@ -71,7 +73,7 @@ macro_rules! TrivialTypeFoldableImpls {
     };
 
     ($($ty:ty,)+) => {
-        TrivialTypeFoldableImpls! {
+        TrivialTypeTraversalImpls! {
             for <'tcx> {
                 $($ty,)+
             }
@@ -80,15 +82,15 @@ macro_rules! TrivialTypeFoldableImpls {
 }
 
 #[macro_export]
-macro_rules! TrivialTypeFoldableAndLiftImpls {
+macro_rules! TrivialTypeTraversalAndLiftImpls {
     ($($t:tt)*) => {
-        TrivialTypeFoldableImpls! { $($t)* }
+        TrivialTypeTraversalImpls! { $($t)* }
         CloneLiftImpls! { $($t)* }
     }
 }
 
 #[macro_export]
-macro_rules! EnumTypeFoldableImpl {
+macro_rules! EnumTypeTraversalImpl {
     (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
         $($variants:tt)*
     } $(where $($wc:tt)*)*) => {
@@ -99,14 +101,22 @@ macro_rules! EnumTypeFoldableImpl {
                 self,
                 folder: &mut V,
             ) -> ::std::result::Result<Self, V::Error> {
-                EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
+                EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
             }
+        }
+    };
 
-            fn visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
+    (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
+        $($variants:tt)*
+    } $(where $($wc:tt)*)*) => {
+        impl<$($p),*> $crate::ty::visit::TypeVisitable<$tcx> for $s
+            $(where $($wc)*)*
+        {
+            fn visit_with<V: $crate::ty::visit::TypeVisitor<$tcx>>(
                 &self,
                 visitor: &mut V,
             ) -> ::std::ops::ControlFlow<V::BreakTy> {
-                EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
+                EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
             }
         }
     };
@@ -120,7 +130,7 @@ macro_rules! EnumTypeFoldableImpl {
     (@FoldVariants($this:expr, $folder:expr)
      input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @FoldVariants($this, $folder)
                 input($($input)*)
                 output(
@@ -137,7 +147,7 @@ macro_rules! EnumTypeFoldableImpl {
     (@FoldVariants($this:expr, $folder:expr)
      input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @FoldVariants($this, $folder)
                 input($($input)*)
                 output(
@@ -155,7 +165,7 @@ macro_rules! EnumTypeFoldableImpl {
     (@FoldVariants($this:expr, $folder:expr)
      input( ($variant:path), $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @FoldVariants($this, $folder)
                 input($($input)*)
                 output(
@@ -174,12 +184,12 @@ macro_rules! EnumTypeFoldableImpl {
     (@VisitVariants($this:expr, $visitor:expr)
      input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @VisitVariants($this, $visitor)
                 input($($input)*)
                 output(
                     $variant ( $($variant_arg),* ) => {
-                        $($crate::ty::fold::TypeFoldable::visit_with(
+                        $($crate::ty::visit::TypeVisitable::visit_with(
                             $variant_arg, $visitor
                         )?;)*
                         ::std::ops::ControlFlow::CONTINUE
@@ -192,12 +202,12 @@ macro_rules! EnumTypeFoldableImpl {
     (@VisitVariants($this:expr, $visitor:expr)
      input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @VisitVariants($this, $visitor)
                 input($($input)*)
                 output(
                     $variant { $($variant_arg),* } => {
-                        $($crate::ty::fold::TypeFoldable::visit_with(
+                        $($crate::ty::visit::TypeVisitable::visit_with(
                             $variant_arg, $visitor
                         )?;)*
                         ::std::ops::ControlFlow::CONTINUE
@@ -210,7 +220,7 @@ macro_rules! EnumTypeFoldableImpl {
     (@VisitVariants($this:expr, $visitor:expr)
      input( ($variant:path), $($input:tt)*)
      output( $($output:tt)*) ) => {
-        EnumTypeFoldableImpl!(
+        EnumTypeTraversalImpl!(
             @VisitVariants($this, $visitor)
                 input($($input)*)
                 output(
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
new file mode 100644
index 00000000000..78080fcd581
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -0,0 +1,147 @@
+use crate::mir::graph_cyclic_cache::GraphIsCyclicCache;
+use crate::mir::predecessors::{PredecessorCache, Predecessors};
+use crate::mir::switch_sources::{SwitchSourceCache, SwitchSources};
+use crate::mir::traversal::PostorderCache;
+use crate::mir::{BasicBlock, BasicBlockData, Successors, START_BLOCK};
+
+use rustc_data_structures::graph;
+use rustc_data_structures::graph::dominators::{dominators, Dominators};
+use rustc_index::vec::IndexVec;
+
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
+pub struct BasicBlocks<'tcx> {
+    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+    predecessor_cache: PredecessorCache,
+    switch_source_cache: SwitchSourceCache,
+    is_cyclic: GraphIsCyclicCache,
+    postorder_cache: PostorderCache,
+}
+
+impl<'tcx> BasicBlocks<'tcx> {
+    #[inline]
+    pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
+        BasicBlocks {
+            basic_blocks,
+            predecessor_cache: PredecessorCache::new(),
+            switch_source_cache: SwitchSourceCache::new(),
+            is_cyclic: GraphIsCyclicCache::new(),
+            postorder_cache: PostorderCache::new(),
+        }
+    }
+
+    /// Returns true if control-flow graph contains a cycle reachable from the `START_BLOCK`.
+    #[inline]
+    pub fn is_cfg_cyclic(&self) -> bool {
+        self.is_cyclic.is_cyclic(self)
+    }
+
+    #[inline]
+    pub fn dominators(&self) -> Dominators<BasicBlock> {
+        dominators(&self)
+    }
+
+    /// Returns predecessors for each basic block.
+    #[inline]
+    pub fn predecessors(&self) -> &Predecessors {
+        self.predecessor_cache.compute(&self.basic_blocks)
+    }
+
+    /// Returns basic blocks in a postorder.
+    #[inline]
+    pub fn postorder(&self) -> &[BasicBlock] {
+        self.postorder_cache.compute(&self.basic_blocks)
+    }
+
+    /// `switch_sources()[&(target, switch)]` returns a list of switch
+    /// values that lead to a `target` block from a `switch` block.
+    #[inline]
+    pub fn switch_sources(&self) -> &SwitchSources {
+        self.switch_source_cache.compute(&self.basic_blocks)
+    }
+
+    /// Returns mutable reference to basic blocks. Invalidates CFG cache.
+    #[inline]
+    pub fn as_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        self.invalidate_cfg_cache();
+        &mut self.basic_blocks
+    }
+
+    /// Get mutable access to basic blocks without invalidating the CFG cache.
+    ///
+    /// By calling this method instead of e.g. [`BasicBlocks::as_mut`] you promise not to change
+    /// the CFG. This means that
+    ///
+    ///  1) The number of basic blocks remains unchanged
+    ///  2) The set of successors of each terminator remains unchanged.
+    ///  3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
+    ///     kind is not changed.
+    ///
+    /// If any of these conditions cannot be upheld, you should call [`BasicBlocks::invalidate_cfg_cache`].
+    #[inline]
+    pub fn as_mut_preserves_cfg(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        &mut self.basic_blocks
+    }
+
+    /// Invalidates cached information about the CFG.
+    ///
+    /// You will only ever need this if you have also called [`BasicBlocks::as_mut_preserves_cfg`].
+    /// All other methods that allow you to mutate the basic blocks also call this method
+    /// themselves, thereby avoiding any risk of accidentaly cache invalidation.
+    pub fn invalidate_cfg_cache(&mut self) {
+        self.predecessor_cache.invalidate();
+        self.switch_source_cache.invalidate();
+        self.is_cyclic.invalidate();
+        self.postorder_cache.invalidate();
+    }
+}
+
+impl<'tcx> std::ops::Deref for BasicBlocks<'tcx> {
+    type Target = IndexVec<BasicBlock, BasicBlockData<'tcx>>;
+
+    #[inline]
+    fn deref(&self) -> &IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        &self.basic_blocks
+    }
+}
+
+impl<'tcx> graph::DirectedGraph for BasicBlocks<'tcx> {
+    type Node = BasicBlock;
+}
+
+impl<'tcx> graph::WithNumNodes for BasicBlocks<'tcx> {
+    #[inline]
+    fn num_nodes(&self) -> usize {
+        self.basic_blocks.len()
+    }
+}
+
+impl<'tcx> graph::WithStartNode for BasicBlocks<'tcx> {
+    #[inline]
+    fn start_node(&self) -> Self::Node {
+        START_BLOCK
+    }
+}
+
+impl<'tcx> graph::WithSuccessors for BasicBlocks<'tcx> {
+    #[inline]
+    fn successors(&self, node: Self::Node) -> <Self as graph::GraphSuccessors<'_>>::Iter {
+        self.basic_blocks[node].terminator().successors()
+    }
+}
+
+impl<'a, 'b> graph::GraphSuccessors<'b> for BasicBlocks<'a> {
+    type Item = BasicBlock;
+    type Iter = Successors<'b>;
+}
+
+impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for BasicBlocks<'tcx> {
+    type Item = BasicBlock;
+    type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
+}
+
+impl<'tcx> graph::WithPredecessors for BasicBlocks<'tcx> {
+    #[inline]
+    fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
+        self.predecessors()[node].iter().copied()
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 2336d460407..efa9464529e 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -100,7 +100,7 @@ impl From<InjectedExpressionId> for ExpressionOperandId {
     }
 }
 
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
 pub enum CoverageKind {
     Counter {
         function_source_hash: u64,
@@ -148,18 +148,8 @@ impl Debug for CoverageKind {
     }
 }
 
-#[derive(
-    Clone,
-    TyEncodable,
-    TyDecodable,
-    Hash,
-    HashStable,
-    TypeFoldable,
-    PartialEq,
-    Eq,
-    PartialOrd,
-    Ord
-)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct CodeRegion {
     pub file_name: Symbol,
     pub start_line: u32,
@@ -178,7 +168,8 @@ impl Debug for CodeRegion {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum Op {
     Subtract,
     Add,
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
index 1279f5aee36..f97bf2883b3 100644
--- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -58,6 +58,6 @@ impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     GraphIsCyclicCache,
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 10c4ea63a68..ae333846f06 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -160,12 +160,18 @@ impl AllocError {
 }
 
 /// The information that makes up a memory access: offset and size.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
 pub struct AllocRange {
     pub start: Size,
     pub size: Size,
 }
 
+impl fmt::Debug for AllocRange {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "[{:#x}..{:#x}]", self.start.bytes(), self.end().bytes())
+    }
+}
+
 /// Free-starting constructor for less syntactic overhead.
 #[inline(always)]
 pub fn alloc_range(start: Size, size: Size) -> AllocRange {
@@ -173,6 +179,11 @@ pub fn alloc_range(start: Size, size: Size) -> AllocRange {
 }
 
 impl AllocRange {
+    #[inline]
+    pub fn from(r: Range<Size>) -> Self {
+        alloc_range(r.start, r.end - r.start) // `Size` subtraction (overflow-checked)
+    }
+
     #[inline(always)]
     pub fn end(self) -> Size {
         self.start + self.size // This does overflow checking.
@@ -537,21 +548,26 @@ impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
 /// Relocations.
 impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Returns all relocations overlapping with the given pointer-offset pair.
-    pub fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] {
+    fn get_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> &[(Size, Tag)] {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
         let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
         self.relocations.range(Size::from_bytes(start)..range.end())
     }
 
+    /// Returns whether this allocation has relocations overlapping with the given range.
+    ///
+    /// Note: this function exists to allow `get_relocations` to be private, in order to somewhat
+    /// limit access to relocations outside of the `Allocation` abstraction.
+    ///
+    pub fn has_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> bool {
+        !self.get_relocations(cx, range).is_empty()
+    }
+
     /// Checks that there are no relocations overlapping with the given range.
     #[inline(always)]
     fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
-        if self.get_relocations(cx, range).is_empty() {
-            Ok(())
-        } else {
-            Err(AllocError::ReadPointerAsBytes)
-        }
+        if self.has_relocations(cx, range) { Err(AllocError::ReadPointerAsBytes) } else { Ok(()) }
     }
 
     /// Removes all relocations inside the given range.
@@ -1084,9 +1100,9 @@ impl InitMask {
     /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
     /// indexes for the first contiguous span of the uninitialized access.
     #[inline]
-    pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> {
+    pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), AllocRange> {
         if end > self.len {
-            return Err(self.len..end);
+            return Err(AllocRange::from(self.len..end));
         }
 
         let uninit_start = self.find_bit(start, end, false);
@@ -1094,7 +1110,7 @@ impl InitMask {
         match uninit_start {
             Some(uninit_start) => {
                 let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
-                Err(uninit_start..uninit_end)
+                Err(AllocRange::from(uninit_start..uninit_end))
             }
             None => Ok(()),
         }
@@ -1165,19 +1181,17 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     ///
     /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
     /// indexes of the first contiguous uninitialized access.
-    fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
+    fn is_init(&self, range: AllocRange) -> Result<(), AllocRange> {
         self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
     }
 
     /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
     /// error which will report the first range of bytes which is uninitialized.
     fn check_init(&self, range: AllocRange) -> AllocResult {
-        self.is_init(range).map_err(|idx_range| {
+        self.is_init(range).map_err(|uninit_range| {
             AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
-                access_offset: range.start,
-                access_size: range.size,
-                uninit_offset: idx_range.start,
-                uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
+                access: range,
+                uninit: uninit_range,
             }))
         })
     }
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index a33a2921f57..795f23edb31 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,4 +1,4 @@
-use super::{AllocId, ConstAlloc, Pointer, Scalar};
+use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
 
 use crate::mir::interpret::ConstValue;
 use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
@@ -29,7 +29,7 @@ impl From<ErrorGuaranteed> for ErrorHandled {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     ErrorHandled,
 }
 
@@ -162,9 +162,9 @@ impl fmt::Display for InvalidProgramInfo<'_> {
             AlreadyReported(ErrorGuaranteed { .. }) => {
                 write!(f, "encountered constants with type errors, stopping evaluation")
             }
-            Layout(ref err) => write!(f, "{}", err),
-            FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
-            SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
+            Layout(ref err) => write!(f, "{err}"),
+            FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
+            SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
         }
     }
 }
@@ -186,7 +186,7 @@ pub enum CheckInAllocMsg {
 
 impl fmt::Display for CheckInAllocMsg {
     /// When this is printed as an error the context looks like this:
-    /// "{msg}0x01 is not a valid pointer".
+    /// "{msg}{pointer} is a dangling pointer".
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(
             f,
@@ -194,9 +194,9 @@ impl fmt::Display for CheckInAllocMsg {
             match *self {
                 CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
                 CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
-                CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
+                CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ",
                 CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
-                CheckInAllocMsg::InboundsTest => "",
+                CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ",
             }
         )
     }
@@ -205,14 +205,10 @@ impl fmt::Display for CheckInAllocMsg {
 /// Details of an access to uninitialized bytes where it is not allowed.
 #[derive(Debug)]
 pub struct UninitBytesAccess {
-    /// Location of the original memory access.
-    pub access_offset: Size,
-    /// Size of the original memory access.
-    pub access_size: Size,
-    /// Location of the first uninitialized byte that was accessed.
-    pub uninit_offset: Size,
-    /// Number of consecutive uninitialized bytes that were accessed.
-    pub uninit_size: Size,
+    /// Range of the original memory access.
+    pub access: AllocRange,
+    /// Range of the uninit memory that was encountered. (Might not be maximal.)
+    pub uninit: AllocRange,
 }
 
 /// Information about a size mismatch.
@@ -308,100 +304,85 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use UndefinedBehaviorInfo::*;
         match self {
-            Ub(msg) => write!(f, "{}", msg),
+            Ub(msg) => write!(f, "{msg}"),
             Unreachable => write!(f, "entering unreachable code"),
             BoundsCheckFailed { ref len, ref index } => {
-                write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
+                write!(f, "indexing out of bounds: the len is {len} but the index is {index}")
             }
             DivisionByZero => write!(f, "dividing by zero"),
             RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
             DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
             RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
             PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
-            InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
+            InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
             InvalidVtableDropFn(sig) => write!(
                 f,
-                "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
-                sig
+                "invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type",
             ),
             InvalidVtableSize => {
                 write!(f, "invalid vtable: size is bigger than largest supported object")
             }
-            InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
+            InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"),
             UnterminatedCString(p) => write!(
                 f,
-                "reading a null-terminated string starting at {:?} with no null found before end of allocation",
-                p,
+                "reading a null-terminated string starting at {p:?} with no null found before end of allocation",
             ),
             PointerUseAfterFree(a) => {
-                write!(f, "pointer to {} was dereferenced after this allocation got freed", a)
+                write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => {
                 write!(
                     f,
-                    "{}{alloc_id} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
-                    msg,
-                    alloc_id = alloc_id,
+                    "{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
                     alloc_size = alloc_size.bytes(),
-                    ptr_offset = ptr_offset,
                 )
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!(
                 f,
-                "{}{alloc_id} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
-                msg,
-                alloc_id = alloc_id,
+                "{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
                 alloc_size = alloc_size.bytes(),
                 ptr_size = ptr_size.bytes(),
                 ptr_size_p = pluralize!(ptr_size.bytes()),
-                ptr_offset = ptr_offset,
             ),
-            DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
-                write!(f, "null pointer is not a valid pointer for this operation")
-            }
-            DanglingIntPointer(0, msg) => {
-                write!(f, "{}null pointer is not a valid pointer", msg)
-            }
             DanglingIntPointer(i, msg) => {
-                write!(f, "{}0x{:x} is not a valid pointer", msg, i)
+                write!(
+                    f,
+                    "{msg}{pointer} is a dangling pointer (it has no provenance)",
+                    pointer = Pointer::<Option<AllocId>>::from_addr(*i),
+                )
             }
             AlignmentCheckFailed { required, has } => write!(
                 f,
-                "accessing memory with alignment {}, but alignment {} is required",
-                has.bytes(),
-                required.bytes()
+                "accessing memory with alignment {has}, but alignment {required} is required",
+                has = has.bytes(),
+                required = required.bytes()
             ),
-            WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
-            DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
+            WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
+            DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
             ValidationFailure { path: None, msg } => {
-                write!(f, "constructing invalid value: {}", msg)
+                write!(f, "constructing invalid value: {msg}")
             }
             ValidationFailure { path: Some(path), msg } => {
-                write!(f, "constructing invalid value at {}: {}", path, msg)
+                write!(f, "constructing invalid value at {path}: {msg}")
             }
             InvalidBool(b) => {
-                write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
+                write!(f, "interpreting an invalid 8-bit value as a bool: 0x{b:02x}")
             }
             InvalidChar(c) => {
-                write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
+                write!(f, "interpreting an invalid 32-bit value as a char: 0x{c:08x}")
             }
-            InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val),
+            InvalidTag(val) => write!(f, "enum value has invalid tag: {val:x}"),
             InvalidFunctionPointer(p) => {
-                write!(f, "using {:?} as function pointer but it does not point to a function", p)
+                write!(f, "using {p:?} as function pointer but it does not point to a function")
             }
-            InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
-            InvalidUninitBytes(Some((alloc, access))) => write!(
+            InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
+            InvalidUninitBytes(Some((alloc, info))) => write!(
                 f,
-                "reading {} byte{} of memory starting at {:?}, \
-                 but {} byte{} {} uninitialized starting at {:?}, \
+                "reading memory at {alloc:?}{access:?}, \
+                 but memory is uninitialized at {uninit:?}, \
                  and this operation requires initialized memory",
-                access.access_size.bytes(),
-                pluralize!(access.access_size.bytes()),
-                Pointer::new(*alloc, access.access_offset),
-                access.uninit_size.bytes(),
-                pluralize!(access.uninit_size.bytes()),
-                pluralize!("is", access.uninit_size.bytes()),
-                Pointer::new(*alloc, access.uninit_offset),
+                access = info.access,
+                uninit = info.uninit,
             ),
             InvalidUninitBytes(None) => write!(
                 f,
@@ -410,8 +391,7 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
             DeadLocal => write!(f, "accessing a dead local variable"),
             ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
                 f,
-                "scalar size mismatch: expected {} bytes but got {} bytes instead",
-                target_size, data_size
+                "scalar size mismatch: expected {target_size} bytes but got {data_size} bytes instead",
             ),
             UninhabitedEnumVariantWritten => {
                 write!(f, "writing discriminant of an uninhabited enum")
@@ -445,13 +425,13 @@ impl fmt::Display for UnsupportedOpInfo {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use UnsupportedOpInfo::*;
         match self {
-            Unsupported(ref msg) => write!(f, "{}", msg),
+            Unsupported(ref msg) => write!(f, "{msg}"),
             ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
             PartialPointerOverwrite(ptr) => {
-                write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
+                write!(f, "unable to overwrite parts of a pointer in memory at {ptr:?}")
             }
-            ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
-            ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
+            ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({did:?})"),
+            ReadExternStatic(did) => write!(f, "cannot read from extern static ({did:?})"),
         }
     }
 }
@@ -534,11 +514,11 @@ impl fmt::Display for InterpError<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use InterpError::*;
         match *self {
-            Unsupported(ref msg) => write!(f, "{}", msg),
-            InvalidProgram(ref msg) => write!(f, "{}", msg),
-            UndefinedBehavior(ref msg) => write!(f, "{}", msg),
-            ResourceExhaustion(ref msg) => write!(f, "{}", msg),
-            MachineStop(ref msg) => write!(f, "{}", msg),
+            Unsupported(ref msg) => write!(f, "{msg}"),
+            InvalidProgram(ref msg) => write!(f, "{msg}"),
+            UndefinedBehavior(ref msg) => write!(f, "{msg}"),
+            ResourceExhaustion(ref msg) => write!(f, "{msg}"),
+            MachineStop(ref msg) => write!(f, "{msg}"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 8733a85ef3f..698024b2330 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -190,11 +190,7 @@ impl fmt::Debug for AllocId {
     }
 }
 
-impl fmt::Display for AllocId {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(self, f)
-    }
-}
+// No "Display" since AllocIds are not usually user-visible.
 
 #[derive(TyDecodable, TyEncodable)]
 enum AllocDiscriminant {
@@ -470,7 +466,7 @@ impl<'tcx> TyCtxt<'tcx> {
             return alloc_id;
         }
         let id = alloc_map.reserve();
-        debug!("creating alloc {:?} with id {}", alloc, id);
+        debug!("creating alloc {alloc:?} with id {id:?}");
         alloc_map.alloc_map.insert(id, alloc.clone());
         alloc_map.dedup.insert(alloc, id);
         id
@@ -538,7 +534,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> {
         match self.get_global_alloc(id) {
             Some(alloc) => alloc,
-            None => bug!("could not find allocation for {}", id),
+            None => bug!("could not find allocation for {id:?}"),
         }
     }
 
@@ -546,7 +542,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// call this function twice, even with the same `Allocation` will ICE the compiler.
     pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) {
         if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) {
-            bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old);
+            bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}");
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 26da93b9dce..d4cdf45d186 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -144,7 +144,7 @@ impl Provenance for AllocId {
         }
         // Print offset only if it is non-zero.
         if ptr.offset.bytes() > 0 {
-            write!(f, "+0x{:x}", ptr.offset.bytes())?;
+            write!(f, "+{:#x}", ptr.offset.bytes())?;
         }
         Ok(())
     }
@@ -181,7 +181,17 @@ impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self.provenance {
             Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
-            None => write!(f, "0x{:x}", self.offset.bytes()),
+            None => write!(f, "{:#x}[noalloc]", self.offset.bytes()),
+        }
+    }
+}
+
+impl<Tag: Provenance> fmt::Display for Pointer<Option<Tag>> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.provenance.is_none() && self.offset.bytes() == 0 {
+            write!(f, "null pointer")
+        } else {
+            fmt::Debug::fmt(self, f)
         }
     }
 }
@@ -227,8 +237,13 @@ impl<Tag> Pointer<Option<Tag>> {
 
 impl<Tag> Pointer<Option<Tag>> {
     #[inline(always)]
+    pub fn from_addr(addr: u64) -> Self {
+        Pointer { provenance: None, offset: Size::from_bytes(addr) }
+    }
+
+    #[inline(always)]
     pub fn null() -> Self {
-        Pointer { provenance: None, offset: Size::ZERO }
+        Pointer::from_addr(0)
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 575147feebc..786927e2dad 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -1,8 +1,8 @@
 use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
 
 use crate::mir;
-use crate::ty::fold::TypeFoldable;
 use crate::ty::subst::InternalSubsts;
+use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
 use rustc_hir::def_id::DefId;
 use rustc_span::{Span, DUMMY_SP};
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index e80918d5e5d..22bbe29c105 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -29,11 +29,14 @@ pub struct ConstAlloc<'tcx> {
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
 #[derive(HashStable)]
 pub enum ConstValue<'tcx> {
-    /// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
+    /// Used only for types with `layout::abi::Scalar` ABI.
     ///
     /// Not using the enum `Value` to encode that this must not be `Uninit`.
     Scalar(Scalar),
 
+    /// Only used for ZSTs.
+    ZeroSized,
+
     /// Used only for `&[u8]` and `&str`
     Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
 
@@ -55,6 +58,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
         Some(match self {
             ConstValue::Scalar(s) => ConstValue::Scalar(s),
+            ConstValue::ZeroSized => ConstValue::ZeroSized,
             ConstValue::Slice { data, start, end } => {
                 ConstValue::Slice { data: tcx.lift(data)?, start, end }
             }
@@ -69,7 +73,7 @@ impl<'tcx> ConstValue<'tcx> {
     #[inline]
     pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
         match *self {
-            ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None,
+            ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
             ConstValue::Scalar(val) => Some(val),
         }
     }
@@ -111,10 +115,6 @@ impl<'tcx> ConstValue<'tcx> {
     pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
         ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
     }
-
-    pub fn zst() -> Self {
-        Self::Scalar(Scalar::ZST)
-    }
 }
 
 /// A `Scalar` represents an immediate, primitive value existing outside of a
@@ -167,7 +167,7 @@ impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
-            Scalar::Int(int) => write!(f, "0x{:x}", int),
+            Scalar::Int(int) => write!(f, "{:#x}", int),
         }
     }
 }
@@ -194,8 +194,6 @@ impl<Tag> From<ScalarInt> for Scalar<Tag> {
 }
 
 impl<Tag> Scalar<Tag> {
-    pub const ZST: Self = Scalar::Int(ScalarInt::ZST);
-
     #[inline(always)]
     pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
         Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap())
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index ad33a54e0a2..26314e3fe8e 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -5,12 +5,12 @@
 use crate::mir::interpret::{
     AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar,
 };
-use crate::mir::traversal::PostorderCache;
 use crate::mir::visit::MirVisitable;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
 
@@ -26,8 +26,7 @@ use rustc_target::abi::{Size, VariantIdx};
 use polonius_engine::Atom;
 pub use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{dominators, Dominators};
-use rustc_data_structures::graph::{self, GraphSuccessors};
+use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitMatrix;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_serialize::{Decodable, Encodable};
@@ -42,11 +41,10 @@ use std::fmt::{self, Debug, Display, Formatter, Write};
 use std::ops::{ControlFlow, Index, IndexMut};
 use std::{iter, mem};
 
-use self::graph_cyclic_cache::GraphIsCyclicCache;
-use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
-use self::switch_sources::{SwitchSourceCache, SwitchSources};
+pub use basic_blocks::BasicBlocks;
 
+mod basic_blocks;
 pub mod coverage;
 mod generic_graph;
 pub mod generic_graphviz;
@@ -68,6 +66,7 @@ pub use terminator::*;
 
 pub mod traversal;
 mod type_foldable;
+mod type_visitable;
 pub mod visit;
 
 pub use self::generic_graph::graphviz_safe_def_name;
@@ -136,7 +135,7 @@ impl MirPhase {
 
 /// Where a specific `mir::Body` comes from.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)]
+#[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub struct MirSource<'tcx> {
     pub instance: InstanceDef<'tcx>,
 
@@ -166,7 +165,7 @@ impl<'tcx> MirSource<'tcx> {
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct GeneratorInfo<'tcx> {
     /// The yield type of the function, if it is a generator.
     pub yield_ty: Option<Ty<'tcx>>,
@@ -183,11 +182,11 @@ pub struct GeneratorInfo<'tcx> {
 }
 
 /// The lowered representation of a single function.
-#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Body<'tcx> {
     /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`]
     /// that indexes into this vector.
-    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+    pub basic_blocks: BasicBlocks<'tcx>,
 
     /// Records how far through the "desugaring and optimization" process this particular
     /// MIR has traversed. This is particularly useful when inlining, since in that context
@@ -255,11 +254,6 @@ pub struct Body<'tcx> {
     /// potentially allow things like `[u8; std::mem::size_of::<T>() * 0]` due to this.
     pub is_polymorphic: bool,
 
-    predecessor_cache: PredecessorCache,
-    switch_source_cache: SwitchSourceCache,
-    is_cyclic: GraphIsCyclicCache,
-    postorder_cache: PostorderCache,
-
     pub tainted_by_errors: Option<ErrorGuaranteed>,
 }
 
@@ -287,7 +281,7 @@ impl<'tcx> Body<'tcx> {
         let mut body = Body {
             phase: MirPhase::Built,
             source,
-            basic_blocks,
+            basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes,
             generator: generator_kind.map(|generator_kind| {
                 Box::new(GeneratorInfo {
@@ -305,10 +299,6 @@ impl<'tcx> Body<'tcx> {
             span,
             required_consts: Vec::new(),
             is_polymorphic: false,
-            predecessor_cache: PredecessorCache::new(),
-            switch_source_cache: SwitchSourceCache::new(),
-            is_cyclic: GraphIsCyclicCache::new(),
-            postorder_cache: PostorderCache::new(),
             tainted_by_errors,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
@@ -324,7 +314,7 @@ impl<'tcx> Body<'tcx> {
         let mut body = Body {
             phase: MirPhase::Built,
             source: MirSource::item(CRATE_DEF_ID.to_def_id()),
-            basic_blocks,
+            basic_blocks: BasicBlocks::new(basic_blocks),
             source_scopes: IndexVec::new(),
             generator: None,
             local_decls: IndexVec::new(),
@@ -335,10 +325,6 @@ impl<'tcx> Body<'tcx> {
             required_consts: Vec::new(),
             var_debug_info: Vec::new(),
             is_polymorphic: false,
-            predecessor_cache: PredecessorCache::new(),
-            switch_source_cache: SwitchSourceCache::new(),
-            is_cyclic: GraphIsCyclicCache::new(),
-            postorder_cache: PostorderCache::new(),
             tainted_by_errors: None,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
@@ -352,48 +338,7 @@ impl<'tcx> Body<'tcx> {
 
     #[inline]
     pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
-        // Because the user could mutate basic block terminators via this reference, we need to
-        // invalidate the caches.
-        //
-        // FIXME: Use a finer-grained API for this, so only transformations that alter terminators
-        // invalidate the caches.
-        self.predecessor_cache.invalidate();
-        self.switch_source_cache.invalidate();
-        self.is_cyclic.invalidate();
-        self.postorder_cache.invalidate();
-        &mut self.basic_blocks
-    }
-
-    #[inline]
-    pub fn basic_blocks_and_local_decls_mut(
-        &mut self,
-    ) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
-        self.predecessor_cache.invalidate();
-        self.switch_source_cache.invalidate();
-        self.is_cyclic.invalidate();
-        self.postorder_cache.invalidate();
-        (&mut self.basic_blocks, &mut self.local_decls)
-    }
-
-    #[inline]
-    pub fn basic_blocks_local_decls_mut_and_var_debug_info(
-        &mut self,
-    ) -> (
-        &mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-        &mut LocalDecls<'tcx>,
-        &mut Vec<VarDebugInfo<'tcx>>,
-    ) {
-        self.predecessor_cache.invalidate();
-        self.switch_source_cache.invalidate();
-        self.is_cyclic.invalidate();
-        self.postorder_cache.invalidate();
-        (&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
-    }
-
-    /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
-    /// `START_BLOCK`.
-    pub fn is_cfg_cyclic(&self) -> bool {
-        self.is_cyclic.is_cyclic(self)
+        self.basic_blocks.as_mut()
     }
 
     #[inline]
@@ -467,14 +412,6 @@ impl<'tcx> Body<'tcx> {
         self.local_decls.drain(self.arg_count + 1..)
     }
 
-    /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
-    /// invalidating statement indices in `Location`s.
-    pub fn make_statement_nop(&mut self, location: Location) {
-        let block = &mut self.basic_blocks[location.block];
-        debug_assert!(location.statement_index < block.statements.len());
-        block.statements[location.statement_index].make_nop()
-    }
-
     /// Returns the source info associated with `location`.
     pub fn source_info(&self, location: Location) -> &SourceInfo {
         let block = &self[location.block];
@@ -511,23 +448,6 @@ impl<'tcx> Body<'tcx> {
     }
 
     #[inline]
-    pub fn predecessors(&self) -> &Predecessors {
-        self.predecessor_cache.compute(&self.basic_blocks)
-    }
-
-    /// `body.switch_sources()[&(target, switch)]` returns a list of switch
-    /// values that lead to a `target` block from a `switch` block.
-    #[inline]
-    pub fn switch_sources(&self) -> &SwitchSources {
-        self.switch_source_cache.compute(&self.basic_blocks)
-    }
-
-    #[inline]
-    pub fn dominators(&self) -> Dominators<BasicBlock> {
-        dominators(self)
-    }
-
-    #[inline]
     pub fn yield_ty(&self) -> Option<Ty<'tcx>> {
         self.generator.as_ref().and_then(|generator| generator.yield_ty)
     }
@@ -571,11 +491,11 @@ impl<'tcx> Index<BasicBlock> for Body<'tcx> {
 impl<'tcx> IndexMut<BasicBlock> for Body<'tcx> {
     #[inline]
     fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> {
-        &mut self.basic_blocks_mut()[index]
+        &mut self.basic_blocks.as_mut()[index]
     }
 }
 
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub enum ClearCrossCrate<T> {
     Clear,
     Set(T),
@@ -736,7 +656,7 @@ pub enum ImplicitSelfKind {
     None,
 }
 
-TrivialTypeFoldableAndLiftImpls! { BindingForm<'tcx>, }
+TrivialTypeTraversalAndLiftImpls! { BindingForm<'tcx>, }
 
 mod binding_form_impl {
     use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -781,7 +701,7 @@ pub struct BlockTailInfo {
 ///
 /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
 /// argument, or the return place.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct LocalDecl<'tcx> {
     /// Whether this is a mutable binding (i.e., `let x` or `let mut x`).
     ///
@@ -916,7 +836,7 @@ static_assert_size!(LocalDecl<'_>, 56);
 ///
 /// Not used for non-StaticRef temporaries, the return place, or anonymous
 /// function parameters.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum LocalInfo<'tcx> {
     /// A user-defined local variable or function parameter
     ///
@@ -1055,7 +975,7 @@ impl<'tcx> LocalDecl<'tcx> {
     }
 }
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum VarDebugInfoContents<'tcx> {
     /// NOTE(eddyb) There's an unenforced invariant that this `Place` is
     /// based on a `Local`, not a `Static`, and contains no indexing.
@@ -1073,7 +993,7 @@ impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
 }
 
 /// Debug information pertaining to a user variable.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct VarDebugInfo<'tcx> {
     pub name: Symbol,
 
@@ -1128,8 +1048,10 @@ impl BasicBlock {
 ///////////////////////////////////////////////////////////////////////////
 // BasicBlockData
 
+/// Data for a basic block, including a list of its statements.
+///
 /// See [`BasicBlock`] for documentation on what basic blocks are at a high level.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct BasicBlockData<'tcx> {
     /// List of statements in this block.
     pub statements: Vec<Statement<'tcx>>,
@@ -1159,7 +1081,7 @@ impl<'tcx> BasicBlockData<'tcx> {
     /// Accessor for terminator.
     ///
     /// Terminator may not be None after construction of the basic block is complete. This accessor
-    /// provides a convenience way to reach the terminator.
+    /// provides a convenient way to reach the terminator.
     #[inline]
     pub fn terminator(&self) -> &Terminator<'tcx> {
         self.terminator.as_ref().expect("invalid terminator state")
@@ -1366,7 +1288,8 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
 ///////////////////////////////////////////////////////////////////////////
 // Statements
 
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+/// A statement in a basic block, including information about its source code.
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Statement<'tcx> {
     pub source_info: SourceInfo,
     pub kind: StatementKind<'tcx>,
@@ -1732,7 +1655,7 @@ impl SourceScope {
     }
 }
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct SourceScopeData<'tcx> {
     pub span: Span,
     pub parent_scope: Option<SourceScope>,
@@ -1788,7 +1711,7 @@ impl<'tcx> Operand<'tcx> {
         Operand::Constant(Box::new(Constant {
             span,
             user_ty: None,
-            literal: ConstantKind::Val(ConstValue::zst(), ty),
+            literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
         }))
     }
 
@@ -1901,12 +1824,10 @@ impl BorrowKind {
         }
     }
 
-    pub fn describe_mutability(&self) -> String {
+    pub fn describe_mutability(&self) -> &str {
         match *self {
-            BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => {
-                "immutable".to_string()
-            }
-            BorrowKind::Mut { .. } => "mutable".to_string(),
+            BorrowKind::Shared | BorrowKind::Shallow | BorrowKind::Unique => "immutable",
+            BorrowKind::Mut { .. } => "mutable",
         }
     }
 }
@@ -2273,7 +2194,7 @@ impl<'tcx> ConstantKind<'tcx> {
 
     #[inline]
     pub fn zero_sized(ty: Ty<'tcx>) -> Self {
-        let cv = ConstValue::Scalar(Scalar::ZST);
+        let cv = ConstValue::ZeroSized;
         Self::Val(cv, ty)
     }
 
@@ -2498,7 +2419,7 @@ impl<'tcx> ConstantKind<'tcx> {
 /// The first will lead to the constraint `w: &'1 str` (for some
 /// inferred region `'1`). The second will lead to the constraint `w:
 /// &'static str`.
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct UserTypeProjections {
     pub contents: Vec<(UserTypeProjection, Span)>,
 }
@@ -2615,7 +2536,7 @@ impl UserTypeProjection {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! { ProjectionKind, }
+TrivialTypeTraversalAndLiftImpls! { ProjectionKind, }
 
 impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
@@ -2624,7 +2545,9 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
             projs: self.projs.try_fold_with(folder)?,
         })
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for UserTypeProjection {
     fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
         self.base.visit_with(visitor)
         // Note: there's nothing in `self.proj` to visit.
@@ -2847,6 +2770,13 @@ fn pretty_print_const_value<'tcx>(
                 fmt.write_str(&cx.into_buffer())?;
                 return Ok(());
             }
+            (ConstValue::ZeroSized, ty::FnDef(d, s)) => {
+                let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
+                cx.print_alloc_ids = true;
+                let cx = cx.print_value_path(*d, s)?;
+                fmt.write_str(&cx.into_buffer())?;
+                return Ok(());
+            }
             // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
             // their fields instead of just dumping the memory.
             _ => {}
@@ -2860,48 +2790,6 @@ fn pretty_print_const_value<'tcx>(
     })
 }
 
-impl<'tcx> graph::DirectedGraph for Body<'tcx> {
-    type Node = BasicBlock;
-}
-
-impl<'tcx> graph::WithNumNodes for Body<'tcx> {
-    #[inline]
-    fn num_nodes(&self) -> usize {
-        self.basic_blocks.len()
-    }
-}
-
-impl<'tcx> graph::WithStartNode for Body<'tcx> {
-    #[inline]
-    fn start_node(&self) -> Self::Node {
-        START_BLOCK
-    }
-}
-
-impl<'tcx> graph::WithSuccessors for Body<'tcx> {
-    #[inline]
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
-        self.basic_blocks[node].terminator().successors()
-    }
-}
-
-impl<'a, 'b> graph::GraphSuccessors<'b> for Body<'a> {
-    type Item = BasicBlock;
-    type Iter = Successors<'b>;
-}
-
-impl<'tcx, 'graph> graph::GraphPredecessors<'graph> for Body<'tcx> {
-    type Item = BasicBlock;
-    type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicBlock>>;
-}
-
-impl<'tcx> graph::WithPredecessors for Body<'tcx> {
-    #[inline]
-    fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
-        self.predecessors()[node].iter().copied()
-    }
-}
-
 /// `Location` represents the position of the start of the statement; or, if
 /// `statement_index` equals the number of statements, then the start of the
 /// terminator.
@@ -2938,7 +2826,7 @@ impl Location {
             return true;
         }
 
-        let predecessors = body.predecessors();
+        let predecessors = body.basic_blocks.predecessors();
 
         // If we're in another block, then we want to check that block is a predecessor of `other`.
         let mut queue: Vec<BasicBlock> = predecessors[other.block].to_vec();
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
index 620cf7e336b..5f1fadaf3bc 100644
--- a/compiler/rustc_middle/src/mir/predecessors.rs
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -73,6 +73,6 @@ impl<CTX> HashStable<CTX> for PredecessorCache {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     PredecessorCache,
 }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 462c0ada3cf..e2fa37ee7be 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -448,7 +448,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
                 self.push(&format!("+ user_ty: {:?}", user_ty));
             }
 
+            // FIXME: this is a poor version of `pretty_print_const_value`.
             let fmt_val = |val: &ConstValue<'tcx>| match val {
+                ConstValue::ZeroSized => format!("<ZST>"),
                 ConstValue::Scalar(s) => format!("Scalar({:?})", s),
                 ConstValue::Slice { .. } => format!("Slice(..)"),
                 ConstValue::ByRef { .. } => format!("ByRef(..)"),
@@ -679,6 +681,7 @@ pub fn write_allocations<'tcx>(
             ConstValue::Scalar(interpret::Scalar::Int { .. }) => {
                 Either::Left(Either::Right(std::iter::empty()))
             }
+            ConstValue::ZeroSized => Either::Left(Either::Right(std::iter::empty())),
             ConstValue::ByRef { alloc, .. } | ConstValue::Slice { data: alloc, .. } => {
                 Either::Right(alloc_ids_from_alloc(alloc))
             }
@@ -716,12 +719,12 @@ pub fn write_allocations<'tcx>(
                 }
                 write!(w, "{}", display_allocation(tcx, alloc.inner()))
             };
-        write!(w, "\n{}", id)?;
+        write!(w, "\n{id:?}")?;
         match tcx.get_global_alloc(id) {
             // This can't really happen unless there are bugs, but it doesn't cost us anything to
             // gracefully handle it and allow buggy rustc to be debugged via allocation printing.
             None => write!(w, " (deallocated)")?,
-            Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?,
+            Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?,
             Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => {
                 match tcx.eval_static_initializer(did) {
                     Ok(alloc) => {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index da4793fa039..620f0380d53 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -161,7 +161,7 @@ rustc_index::newtype_index! {
 }
 
 /// The layout of generator state.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct GeneratorLayout<'tcx> {
     /// The type of every local stored inside the generator.
     pub field_tys: IndexVec<GeneratorSavedLocal, Ty<'tcx>>,
diff --git a/compiler/rustc_middle/src/mir/switch_sources.rs b/compiler/rustc_middle/src/mir/switch_sources.rs
index 99d13fcfef4..d1f3e6b6fe6 100644
--- a/compiler/rustc_middle/src/mir/switch_sources.rs
+++ b/compiler/rustc_middle/src/mir/switch_sources.rs
@@ -73,6 +73,6 @@ impl<CTX> HashStable<CTX> for SwitchSourceCache {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     SwitchSourceCache,
 }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index f8ee59f306f..45fc5f24a60 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -179,7 +179,8 @@ pub enum BorrowKind {
 /// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
 /// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
 /// causing an ICE if they are violated.
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum StatementKind<'tcx> {
     /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
     /// without the possibility of dropping the previous value (that must be done separately, if at
@@ -236,19 +237,19 @@ pub enum StatementKind<'tcx> {
 
     /// `StorageLive` and `StorageDead` statements mark the live range of a local.
     ///
-    /// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These
-    /// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead`
-    /// statements for a particular local, the local is always considered live.
+    /// At any point during the execution of a function, each local is either allocated or
+    /// unallocated. Except as noted below, all locals except function parameters are initially
+    /// unallocated. `StorageLive` statements cause memory to be allocated for the local while
+    /// `StorageDead` statements cause the memory to be freed. Using a local in any way (not only
+    /// reading/writing from it) while it is unallocated is UB.
     ///
-    /// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to
-    /// check validity of each use of a local. I believe this is equivalent to requiring for every
-    /// use of a local, there exist at least one path from the root to that use that contains a
-    /// `StorageLive` more recently than a `StorageDead`.
+    /// Some locals have no `StorageLive` or `StorageDead` statements within the entire MIR body.
+    /// These locals are implicitly allocated for the full duration of the function. There is a
+    /// convenience method at `rustc_mir_dataflow::storage::always_storage_live_locals` for
+    /// computing these locals.
     ///
-    /// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening
-    /// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison,
-    /// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to
-    /// have a path in the CFG that might do this?
+    /// If the local is already allocated, calling `StorageLive` again is UB. However, for an
+    /// unallocated local an additional `StorageDead` all is simply a nop.
     StorageLive(Local),
 
     /// See `StorageLive` above.
@@ -311,6 +312,7 @@ pub enum StatementKind<'tcx> {
 
 /// Describes what kind of retag is to be performed.
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
+#[rustc_pass_by_value]
 pub enum RetagKind {
     /// The initial retag when entering a function.
     FnEntry,
@@ -375,13 +377,15 @@ pub enum FakeReadCause {
     ForIndex,
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct Coverage {
     pub kind: CoverageKind,
     pub code_region: Option<CodeRegion>,
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct CopyNonOverlapping<'tcx> {
     pub src: Operand<'tcx>,
     pub dst: Operand<'tcx>,
@@ -392,6 +396,8 @@ pub struct CopyNonOverlapping<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Terminators
 
+/// The various kinds of terminators, representing ways of exiting from a basic block.
+///
 /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
 /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
 /// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
@@ -671,7 +677,8 @@ pub enum AssertKind<O> {
     ResumedAfterPanic(GeneratorKind),
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -906,7 +913,7 @@ pub enum Operand<'tcx> {
 static_assert_size!(Operand<'_>, 24);
 
 ///////////////////////////////////////////////////////////////////////////
-/// Rvalues
+// Rvalues
 
 /// The various kinds of rvalues that can appear in MIR.
 ///
@@ -990,11 +997,20 @@ pub enum Rvalue<'tcx> {
     ///   matching types and return a value of that type.
     BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
-    /// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the
-    /// same computation as the matching `BinaryOp`, checks if the infinite precison result would be
-    /// unequal to the actual result and sets the `bool` if this is the case.
+    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
+    ///
+    /// When overflow checking is disabled and we are generating run-time code, the error condition
+    /// is false. Otherwise, and always during CTFE, the error condition is determined as described
+    /// below.
+    ///
+    /// For addition, subtraction, and multiplication on integers the error condition is set when
+    /// the infinite precision result would be unequal to the actual result.
+    ///
+    /// For shift operations on integers the error condition is set when the value of right-hand
+    /// side is greater than or equal to the number of bits in the type of the left-hand side, or
+    /// when the value of right-hand side is negative.
     ///
-    /// This only supports addition, subtraction, multiplication, and shift operations on integers.
+    /// Other combinations of types and operators are unsupported.
     CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
     /// Computes a value as described by the operation.
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index c93b7a95502..c99faf80187 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -9,7 +9,7 @@ use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_target::abi::VariantIdx;
 
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct PlaceTy<'tcx> {
     pub ty: Ty<'tcx>,
     /// Downcast to a particular variant of an enum or a generator, if included.
diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs
index 7228e3f33b1..627dc32f37e 100644
--- a/compiler/rustc_middle/src/mir/traversal.rs
+++ b/compiler/rustc_middle/src/mir/traversal.rs
@@ -104,22 +104,25 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
 ///
 /// A Postorder traversal of this graph is `D B C A` or `D C B A`
 pub struct Postorder<'a, 'tcx> {
-    body: &'a Body<'tcx>,
+    basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     visited: BitSet<BasicBlock>,
     visit_stack: Vec<(BasicBlock, Successors<'a>)>,
     root_is_start_block: bool,
 }
 
 impl<'a, 'tcx> Postorder<'a, 'tcx> {
-    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
+    pub fn new(
+        basic_blocks: &'a IndexVec<BasicBlock, BasicBlockData<'tcx>>,
+        root: BasicBlock,
+    ) -> Postorder<'a, 'tcx> {
         let mut po = Postorder {
-            body,
-            visited: BitSet::new_empty(body.basic_blocks().len()),
+            basic_blocks,
+            visited: BitSet::new_empty(basic_blocks.len()),
             visit_stack: Vec::new(),
             root_is_start_block: root == START_BLOCK,
         };
 
-        let data = &po.body[root];
+        let data = &po.basic_blocks[root];
 
         if let Some(ref term) = data.terminator {
             po.visited.insert(root);
@@ -190,7 +193,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
             };
 
             if self.visited.insert(bb) {
-                if let Some(term) = &self.body[bb].terminator {
+                if let Some(term) = &self.basic_blocks[bb].terminator {
                     self.visit_stack.push((bb, term.successors()));
                 }
             }
@@ -199,7 +202,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> {
 }
 
 pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
-    Postorder::new(body, START_BLOCK)
+    Postorder::new(&body.basic_blocks, START_BLOCK)
 }
 
 impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
@@ -211,12 +214,12 @@ impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
             self.traverse_successor();
         }
 
-        next.map(|(bb, _)| (bb, &self.body[bb]))
+        next.map(|(bb, _)| (bb, &self.basic_blocks[bb]))
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
         // All the blocks, minus the number of blocks we've visited.
-        let upper = self.body.basic_blocks().len() - self.visited.count();
+        let upper = self.basic_blocks.len() - self.visited.count();
 
         let lower = if self.root_is_start_block {
             // We will visit all remaining blocks exactly once.
@@ -263,10 +266,8 @@ pub struct ReversePostorder<'a, 'tcx> {
 
 impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
     pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
-        let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect();
-
+        let blocks: Vec<_> = Postorder::new(&body.basic_blocks, root).map(|(bb, _)| bb).collect();
         let len = blocks.len();
-
         ReversePostorder { body, blocks, idx: len }
     }
 }
@@ -334,10 +335,8 @@ impl<'a, 'tcx> Iterator for ReversePostorderIter<'a, 'tcx> {
 impl<'a, 'tcx> ExactSizeIterator for ReversePostorderIter<'a, 'tcx> {}
 
 pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorderIter<'a, 'tcx> {
-    let blocks = body.postorder_cache.compute(body);
-
+    let blocks = body.basic_blocks.postorder();
     let len = blocks.len();
-
     ReversePostorderIter { body, blocks, idx: len }
 }
 
@@ -360,7 +359,7 @@ impl PostorderCache {
 
     /// Returns the `&[BasicBlocks]` represents the postorder graph for this MIR.
     #[inline]
-    pub(super) fn compute(&self, body: &Body<'_>) -> &[BasicBlock] {
+    pub(super) fn compute(&self, body: &IndexVec<BasicBlock, BasicBlockData<'_>>) -> &[BasicBlock] {
         self.cache.get_or_init(|| Postorder::new(body, START_BLOCK).map(|(bb, _)| bb).collect())
     }
 }
@@ -384,6 +383,6 @@ impl<CTX> HashStable<CTX> for PostorderCache {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     PostorderCache,
 }
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 4201b2d11ce..3c9850a9eb3 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -4,7 +4,7 @@ use super::*;
 use crate::ty;
 use rustc_data_structures::functor::IdFunctor;
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     BlockTailInfo,
     MirPhase,
     SourceInfo,
@@ -89,65 +89,12 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
         };
         Ok(Terminator { source_info: self.source_info, kind })
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        use crate::mir::TerminatorKind::*;
-
-        match self.kind {
-            SwitchInt { ref discr, switch_ty, .. } => {
-                discr.visit_with(visitor)?;
-                switch_ty.visit_with(visitor)
-            }
-            Drop { ref place, .. } => place.visit_with(visitor),
-            DropAndReplace { ref place, ref value, .. } => {
-                place.visit_with(visitor)?;
-                value.visit_with(visitor)
-            }
-            Yield { ref value, .. } => value.visit_with(visitor),
-            Call { ref func, ref args, ref destination, .. } => {
-                destination.visit_with(visitor)?;
-                func.visit_with(visitor)?;
-                args.visit_with(visitor)
-            }
-            Assert { ref cond, ref msg, .. } => {
-                cond.visit_with(visitor)?;
-                use AssertKind::*;
-                match msg {
-                    BoundsCheck { ref len, ref index } => {
-                        len.visit_with(visitor)?;
-                        index.visit_with(visitor)
-                    }
-                    Overflow(_, l, r) => {
-                        l.visit_with(visitor)?;
-                        r.visit_with(visitor)
-                    }
-                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
-                        op.visit_with(visitor)
-                    }
-                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
-                }
-            }
-            InlineAsm { ref operands, .. } => operands.visit_with(visitor),
-            Goto { .. }
-            | Resume
-            | Abort
-            | Return
-            | GeneratorDrop
-            | Unreachable
-            | FalseEdge { .. }
-            | FalseUnwind { .. } => ControlFlow::CONTINUE,
-        }
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
@@ -157,21 +104,12 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
             projection: self.projection.try_fold_with(folder)?,
         })
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.local.visit_with(visitor)?;
-        self.projection.visit_with(visitor)
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_place_elems(v))
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.iter().try_for_each(|t| t.visit_with(visitor))
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
@@ -224,55 +162,6 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
             }
         })
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        use crate::mir::Rvalue::*;
-        match *self {
-            Use(ref op) => op.visit_with(visitor),
-            Repeat(ref op, _) => op.visit_with(visitor),
-            ThreadLocalRef(did) => did.visit_with(visitor),
-            Ref(region, _, ref place) => {
-                region.visit_with(visitor)?;
-                place.visit_with(visitor)
-            }
-            AddressOf(_, ref place) => place.visit_with(visitor),
-            Len(ref place) => place.visit_with(visitor),
-            Cast(_, ref op, ty) => {
-                op.visit_with(visitor)?;
-                ty.visit_with(visitor)
-            }
-            BinaryOp(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (ref rhs, ref lhs)) => {
-                rhs.visit_with(visitor)?;
-                lhs.visit_with(visitor)
-            }
-            UnaryOp(_, ref val) => val.visit_with(visitor),
-            Discriminant(ref place) => place.visit_with(visitor),
-            NullaryOp(_, ty) => ty.visit_with(visitor),
-            Aggregate(ref kind, ref fields) => {
-                match **kind {
-                    AggregateKind::Array(ty) => {
-                        ty.visit_with(visitor)?;
-                    }
-                    AggregateKind::Tuple => {}
-                    AggregateKind::Adt(_, _, substs, user_ty, _) => {
-                        substs.visit_with(visitor)?;
-                        user_ty.visit_with(visitor)?;
-                    }
-                    AggregateKind::Closure(_, substs) => {
-                        substs.visit_with(visitor)?;
-                    }
-                    AggregateKind::Generator(_, substs, _) => {
-                        substs.visit_with(visitor)?;
-                    }
-                }
-                fields.visit_with(visitor)
-            }
-            ShallowInitBox(ref op, ty) => {
-                op.visit_with(visitor)?;
-                ty.visit_with(visitor)
-            }
-        }
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
@@ -283,13 +172,6 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
             Operand::Constant(c) => Operand::Constant(c.try_fold_with(folder)?),
         })
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
-            Operand::Constant(ref c) => c.visit_with(visitor),
-        }
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
@@ -307,43 +189,24 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
             Subslice { from, to, from_end } => Subslice { from, to, from_end },
         })
     }
-
-    fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
-        use crate::mir::ProjectionElem::*;
-
-        match self {
-            Field(_, ty) => ty.visit_with(visitor),
-            Index(v) => v.visit_with(visitor),
-            _ => ControlFlow::CONTINUE,
-        }
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Field {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
 }
 
 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
@@ -354,10 +217,6 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
             literal: self.literal.try_fold_with(folder)?,
         })
     }
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.literal.visit_with(visitor)?;
-        self.user_ty.visit_with(visitor)
-    }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
@@ -365,10 +224,6 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_mir_const(self)
     }
-
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_mir_const(*self)
-    }
 }
 
 impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
@@ -381,11 +236,4 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ConstantKind<'tcx> {
             ConstantKind::Val(v, t) => Ok(ConstantKind::Val(v, t.try_fold_with(folder)?)),
         }
     }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        match *self {
-            ConstantKind::Ty(c) => c.visit_with(visitor),
-            ConstantKind::Val(_, t) => t.visit_with(visitor),
-        }
-    }
 }
diff --git a/compiler/rustc_middle/src/mir/type_visitable.rs b/compiler/rustc_middle/src/mir/type_visitable.rs
new file mode 100644
index 00000000000..d52ae5fac67
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/type_visitable.rs
@@ -0,0 +1,186 @@
+//! `TypeVisitable` implementations for MIR types
+
+use super::*;
+use crate::ty;
+
+impl<'tcx> TypeVisitable<'tcx> for Terminator<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        use crate::mir::TerminatorKind::*;
+
+        match self.kind {
+            SwitchInt { ref discr, switch_ty, .. } => {
+                discr.visit_with(visitor)?;
+                switch_ty.visit_with(visitor)
+            }
+            Drop { ref place, .. } => place.visit_with(visitor),
+            DropAndReplace { ref place, ref value, .. } => {
+                place.visit_with(visitor)?;
+                value.visit_with(visitor)
+            }
+            Yield { ref value, .. } => value.visit_with(visitor),
+            Call { ref func, ref args, ref destination, .. } => {
+                destination.visit_with(visitor)?;
+                func.visit_with(visitor)?;
+                args.visit_with(visitor)
+            }
+            Assert { ref cond, ref msg, .. } => {
+                cond.visit_with(visitor)?;
+                use AssertKind::*;
+                match msg {
+                    BoundsCheck { ref len, ref index } => {
+                        len.visit_with(visitor)?;
+                        index.visit_with(visitor)
+                    }
+                    Overflow(_, l, r) => {
+                        l.visit_with(visitor)?;
+                        r.visit_with(visitor)
+                    }
+                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+                        op.visit_with(visitor)
+                    }
+                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
+                }
+            }
+            InlineAsm { ref operands, .. } => operands.visit_with(visitor),
+            Goto { .. }
+            | Resume
+            | Abort
+            | Return
+            | GeneratorDrop
+            | Unreachable
+            | FalseEdge { .. }
+            | FalseUnwind { .. } => ControlFlow::CONTINUE,
+        }
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for GeneratorKind {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Place<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.local.visit_with(visitor)?;
+        self.projection.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.iter().try_for_each(|t| t.visit_with(visitor))
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Rvalue<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        use crate::mir::Rvalue::*;
+        match *self {
+            Use(ref op) => op.visit_with(visitor),
+            Repeat(ref op, _) => op.visit_with(visitor),
+            ThreadLocalRef(did) => did.visit_with(visitor),
+            Ref(region, _, ref place) => {
+                region.visit_with(visitor)?;
+                place.visit_with(visitor)
+            }
+            AddressOf(_, ref place) => place.visit_with(visitor),
+            Len(ref place) => place.visit_with(visitor),
+            Cast(_, ref op, ty) => {
+                op.visit_with(visitor)?;
+                ty.visit_with(visitor)
+            }
+            BinaryOp(_, box (ref rhs, ref lhs)) | CheckedBinaryOp(_, box (ref rhs, ref lhs)) => {
+                rhs.visit_with(visitor)?;
+                lhs.visit_with(visitor)
+            }
+            UnaryOp(_, ref val) => val.visit_with(visitor),
+            Discriminant(ref place) => place.visit_with(visitor),
+            NullaryOp(_, ty) => ty.visit_with(visitor),
+            Aggregate(ref kind, ref fields) => {
+                match **kind {
+                    AggregateKind::Array(ty) => {
+                        ty.visit_with(visitor)?;
+                    }
+                    AggregateKind::Tuple => {}
+                    AggregateKind::Adt(_, _, substs, user_ty, _) => {
+                        substs.visit_with(visitor)?;
+                        user_ty.visit_with(visitor)?;
+                    }
+                    AggregateKind::Closure(_, substs) => {
+                        substs.visit_with(visitor)?;
+                    }
+                    AggregateKind::Generator(_, substs, _) => {
+                        substs.visit_with(visitor)?;
+                    }
+                }
+                fields.visit_with(visitor)
+            }
+            ShallowInitBox(ref op, ty) => {
+                op.visit_with(visitor)?;
+                ty.visit_with(visitor)
+            }
+        }
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Operand<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match *self {
+            Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
+            Operand::Constant(ref c) => c.visit_with(visitor),
+        }
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for PlaceElem<'tcx> {
+    fn visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<Vs::BreakTy> {
+        use crate::mir::ProjectionElem::*;
+
+        match self {
+            Field(_, ty) => ty.visit_with(visitor),
+            Index(v) => v.visit_with(visitor),
+            _ => ControlFlow::CONTINUE,
+        }
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Field {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for GeneratorSavedLocal {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
+
+impl<'tcx, R: Idx, C: Idx> TypeVisitable<'tcx> for BitMatrix<R, C> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for Constant<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        self.literal.visit_with(visitor)?;
+        self.user_ty.visit_with(visitor)
+    }
+}
+
+impl<'tcx> TypeVisitable<'tcx> for ConstantKind<'tcx> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_mir_const(*self)
+    }
+}
+
+impl<'tcx> TypeSuperVisitable<'tcx> for ConstantKind<'tcx> {
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        match *self {
+            ConstantKind::Ty(c) => c.visit_with(visitor),
+            ConstantKind::Val(_, t) => t.visit_with(visitor),
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 5ce92d127f3..d1477f9e2ae 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -30,9 +30,11 @@
 //! For example, the `super_basic_block_data` method begins like this:
 //!
 //! ```ignore (pseudo-rust)
-//! fn super_basic_block_data(&mut self,
-//!                           block: BasicBlock,
-//!                           data: & $($mutability)? BasicBlockData<'tcx>) {
+//! fn super_basic_block_data(
+//!     &mut self,
+//!     block: BasicBlock,
+//!     data: & $($mutability)? BasicBlockData<'tcx>
+//! ) {
 //!     let BasicBlockData {
 //!         statements,
 //!         terminator,
@@ -78,106 +80,135 @@ macro_rules! make_mir_visitor {
                 self.super_body(body);
             }
 
-            fn visit_basic_block_data(&mut self,
-                                      block: BasicBlock,
-                                      data: & $($mutability)? BasicBlockData<'tcx>) {
+            fn visit_basic_block_data(
+                &mut self,
+                block: BasicBlock,
+                data: & $($mutability)? BasicBlockData<'tcx>,
+            ) {
                 self.super_basic_block_data(block, data);
             }
 
-            fn visit_source_scope_data(&mut self,
-                                           scope_data: & $($mutability)? SourceScopeData<'tcx>) {
+            fn visit_source_scope_data(
+                &mut self,
+                scope_data: & $($mutability)? SourceScopeData<'tcx>,
+            ) {
                 self.super_source_scope_data(scope_data);
             }
 
-            fn visit_statement(&mut self,
-                               statement: & $($mutability)? Statement<'tcx>,
-                               location: Location) {
+            fn visit_statement(
+                &mut self,
+                statement: & $($mutability)? Statement<'tcx>,
+                location: Location,
+            ) {
                 self.super_statement(statement, location);
             }
 
-            fn visit_assign(&mut self,
-                            place: & $($mutability)? Place<'tcx>,
-                            rvalue: & $($mutability)? Rvalue<'tcx>,
-                            location: Location) {
+            fn visit_assign(
+                &mut self,
+                place: & $($mutability)? Place<'tcx>,
+                rvalue: & $($mutability)? Rvalue<'tcx>,
+                location: Location,
+            ) {
                 self.super_assign(place, rvalue, location);
             }
 
-            fn visit_terminator(&mut self,
-                                terminator: & $($mutability)? Terminator<'tcx>,
-                                location: Location) {
+            fn visit_terminator(
+                &mut self,
+                terminator: & $($mutability)? Terminator<'tcx>,
+                location: Location,
+            ) {
                 self.super_terminator(terminator, location);
             }
 
-            fn visit_assert_message(&mut self,
-                                    msg: & $($mutability)? AssertMessage<'tcx>,
-                                    location: Location) {
+            fn visit_assert_message(
+                &mut self,
+                msg: & $($mutability)? AssertMessage<'tcx>,
+                location: Location,
+            ) {
                 self.super_assert_message(msg, location);
             }
 
-            fn visit_rvalue(&mut self,
-                            rvalue: & $($mutability)? Rvalue<'tcx>,
-                            location: Location) {
+            fn visit_rvalue(
+                &mut self,
+                rvalue: & $($mutability)? Rvalue<'tcx>,
+                location: Location,
+            ) {
                 self.super_rvalue(rvalue, location);
             }
 
-            fn visit_operand(&mut self,
-                             operand: & $($mutability)? Operand<'tcx>,
-                             location: Location) {
+            fn visit_operand(
+                &mut self,
+                operand: & $($mutability)? Operand<'tcx>,
+                location: Location,
+            ) {
                 self.super_operand(operand, location);
             }
 
-            fn visit_ascribe_user_ty(&mut self,
-                                     place: & $($mutability)? Place<'tcx>,
-                                     variance: & $($mutability)? ty::Variance,
-                                     user_ty: & $($mutability)? UserTypeProjection,
-                                     location: Location) {
+            fn visit_ascribe_user_ty(
+                &mut self,
+                place: & $($mutability)? Place<'tcx>,
+                variance: $(& $mutability)? ty::Variance,
+                user_ty: & $($mutability)? UserTypeProjection,
+                location: Location,
+            ) {
                 self.super_ascribe_user_ty(place, variance, user_ty, location);
             }
 
-            fn visit_coverage(&mut self,
-                              coverage: & $($mutability)? Coverage,
-                              location: Location) {
+            fn visit_coverage(
+                &mut self,
+                coverage: & $($mutability)? Coverage,
+                location: Location,
+            ) {
                 self.super_coverage(coverage, location);
             }
 
-            fn visit_retag(&mut self,
-                           kind: & $($mutability)? RetagKind,
-                           place: & $($mutability)? Place<'tcx>,
-                           location: Location) {
+            fn visit_retag(
+                &mut self,
+                kind: $(& $mutability)? RetagKind,
+                place: & $($mutability)? Place<'tcx>,
+                location: Location,
+            ) {
                 self.super_retag(kind, place, location);
             }
 
-            fn visit_place(&mut self,
-                            place: & $($mutability)? Place<'tcx>,
-                            context: PlaceContext,
-                            location: Location) {
+            fn visit_place(
+                &mut self,
+                place: & $($mutability)? Place<'tcx>,
+                context: PlaceContext,
+                location: Location,
+            ) {
                 self.super_place(place, context, location);
             }
 
             visit_place_fns!($($mutability)?);
 
-            fn visit_constant(&mut self,
-                              constant: & $($mutability)? Constant<'tcx>,
-                              location: Location) {
+            fn visit_constant(
+                &mut self,
+                constant: & $($mutability)? Constant<'tcx>,
+                location: Location,
+            ) {
                 self.super_constant(constant, location);
             }
 
-            // The macro results in a false positive of sorts, where &mut Span
-            // is fine, but &Span is not; just allow the lint.
-            #[allow(rustc::pass_by_value)]
-            fn visit_span(&mut self,
-                          span: & $($mutability)? Span) {
+            fn visit_span(
+                &mut self,
+                span: $(& $mutability)? Span,
+            ) {
                 self.super_span(span);
             }
 
-            fn visit_source_info(&mut self,
-                                 source_info: & $($mutability)? SourceInfo) {
+            fn visit_source_info(
+                &mut self,
+                source_info: & $($mutability)? SourceInfo,
+            ) {
                 self.super_source_info(source_info);
             }
 
-            fn visit_ty(&mut self,
-                        ty: $(& $mutability)? Ty<'tcx>,
-                        _: TyContext) {
+            fn visit_ty(
+                &mut self,
+                ty: $(& $mutability)? Ty<'tcx>,
+                _: TyContext,
+            ) {
                 self.super_ty(ty);
             }
 
@@ -196,45 +227,56 @@ macro_rules! make_mir_visitor {
                 self.super_user_type_annotation(index, ty);
             }
 
-            fn visit_region(&mut self,
-                            region: $(& $mutability)? ty::Region<'tcx>,
-                            _: Location) {
+            fn visit_region(
+                &mut self,
+                region: $(& $mutability)? ty::Region<'tcx>,
+                _: Location,
+            ) {
                 self.super_region(region);
             }
 
-            fn visit_const(&mut self,
-                           constant: $(& $mutability)? ty::Const<'tcx>,
-                           _: Location) {
+            fn visit_const(
+                &mut self,
+                constant: $(& $mutability)? ty::Const<'tcx>,
+                _: Location,
+            ) {
                 self.super_const(constant);
             }
 
-            fn visit_substs(&mut self,
-                            substs: & $($mutability)? SubstsRef<'tcx>,
-                            _: Location) {
+            fn visit_substs(
+                &mut self,
+                substs: & $($mutability)? SubstsRef<'tcx>,
+                _: Location,
+            ) {
                 self.super_substs(substs);
             }
 
-            fn visit_local_decl(&mut self,
-                                local: Local,
-                                local_decl: & $($mutability)? LocalDecl<'tcx>) {
+            fn visit_local_decl(
+                &mut self,
+                local: Local,
+                local_decl: & $($mutability)? LocalDecl<'tcx>,
+            ) {
                 self.super_local_decl(local, local_decl);
             }
 
-            fn visit_var_debug_info(&mut self,
-                                    var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) {
+            fn visit_var_debug_info(
+                &mut self,
+                var_debug_info: & $($mutability)* VarDebugInfo<'tcx>,
+            ) {
                 self.super_var_debug_info(var_debug_info);
             }
 
-            #[allow(rustc::pass_by_value)]
-            fn visit_local(&mut self,
-                            _local: & $($mutability)? Local,
-                            _context: PlaceContext,
-                            _location: Location) {
-            }
+            fn visit_local(
+                &mut self,
+                _local: $(& $mutability)? Local,
+                _context: PlaceContext,
+                _location: Location,
+            ) {}
 
-            #[allow(rustc::pass_by_value)]
-            fn visit_source_scope(&mut self,
-                                      scope: & $($mutability)? SourceScope) {
+            fn visit_source_scope(
+                &mut self,
+                scope: $(& $mutability)? SourceScope,
+            ) {
                 self.super_source_scope(scope);
             }
 
@@ -296,7 +338,7 @@ macro_rules! make_mir_visitor {
                     self.visit_var_debug_info(var_debug_info);
                 }
 
-                self.visit_span(&$($mutability)? body.span);
+                self.visit_span($(& $mutability)? body.span);
 
                 for const_ in &$($mutability)? body.required_consts {
                     let location = START_BLOCK.start_location();
@@ -338,14 +380,14 @@ macro_rules! make_mir_visitor {
                     local_data: _,
                 } = scope_data;
 
-                self.visit_span(span);
+                self.visit_span($(& $mutability)? *span);
                 if let Some(parent_scope) = parent_scope {
-                    self.visit_source_scope(parent_scope);
+                    self.visit_source_scope($(& $mutability)? *parent_scope);
                 }
                 if let Some((callee, callsite_span)) = inlined {
                     let location = START_BLOCK.start_location();
 
-                    self.visit_span(callsite_span);
+                    self.visit_span($(& $mutability)? *callsite_span);
 
                     let ty::Instance { def: callee_def, substs: callee_substs } = callee;
                     match callee_def {
@@ -368,7 +410,7 @@ macro_rules! make_mir_visitor {
                     self.visit_substs(callee_substs, location);
                 }
                 if let Some(inlined_parent_scope) = inlined_parent_scope {
-                    self.visit_source_scope(inlined_parent_scope);
+                    self.visit_source_scope($(& $mutability)? *inlined_parent_scope);
                 }
             }
 
@@ -383,7 +425,7 @@ macro_rules! make_mir_visitor {
                 self.visit_source_info(source_info);
                 match kind {
                     StatementKind::Assign(
-                        box(ref $($mutability)? place, ref $($mutability)? rvalue)
+                        box (place, rvalue)
                     ) => {
                         self.visit_assign(place, rvalue, location);
                     }
@@ -410,26 +452,26 @@ macro_rules! make_mir_visitor {
                     }
                     StatementKind::StorageLive(local) => {
                         self.visit_local(
-                            local,
+                            $(& $mutability)? *local,
                             PlaceContext::NonUse(NonUseContext::StorageLive),
                             location
                         );
                     }
                     StatementKind::StorageDead(local) => {
                         self.visit_local(
-                            local,
+                            $(& $mutability)? *local,
                             PlaceContext::NonUse(NonUseContext::StorageDead),
                             location
                         );
                     }
                     StatementKind::Retag(kind, place) => {
-                        self.visit_retag(kind, place, location);
+                        self.visit_retag($(& $mutability)? *kind, place, location);
                     }
                     StatementKind::AscribeUserType(
-                        box(ref $($mutability)? place, ref $($mutability)? user_ty),
+                        box (place, user_ty),
                         variance
                     ) => {
-                        self.visit_ascribe_user_ty(place, variance, user_ty, location);
+                        self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location);
                     }
                     StatementKind::Coverage(coverage) => {
                         self.visit_coverage(
@@ -438,9 +480,9 @@ macro_rules! make_mir_visitor {
                         )
                     }
                     StatementKind::CopyNonOverlapping(box crate::mir::CopyNonOverlapping{
-                      ref $($mutability)? src,
-                      ref $($mutability)? dst,
-                      ref $($mutability)? count,
+                        src,
+                        dst,
+                        count,
                     }) => {
                       self.visit_operand(src, location);
                       self.visit_operand(dst, location);
@@ -475,15 +517,14 @@ macro_rules! make_mir_visitor {
                     TerminatorKind::GeneratorDrop |
                     TerminatorKind::Unreachable |
                     TerminatorKind::FalseEdge { .. } |
-                    TerminatorKind::FalseUnwind { .. } => {
-                    }
+                    TerminatorKind::FalseUnwind { .. } => {}
 
                     TerminatorKind::Return => {
                         // `return` logically moves from the return place `_0`. Note that the place
                         // cannot be changed by any visitor, though.
                         let $($mutability)? local = RETURN_PLACE;
                         self.visit_local(
-                            & $($mutability)? local,
+                            $(& $mutability)? local,
                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
                             location,
                         );
@@ -788,7 +829,7 @@ macro_rules! make_mir_visitor {
 
             fn super_ascribe_user_ty(&mut self,
                                      place: & $($mutability)? Place<'tcx>,
-                                     _variance: & $($mutability)? ty::Variance,
+                                     _variance: $(& $mutability)? ty::Variance,
                                      user_ty: & $($mutability)? UserTypeProjection,
                                      location: Location) {
                 self.visit_place(
@@ -805,7 +846,7 @@ macro_rules! make_mir_visitor {
             }
 
             fn super_retag(&mut self,
-                           _kind: & $($mutability)? RetagKind,
+                           _kind: $(& $mutability)? RetagKind,
                            place: & $($mutability)? Place<'tcx>,
                            location: Location) {
                 self.visit_place(
@@ -840,8 +881,10 @@ macro_rules! make_mir_visitor {
                 self.visit_source_info(source_info);
             }
 
-            fn super_var_debug_info(&mut self,
-                                    var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) {
+            fn super_var_debug_info(
+                &mut self,
+                var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
+            ) {
                 let VarDebugInfo {
                     name: _,
                     source_info,
@@ -861,21 +904,23 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            #[allow(rustc::pass_by_value)]
-            fn super_source_scope(&mut self,
-                                      _scope: & $($mutability)? SourceScope) {
-            }
+            fn super_source_scope(
+                &mut self,
+                _scope: $(& $mutability)? SourceScope
+            ) {}
 
-            fn super_constant(&mut self,
-                              constant: & $($mutability)? Constant<'tcx>,
-                              location: Location) {
+            fn super_constant(
+                &mut self,
+                constant: & $($mutability)? Constant<'tcx>,
+                location: Location
+            ) {
                 let Constant {
                     span,
                     user_ty,
                     literal,
                 } = constant;
 
-                self.visit_span(span);
+                self.visit_span($(& $mutability)? *span);
                 drop(user_ty); // no visit method for this
                 match literal {
                     ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location),
@@ -883,10 +928,7 @@ macro_rules! make_mir_visitor {
                 }
             }
 
-            // The macro results in a false positive of sorts, where &mut Span
-            // is fine, but &Span is not; just allow the lint.
-            #[allow(rustc::pass_by_value)]
-            fn super_span(&mut self, _span: & $($mutability)? Span) {
+            fn super_span(&mut self, _span: $(& $mutability)? Span) {
             }
 
             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
@@ -895,8 +937,8 @@ macro_rules! make_mir_visitor {
                     scope,
                 } = source_info;
 
-                self.visit_span(span);
-                self.visit_source_scope(scope);
+                self.visit_span($(& $mutability)? *span);
+                self.visit_source_scope($(& $mutability)? *scope);
             }
 
             fn super_user_type_projection(
@@ -910,7 +952,7 @@ macro_rules! make_mir_visitor {
                 _index: UserTypeAnnotationIndex,
                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
             ) {
-                self.visit_span(& $($mutability)? ty.span);
+                self.visit_span($(& $mutability)? ty.span);
                 self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
             }
 
@@ -1058,7 +1100,7 @@ macro_rules! visit_place_fns {
                 }
             }
 
-            self.visit_local(&place.local, context, location);
+            self.visit_local(place.local, context, location);
 
             self.visit_projection(place.as_ref(), context, location);
         }
@@ -1091,7 +1133,7 @@ macro_rules! visit_place_fns {
                 }
                 ProjectionElem::Index(local) => {
                     self.visit_local(
-                        &local,
+                        local,
                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
                         location,
                     );
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index a1065eef850..cbc45526e89 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -26,6 +26,12 @@ rustc_queries! {
         desc { "get the resolver outputs" }
     }
 
+    query resolver_for_lowering(_: ()) -> &'tcx Steal<ty::ResolverAstLowering> {
+        eval_always
+        no_hash
+        desc { "get the resolver for lowering" }
+    }
+
     /// Return the span for a definition.
     /// Contrary to `def_span` below, this query returns the full absolute span of the definition.
     /// This span is meant for dep-tracking rather than diagnostics. It should not be used outside
@@ -40,7 +46,8 @@ rustc_queries! {
     /// This is because the `hir_crate` query gives you access to all other items.
     /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
     /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
-    query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
+    query hir_crate(key: ()) -> Crate<'tcx> {
+        storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "get the crate HIR" }
     }
@@ -1356,9 +1363,13 @@ rustc_queries! {
         desc { "query a crate is `#![profiler_runtime]`" }
         separate_provide_extern
     }
-    query panic_strategy(_: CrateNum) -> PanicStrategy {
+    query has_ffi_unwind_calls(key: LocalDefId) -> bool {
+        desc { |tcx| "check if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+        cache_on_disk_if { true }
+    }
+    query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
         fatal_cycle
-        desc { "query a crate's configured panic strategy" }
+        desc { "query a crate's required panic strategy" }
         separate_provide_extern
     }
     query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
@@ -1569,7 +1580,7 @@ rustc_queries! {
         Option<&'tcx FxHashMap<ItemLocalId, Region>> {
         desc { "looking up a named region" }
     }
-    query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxHashSet<LocalDefId>> {
+    query is_late_bound_map(_: LocalDefId) -> Option<&'tcx FxIndexSet<LocalDefId>> {
         desc { "testing if a region is late bound" }
     }
     /// For a given item (like a struct), gets the default lifetimes to be used
@@ -1821,7 +1832,8 @@ rustc_queries! {
         remap_env_constness
     }
 
-    /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
+    /// Do not call this query directly:
+    /// invoke `DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx)` instead.
     query dropck_outlives(
         goal: CanonicalTyGoal<'tcx>
     ) -> Result<
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 120d09ee353..3fe6394ad7e 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -191,18 +191,8 @@ pub enum StmtKind<'tcx> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Expr<'_>, 104);
 
-#[derive(
-    Clone,
-    Debug,
-    Copy,
-    PartialEq,
-    Eq,
-    Hash,
-    HashStable,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable
-)]
+#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct LocalVarId(pub hir::HirId);
 
 /// A THIR expression.
@@ -429,6 +419,10 @@ pub enum ExprKind<'tcx> {
         lit: ty::ScalarInt,
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
     },
+    /// A literal of a ZST type.
+    ZstLiteral {
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
     /// Associated constants and named constants
     NamedConst {
         def_id: DefId,
@@ -464,12 +458,6 @@ pub enum ExprKind<'tcx> {
     },
 }
 
-impl<'tcx> ExprKind<'tcx> {
-    pub fn zero_sized_literal(user_ty: Option<Canonical<'tcx, UserType<'tcx>>>) -> Self {
-        ExprKind::NonHirLiteral { lit: ty::ScalarInt::ZST, user_ty }
-    }
-}
-
 /// Represents the association of a field identifier and an expression.
 ///
 /// This is used in struct constructors.
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
index e02ed414574..527dbd1cd09 100644
--- a/compiler/rustc_middle/src/thir/abstract_const.rs
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -42,7 +42,7 @@ impl From<ErrorGuaranteed> for NotConstEvaluatable {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     NotConstEvaluatable,
 }
 
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 8c8ebb0a6b8..c8d09875c28 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -129,6 +129,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
         Literal { lit: _, neg: _ } => {}
         NonHirLiteral { lit: _, user_ty: _ } => {}
+        ZstLiteral { user_ty: _ } => {}
         NamedConst { def_id: _, substs: _, user_ty: _ } => {}
         ConstParam { param: _, def_id: _ } => {}
         StaticRef { alloc_id: _, ty: _, def_id: _ } => {}
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index 70abdb9ab4c..6d4af8bea62 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -390,7 +390,7 @@ impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
 }
 
 /// A chalk environment and goal.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, TypeVisitable)]
 pub struct ChalkEnvironmentAndGoal<'tcx> {
     pub environment: &'tcx ty::List<ty::Predicate<'tcx>>,
     pub goal: ty::Predicate<'tcx>,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 7f913faf860..fe7f72024d3 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -523,7 +523,7 @@ pub struct DerivedObligationCause<'tcx> {
     pub parent_code: InternedObligationCauseCode<'tcx>,
 }
 
-#[derive(Clone, Debug, TypeFoldable, Lift)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 pub enum SelectionError<'tcx> {
     /// The trait is not implemented.
     Unimplemented,
@@ -546,9 +546,17 @@ pub enum SelectionError<'tcx> {
     ErrorReporting,
     /// Multiple applicable `impl`s where found. The `DefId`s correspond to
     /// all the `impl`s' Items.
-    Ambiguous(Vec<DefId>),
+    Ambiguous(Vec<AmbiguousSelection>),
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum AmbiguousSelection {
+    Impl(DefId),
+    ParamEnv(Span),
+}
+
+TrivialTypeTraversalAndLiftImpls! { AmbiguousSelection, }
+
 /// When performing resolution, it is typically the case that there
 /// can be one of three outcomes:
 ///
@@ -592,7 +600,8 @@ pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
 /// ### The type parameter `N`
 ///
 /// See explanation on `ImplSourceUserDefinedData`.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum ImplSource<'tcx, N> {
     /// ImplSource identifying a particular impl.
     UserDefined(ImplSourceUserDefinedData<'tcx, N>),
@@ -753,14 +762,16 @@ impl<'tcx, N> ImplSource<'tcx, N> {
 /// is `Obligation`, as one might expect. During codegen, however, this
 /// is `()`, because codegen only requires a shallow resolution of an
 /// impl, and nested obligations are satisfied later.
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceUserDefinedData<'tcx, N> {
     pub impl_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceGeneratorData<'tcx, N> {
     pub generator_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -769,7 +780,8 @@ pub struct ImplSourceGeneratorData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceClosureData<'tcx, N> {
     pub closure_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -778,13 +790,15 @@ pub struct ImplSourceClosureData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceAutoImplData<N> {
     pub trait_def_id: DefId,
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceTraitUpcastingData<'tcx, N> {
     /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -798,12 +812,14 @@ pub struct ImplSourceTraitUpcastingData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceBuiltinData<N> {
     pub nested: Vec<N>,
 }
 
-#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(PartialEq, Eq, Clone, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceObjectData<'tcx, N> {
     /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
     pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -817,7 +833,8 @@ pub struct ImplSourceObjectData<'tcx, N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceFnPointerData<'tcx, N> {
     pub fn_ty: Ty<'tcx>,
     pub nested: Vec<N>,
@@ -830,12 +847,14 @@ pub struct ImplSourceDiscriminantKindData;
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourcePointeeData;
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceConstDestructData<N> {
     pub nested: Vec<N>,
 }
 
-#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index d43492c903c..937b166d484 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -24,7 +24,8 @@ pub mod type_op {
     use rustc_hir::def_id::DefId;
     use std::fmt;
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+    #[derive(TypeFoldable, TypeVisitable)]
     pub struct AscribeUserType<'tcx> {
         pub mir_ty: Ty<'tcx>,
         pub def_id: DefId,
@@ -37,19 +38,22 @@ pub mod type_op {
         }
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+    #[derive(TypeFoldable, TypeVisitable)]
     pub struct Eq<'tcx> {
         pub a: Ty<'tcx>,
         pub b: Ty<'tcx>,
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+    #[derive(TypeFoldable, TypeVisitable)]
     pub struct Subtype<'tcx> {
         pub sub: Ty<'tcx>,
         pub sup: Ty<'tcx>,
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+    #[derive(TypeFoldable, TypeVisitable)]
     pub struct ProvePredicate<'tcx> {
         pub predicate: Predicate<'tcx>,
     }
@@ -60,7 +64,8 @@ pub mod type_op {
         }
     }
 
-    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
+    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, Lift)]
+    #[derive(TypeFoldable, TypeVisitable)]
     pub struct Normalize<T> {
         pub value: T,
     }
@@ -107,7 +112,7 @@ impl<'tcx> From<TypeError<'tcx>> for NoSolution {
     }
 }
 
-#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct DropckOutlivesResult<'tcx> {
     pub kinds: Vec<GenericArg<'tcx>>,
     pub overflows: Vec<Ty<'tcx>>,
@@ -208,7 +213,7 @@ pub struct MethodAutoderefBadTy<'tcx> {
 }
 
 /// Result from the `normalize_projection_ty` query.
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct NormalizationResult<'tcx> {
     /// Result of normalization.
     pub normalized_ty: Ty<'tcx>,
@@ -221,7 +226,7 @@ pub struct NormalizationResult<'tcx> {
 /// case they are called implied bounds). They are fed to the
 /// `OutlivesEnv` which in turn is supplied to the region checker and
 /// other parts of the inference system.
-#[derive(Clone, Debug, TypeFoldable, Lift)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
 pub enum OutlivesBound<'tcx> {
     RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
     RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ffa70cddbd5..0ca5a532b75 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -103,7 +103,7 @@ pub type EvaluationCache<'tcx> = Cache<
 /// required for associated types to work in default impls, as the bounds
 /// are visible both as projection bounds and as where-clauses from the
 /// parameter environment.
-#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
+#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)]
 pub enum SelectionCandidate<'tcx> {
     BuiltinCandidate {
         /// `false` if there are no *further* obligations.
@@ -176,6 +176,10 @@ pub enum EvaluationResult {
     EvaluatedToOk,
     /// Evaluation successful, but there were unevaluated region obligations.
     EvaluatedToOkModuloRegions,
+    /// Evaluation successful, but need to rerun because opaque types got
+    /// hidden types assigned without it being known whether the opaque types
+    /// are within their defining scope
+    EvaluatedToOkModuloOpaqueTypes,
     /// Evaluation is known to be ambiguous -- it *might* hold for some
     /// assignment of inference variables, but it might not.
     ///
@@ -252,9 +256,11 @@ impl EvaluationResult {
 
     pub fn may_apply(self) -> bool {
         match self {
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
-                true
-            }
+            EvaluatedToOkModuloOpaqueTypes
+            | EvaluatedToOk
+            | EvaluatedToOkModuloRegions
+            | EvaluatedToAmbig
+            | EvaluatedToUnknown => true,
 
             EvaluatedToErr | EvaluatedToRecur => false,
         }
@@ -264,7 +270,11 @@ impl EvaluationResult {
         match self {
             EvaluatedToUnknown | EvaluatedToRecur => true,
 
-            EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
+            EvaluatedToOkModuloOpaqueTypes
+            | EvaluatedToOk
+            | EvaluatedToOkModuloRegions
+            | EvaluatedToAmbig
+            | EvaluatedToErr => false,
         }
     }
 }
@@ -283,7 +293,7 @@ impl From<ErrorGuaranteed> for OverflowError {
     }
 }
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     OverflowError,
 }
 
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index ce13825b016..3c1d0061ae1 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -1,5 +1,5 @@
 use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::fold::TypeFoldable;
+use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, TyCtxt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorGuaranteed;
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index ea706053231..8f1a1564fc8 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -129,7 +129,7 @@ impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDestructData<N> {
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
     super::ImplSourcePointeeData,
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index d9332f6896a..d36cf2fe3f8 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -77,7 +77,7 @@ pub enum PointerCast {
 ///    At some point, of course, `Box` should move out of the compiler, in which
 ///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
 ///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
-#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
     pub target: Ty<'tcx>,
@@ -89,7 +89,7 @@ impl<'tcx> Adjustment<'tcx> {
     }
 }
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum Adjust<'tcx> {
     /// Go from ! to any type.
     NeverToAny,
@@ -107,7 +107,8 @@ pub enum Adjust<'tcx> {
 /// call, with the signature `&'a T -> &'a U` or `&'a mut T -> &'a mut U`.
 /// The target type is `U` in both cases, with the region and mutability
 /// being those shared by both the receiver and the returned reference.
-#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct OverloadedDeref<'tcx> {
     pub region: ty::Region<'tcx>,
     pub mutbl: hir::Mutability,
@@ -165,7 +166,8 @@ impl From<AutoBorrowMutability> for hir::Mutability {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum AutoBorrow<'tcx> {
     /// Converts from T to &T.
     Ref(ty::Region<'tcx>, AutoBorrowMutability),
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index bf7cb610a90..4cac7670735 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -165,22 +165,27 @@ impl<'a> HashStable<StableHashingContext<'a>> for AdtDefData {
 pub struct AdtDef<'tcx>(pub Interned<'tcx, AdtDefData>);
 
 impl<'tcx> AdtDef<'tcx> {
+    #[inline]
     pub fn did(self) -> DefId {
         self.0.0.did
     }
 
+    #[inline]
     pub fn variants(self) -> &'tcx IndexVec<VariantIdx, VariantDef> {
         &self.0.0.variants
     }
 
+    #[inline]
     pub fn variant(self, idx: VariantIdx) -> &'tcx VariantDef {
         &self.0.0.variants[idx]
     }
 
+    #[inline]
     pub fn flags(self) -> AdtFlags {
         self.0.0.flags
     }
 
+    #[inline]
     pub fn repr(self) -> ReprOptions {
         self.0.0.repr
     }
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
index 7ab192daf4b..3d65429f2e5 100644
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ b/compiler/rustc_middle/src/ty/binding.rs
@@ -8,7 +8,7 @@ pub enum BindingMode {
     BindByValue(Mutability),
 }
 
-TrivialTypeFoldableAndLiftImpls! { BindingMode, }
+TrivialTypeTraversalAndLiftImpls! { BindingMode, }
 
 impl BindingMode {
     pub fn convert(ba: BindingAnnotation) -> BindingMode {
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index 20a6af5f6c1..c4b743dd467 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -15,6 +15,12 @@ pub enum IntTy {
     Char,
 }
 
+impl IntTy {
+    pub fn is_signed(self) -> bool {
+        matches!(self, Self::I)
+    }
+}
+
 // Valid types for the result of a non-coercion cast
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum CastTy<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index c88cac30a19..f5ce43f3afb 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -18,18 +18,8 @@ use self::BorrowKind::*;
 // This represents accessing self in the closure structure
 pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
 
-#[derive(
-    Clone,
-    Copy,
-    Debug,
-    PartialEq,
-    Eq,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable,
-    HashStable
-)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct UpvarPath {
     pub hir_id: hir::HirId,
 }
@@ -37,7 +27,8 @@ pub struct UpvarPath {
 /// Upvars do not get their own `NodeId`. Instead, we use the pair of
 /// the original var ID (that is, the root variable that is referenced
 /// by the upvar) and the ID of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct UpvarId {
     pub var_path: UpvarPath,
     pub closure_expr_id: LocalDefId,
@@ -51,7 +42,8 @@ impl UpvarId {
 
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum UpvarCapture {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
@@ -139,7 +131,8 @@ impl<'tcx> ClosureKind {
 }
 
 /// A composite describing a `Place` that is captured by a closure.
-#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct CapturedPlace<'tcx> {
     /// The `Place` that is captured.
     pub place: HirPlace<'tcx>,
@@ -284,7 +277,8 @@ pub fn is_ancestor_or_same_capture(
 /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
-#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
+#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct CaptureInfo {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
     ///
@@ -362,7 +356,8 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
     curr_string
 }
 
-#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, TypeFoldable, Copy, HashStable)]
+#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum BorrowKind {
     /// Data must be immutable and is aliasable.
     ImmBorrow,
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index bc52259b151..a4e7a12bba3 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -2,7 +2,7 @@ use crate::mir::interpret::LitToConstInput;
 use crate::mir::ConstantKind;
 use crate::ty::{
     self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
-    TyCtxt, TypeFoldable,
+    TyCtxt, TypeVisitable,
 };
 use rustc_data_structures::intern::Interned;
 use rustc_errors::ErrorGuaranteed;
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 51e51a63fd0..7436f0f6f4d 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -4,6 +4,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_target::abi::Size;
 use std::convert::{TryFrom, TryInto};
 use std::fmt;
+use std::num::NonZeroU8;
 
 use crate::ty::TyCtxt;
 
@@ -123,7 +124,7 @@ pub struct ScalarInt {
     /// The first `size` bytes of `data` are the value.
     /// Do not try to read less or more bytes than that. The remaining bytes must be 0.
     data: u128,
-    size: u8,
+    size: NonZeroU8,
 }
 
 // Cannot derive these, as the derives take references to the fields, and we
@@ -135,33 +136,31 @@ impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
         // Since `Self` is a packed struct, that would create a possibly unaligned reference,
         // which is UB.
         { self.data }.hash_stable(hcx, hasher);
-        self.size.hash_stable(hcx, hasher);
+        self.size.get().hash_stable(hcx, hasher);
     }
 }
 
 impl<S: Encoder> Encodable<S> for ScalarInt {
     fn encode(&self, s: &mut S) {
         s.emit_u128(self.data);
-        s.emit_u8(self.size);
+        s.emit_u8(self.size.get());
     }
 }
 
 impl<D: Decoder> Decodable<D> for ScalarInt {
     fn decode(d: &mut D) -> ScalarInt {
-        ScalarInt { data: d.read_u128(), size: d.read_u8() }
+        ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() }
     }
 }
 
 impl ScalarInt {
-    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };
+    pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: NonZeroU8::new(1).unwrap() };
 
-    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };
-
-    pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };
+    pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: NonZeroU8::new(1).unwrap() };
 
     #[inline]
     pub fn size(self) -> Size {
-        Size::from_bytes(self.size)
+        Size::from_bytes(self.size.get())
     }
 
     /// Make sure the `data` fits in `size`.
@@ -185,7 +184,7 @@ impl ScalarInt {
 
     #[inline]
     pub fn null(size: Size) -> Self {
-        Self { data: 0, size: size.bytes() as u8 }
+        Self { data: 0, size: NonZeroU8::new(size.bytes() as u8).unwrap() }
     }
 
     #[inline]
@@ -197,7 +196,7 @@ impl ScalarInt {
     pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
         let data = i.into();
         if size.truncate(data) == data {
-            Some(Self { data, size: size.bytes() as u8 })
+            Some(Self { data, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -209,7 +208,7 @@ impl ScalarInt {
         // `into` performed sign extension, we have to truncate
         let truncated = size.truncate(i as u128);
         if size.sign_extend(truncated) as i128 == i {
-            Some(Self { data: truncated, size: size.bytes() as u8 })
+            Some(Self { data: truncated, size: NonZeroU8::new(size.bytes() as u8).unwrap() })
         } else {
             None
         }
@@ -225,7 +224,7 @@ impl ScalarInt {
     #[inline]
     pub fn to_bits(self, target_size: Size) -> Result<u128, Size> {
         assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
-        if target_size.bytes() == u64::from(self.size) {
+        if target_size.bytes() == u64::from(self.size.get()) {
             self.check_data();
             Ok(self.data)
         } else {
@@ -339,7 +338,7 @@ macro_rules! from {
                 fn from(u: $ty) -> Self {
                     Self {
                         data: u128::from(u),
-                        size: std::mem::size_of::<$ty>() as u8,
+                        size: NonZeroU8::new(std::mem::size_of::<$ty>() as u8).unwrap(),
                     }
                 }
             }
@@ -382,7 +381,7 @@ impl TryFrom<ScalarInt> for bool {
 impl From<char> for ScalarInt {
     #[inline]
     fn from(c: char) -> Self {
-        Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
+        Self { data: c as u128, size: NonZeroU8::new(std::mem::size_of::<char>() as u8).unwrap() }
     }
 }
 
@@ -409,7 +408,7 @@ impl From<Single> for ScalarInt {
     #[inline]
     fn from(f: Single) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: 4 }
+        Self { data: f.to_bits(), size: NonZeroU8::new((Single::BITS / 8) as u8).unwrap() }
     }
 }
 
@@ -425,7 +424,7 @@ impl From<Double> for ScalarInt {
     #[inline]
     fn from(f: Double) -> Self {
         // We trust apfloat to give us properly truncated data.
-        Self { data: f.to_bits(), size: 8 }
+        Self { data: f.to_bits(), size: NonZeroU8::new((Double::BITS / 8) as u8).unwrap() }
     }
 }
 
@@ -439,19 +438,18 @@ impl TryFrom<ScalarInt> for Double {
 
 impl fmt::Debug for ScalarInt {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.size == 0 {
-            self.check_data();
-            write!(f, "<ZST>")
-        } else {
-            // Dispatch to LowerHex below.
-            write!(f, "0x{:x}", self)
-        }
+        // Dispatch to LowerHex below.
+        write!(f, "0x{:x}", self)
     }
 }
 
 impl fmt::LowerHex for ScalarInt {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.check_data();
+        if f.alternate() {
+            // Like regular ints, alternate flag adds leading `0x`.
+            write!(f, "0x")?;
+        }
         // Format as hex number wide enough to fit any value of the given `size`.
         // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
         // Using a block `{self.data}` here to force a copy instead of using `self.data`
@@ -459,7 +457,7 @@ impl fmt::LowerHex for ScalarInt {
         // would thus borrow `self.data`. Since `Self`
         // is a packed struct, that would create a possibly unaligned reference, which
         // is UB.
-        write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
+        write!(f, "{:01$x}", { self.data }, self.size.get() as usize * 2)
     }
 }
 
@@ -473,7 +471,7 @@ impl fmt::UpperHex for ScalarInt {
         // would thus borrow `self.data`. Since `Self`
         // is a packed struct, that would create a possibly unaligned reference, which
         // is UB.
-        write!(f, "{:01$X}", { self.data }, self.size as usize * 2)
+        write!(f, "{:01$X}", { self.data }, self.size.get() as usize * 2)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 10d03065c79..cb0137d2e5e 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -4,7 +4,7 @@ use crate::mir::interpret::{AllocId, ConstValue, Scalar};
 use crate::mir::Promoted;
 use crate::ty::subst::{InternalSubsts, SubstsRef};
 use crate::ty::ParamEnv;
-use crate::ty::{self, TyCtxt, TypeFoldable};
+use crate::ty::{self, TyCtxt, TypeVisitable};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index c3df9a66fe7..a594dab2e20 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -4,7 +4,7 @@ use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
 use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
-use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
+use crate::lint::{struct_lint_level, LintLevelSource};
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::resolve_lifetime;
 use crate::middle::stability;
@@ -32,12 +32,13 @@ use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
-use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
+use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
 use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
+use rustc_hir::definitions::Definitions;
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
@@ -390,7 +391,7 @@ impl<'a, V> LocalTableInContextMut<'a, V> {
 /// Here, we would store the type `T`, the span of the value `x`, the "scope-span" for
 /// the scope that contains `x`, the expr `T` evaluated from, and the span of `foo.await`.
 #[derive(TyEncodable, TyDecodable, Clone, Debug, Eq, Hash, PartialEq, HashStable)]
-#[derive(TypeFoldable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct GeneratorInteriorTypeCause<'tcx> {
     /// Type of the captured binding.
     pub ty: Ty<'tcx>,
@@ -871,7 +872,7 @@ rustc_index::newtype_index! {
 pub type CanonicalUserTypeAnnotations<'tcx> =
     IndexVec<UserTypeAnnotationIndex, CanonicalUserTypeAnnotation<'tcx>>;
 
-#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct CanonicalUserTypeAnnotation<'tcx> {
     pub user_ty: CanonicalUserType<'tcx>,
     pub span: Span,
@@ -931,7 +932,7 @@ impl<'tcx> CanonicalUserType<'tcx> {
 /// from constants that are named via paths, like `Foo::<A>::new` and
 /// so forth.
 #[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub enum UserType<'tcx> {
     Ty(Ty<'tcx>),
 
@@ -1045,6 +1046,7 @@ impl<'tcx> Deref for TyCtxt<'tcx> {
 
 pub struct GlobalCtxt<'tcx> {
     pub arena: &'tcx WorkerLocal<Arena<'tcx>>,
+    pub hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
 
     interners: CtxtInterners<'tcx>,
 
@@ -1069,13 +1071,15 @@ pub struct GlobalCtxt<'tcx> {
     /// Common consts, pre-interned for your convenience.
     pub consts: CommonConsts<'tcx>,
 
-    definitions: rustc_hir::definitions::Definitions,
+    definitions: RwLock<Definitions>,
     cstore: Box<CrateStoreDyn>,
 
     /// Output of the resolver.
     pub(crate) untracked_resolutions: ty::ResolverOutputs,
-
-    pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>,
+    untracked_resolver_for_lowering: Steal<ty::ResolverAstLowering>,
+    /// The entire crate as AST. This field serves as the input for the hir_crate query,
+    /// which lowers it from AST to HIR. It must not be read or used by anything else.
+    pub untracked_crate: Steal<Lrc<ast::Crate>>,
 
     /// This provides access to the incremental compilation on-disk cache for query results.
     /// Do not access this directly. It is only meant to be used by
@@ -1233,10 +1237,12 @@ impl<'tcx> TyCtxt<'tcx> {
         s: &'tcx Session,
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
-        definitions: rustc_hir::definitions::Definitions,
+        hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
+        definitions: Definitions,
         cstore: Box<CrateStoreDyn>,
         untracked_resolutions: ty::ResolverOutputs,
-        krate: &'tcx hir::Crate<'tcx>,
+        untracked_resolver_for_lowering: ty::ResolverAstLowering,
+        krate: Lrc<ast::Crate>,
         dep_graph: DepGraph,
         on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
@@ -1263,16 +1269,18 @@ impl<'tcx> TyCtxt<'tcx> {
             sess: s,
             lint_store,
             arena,
+            hir_arena,
             interners,
             dep_graph,
-            definitions,
+            definitions: RwLock::new(definitions),
             cstore,
-            untracked_resolutions,
             prof: s.prof.clone(),
             types: common_types,
             lifetimes: common_lifetimes,
             consts: common_consts,
-            untracked_crate: krate,
+            untracked_resolutions,
+            untracked_resolver_for_lowering: Steal::new(untracked_resolver_for_lowering),
+            untracked_crate: Steal::new(krate),
             on_disk_cache,
             queries,
             query_caches: query::QueryCaches::default(),
@@ -1368,7 +1376,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey {
         // Accessing the DefKey is ok, since it is part of DefPathHash.
         if let Some(id) = id.as_local() {
-            self.definitions.def_key(id)
+            self.definitions_untracked().def_key(id)
         } else {
             self.cstore.def_key(id)
         }
@@ -1382,7 +1390,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn def_path(self, id: DefId) -> rustc_hir::definitions::DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
         if let Some(id) = id.as_local() {
-            self.definitions.def_path(id)
+            self.definitions_untracked().def_path(id)
         } else {
             self.cstore.def_path(id)
         }
@@ -1392,7 +1400,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
         // Accessing the DefPathHash is ok, it is incr. comp. stable.
         if let Some(def_id) = def_id.as_local() {
-            self.definitions.def_path_hash(def_id)
+            self.definitions_untracked().def_path_hash(def_id)
         } else {
             self.cstore.def_path_hash(def_id)
         }
@@ -1429,7 +1437,7 @@ impl<'tcx> TyCtxt<'tcx> {
         // If this is a DefPathHash from the local crate, we can look up the
         // DefId in the tcx's `Definitions`.
         if stable_crate_id == self.sess.local_stable_crate_id() {
-            self.definitions.local_def_path_hash_to_def_id(hash, err).to_def_id()
+            self.definitions.read().local_def_path_hash_to_def_id(hash, err).to_def_id()
         } else {
             // If this is a DefPathHash from an upstream crate, let the CrateStore map
             // it to a DefId.
@@ -1460,6 +1468,64 @@ impl<'tcx> TyCtxt<'tcx> {
         )
     }
 
+    /// Create a new definition within the incr. comp. engine.
+    pub fn create_def(self, parent: LocalDefId, data: hir::definitions::DefPathData) -> LocalDefId {
+        // This function modifies `self.definitions` using a side-effect.
+        // We need to ensure that these side effects are re-run by the incr. comp. engine.
+        // Depending on the forever-red node will tell the graph that the calling query
+        // needs to be re-evaluated.
+        use rustc_query_system::dep_graph::DepNodeIndex;
+        self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE);
+
+        // The following call has the side effect of modifying the tables inside `definitions`.
+        // These very tables are relied on by the incr. comp. engine to decode DepNodes and to
+        // decode the on-disk cache.
+        //
+        // Any LocalDefId which is used within queries, either as key or result, either:
+        // - has been created before the construction of the TyCtxt;
+        // - has been created by this call to `create_def`.
+        // As a consequence, this LocalDefId is always re-created before it is needed by the incr.
+        // comp. engine itself.
+        //
+        // This call also writes to the value of `source_span` and `expn_that_defined` queries.
+        // This is fine because:
+        // - those queries are `eval_always` so we won't miss their result changing;
+        // - this write will have happened before these queries are called.
+        self.definitions.write().create_def(parent, data)
+    }
+
+    pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
+        // Create a dependency to the crate to be sure we re-execute this when the amount of
+        // definitions change.
+        self.ensure().hir_crate(());
+        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
+        let definitions = self.definitions.leak();
+        definitions.iter_local_def_id()
+    }
+
+    pub fn def_path_table(self) -> &'tcx rustc_hir::definitions::DefPathTable {
+        // Create a dependency to the crate to be sure we reexcute this when the amount of
+        // definitions change.
+        self.ensure().hir_crate(());
+        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
+        let definitions = self.definitions.leak();
+        definitions.def_path_table()
+    }
+
+    pub fn def_path_hash_to_def_index_map(
+        self,
+    ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap {
+        // Create a dependency to the crate to be sure we reexcute this when the amount of
+        // definitions change.
+        self.ensure().hir_crate(());
+        // Leak a read lock once we start iterating on definitions, to prevent adding new onces
+        // while iterating.  If some query needs to add definitions, it should be `ensure`d above.
+        let definitions = self.definitions.leak();
+        definitions.def_path_hash_to_def_index_map()
+    }
+
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
     pub fn cstore_untracked(self) -> &'tcx CrateStoreDyn {
@@ -1468,8 +1534,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Note that this is *untracked* and should only be used within the query
     /// system if the result is otherwise tracked through queries
-    pub fn definitions_untracked(self) -> &'tcx hir::definitions::Definitions {
-        &self.definitions
+    #[inline]
+    pub fn definitions_untracked(self) -> ReadGuard<'tcx, Definitions> {
+        self.definitions.read()
     }
 
     /// Note that this is *untracked* and should only be used within the query
@@ -1480,23 +1547,18 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     #[inline(always)]
-    pub fn create_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        StableHashingContext::new(
-            self.sess,
-            &self.definitions,
-            &*self.cstore,
-            &self.untracked_resolutions.source_span,
-        )
-    }
-
-    #[inline(always)]
-    pub fn create_no_span_stable_hashing_context(self) -> StableHashingContext<'tcx> {
-        StableHashingContext::ignore_spans(
+    pub fn with_stable_hashing_context<R>(
+        self,
+        f: impl FnOnce(StableHashingContext<'_>) -> R,
+    ) -> R {
+        let definitions = self.definitions_untracked();
+        let hcx = StableHashingContext::new(
             self.sess,
-            &self.definitions,
+            &*definitions,
             &*self.cstore,
             &self.untracked_resolutions.source_span,
-        )
+        );
+        f(hcx)
     }
 
     pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult {
@@ -2304,7 +2366,7 @@ impl<'tcx> TyCtxt<'tcx> {
         self.interners.intern_ty(
             st,
             self.sess,
-            &self.definitions,
+            &self.definitions.read(),
             &*self.cstore,
             // This is only used to create a stable hashing context.
             &self.untracked_resolutions.source_span,
@@ -2787,6 +2849,18 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
+    /// typically generated by `#[derive(LintDiagnostic)]`).
+    pub fn emit_spanned_lint(
+        self,
+        lint: &'static Lint,
+        hir_id: HirId,
+        span: impl Into<MultiSpan>,
+        decorator: impl for<'a> DecorateLint<'a, ()>,
+    ) {
+        self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag))
+    }
+
     pub fn struct_span_lint_hir(
         self,
         lint: &'static Lint,
@@ -2798,6 +2872,17 @@ impl<'tcx> TyCtxt<'tcx> {
         struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate);
     }
 
+    /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
+    /// generated by `#[derive(LintDiagnostic)]`).
+    pub fn emit_lint(
+        self,
+        lint: &'static Lint,
+        id: HirId,
+        decorator: impl for<'a> DecorateLint<'a, ()>,
+    ) {
+        self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag))
+    }
+
     pub fn struct_lint_node(
         self,
         lint: &'static Lint,
@@ -2899,6 +2984,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 
 pub fn provide(providers: &mut ty::query::Providers) {
     providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
+    providers.resolver_for_lowering = |tcx, ()| &tcx.untracked_resolver_for_lowering;
     providers.module_reexports =
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index a84b3c9373b..25bc6dc6167 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -3,8 +3,8 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
-    PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor,
+    visit::TypeVisitable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy,
+    PolyTraitPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
@@ -87,7 +87,7 @@ pub trait IsSuggestable<'tcx> {
 
 impl<'tcx, T> IsSuggestable<'tcx> for T
 where
-    T: TypeFoldable<'tcx>,
+    T: TypeVisitable<'tcx>,
 {
     fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool {
         self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue()
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 6d7e60ecc31..f39fa363a16 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,5 +1,6 @@
 use crate::mir;
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use crate::ty::visit::TypeVisitable;
 use crate::ty::{self, Ty, TyCtxt, TypeFlags};
 
 pub(super) fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 812dd2adc2e..49a518b101d 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -13,7 +13,7 @@ use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::fmt;
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]
 pub struct ExpectedFound<T> {
     pub expected: T,
     pub found: T,
@@ -30,7 +30,7 @@ impl<T> ExpectedFound<T> {
 }
 
 // Data structures used in type unification
-#[derive(Clone, Debug, TypeFoldable)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
 pub enum TypeError<'tcx> {
     Mismatch,
     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
@@ -795,7 +795,7 @@ fn foo(&self) -> Self::T { String::new() }
                         if item_def_id == proj_ty_item_def_id =>
                     {
                         Some((
-                            self.sess.source_map().guess_head_span(self.def_span(item.def_id)),
+                            self.def_span(item.def_id),
                             format!("consider calling `{}`", self.def_path_str(item.def_id)),
                         ))
                     }
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index a8145e6820c..8d019a3bad8 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,6 +1,6 @@
 use crate::mir::Mutability;
 use crate::ty::subst::GenericArgKind;
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Ty, TyCtxt, TypeVisitable};
 use rustc_hir::def_id::DefId;
 use std::fmt::Debug;
 use std::hash::Hash;
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a6310ae5e66..f8893ae29f5 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -1,76 +1,60 @@
-//! A generalized traversal mechanism for complex data structures that contain
-//! type information.
+//! A folding traversal mechanism for complex data structures that contain type
+//! information.
 //!
-//! There are two types of traversal.
-//! - Folding. This is a modifying traversal. It consumes the data structure,
-//!   producing a (possibly) modified version of it. Both fallible and
-//!   infallible versions are available. The name is potentially
-//!   confusing, because this traversal is more like `Iterator::map` than
-//!   `Iterator::fold`.
-//! - Visiting. This is a read-only traversal of the data structure.
+//! This is a modifying traversal. It consumes the data structure, producing a
+//! (possibly) modified version of it. Both fallible and infallible versions are
+//! available. The name is potentially confusing, because this traversal is more
+//! like `Iterator::map` than `Iterator::fold`.
 //!
-//! These traversals have limited flexibility. Only a small number of "types of
+//! This traversal has limited flexibility. Only a small number of "types of
 //! interest" within the complex data structures can receive custom
-//! modification (when folding) or custom visitation (when visiting). These are
-//! the ones containing the most important type-related information, such as
-//! `Ty`, `Predicate`, `Region`, and `Const`.
+//! modification. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
 //!
-//! There are three traits involved in each traversal type.
-//! - `TypeFoldable`. This is implemented once for many types. This includes
-//!   both:
+//! There are three groups of traits involved in each traversal.
+//! - `TypeFoldable`. This is implemented once for many types, including:
 //!   - Types of interest, for which the the methods delegate to the
-//!     folder/visitor.
+//!     folder.
 //!   - All other types, including generic containers like `Vec` and `Option`.
-//!     It defines a "skeleton" of how they should be traversed, for both
-//!     folding and visiting.
+//!     It defines a "skeleton" of how they should be folded.
 //! - `TypeSuperFoldable`. This is implemented only for each type of interest,
-//!   and defines the traversal "skeleton" for these types.
-//! - `TypeFolder`/`FallibleTypeFolder` (for infallible/fallible folding
-//!   traversals) or `TypeVisitor` (for visiting traversals). One of these is
-//!   implemented for each folder/visitor. This defines how types of interest
-//!   are folded/visited.
+//!   and defines the folding "skeleton" for these types.
+//! - `TypeFolder`/`FallibleTypeFolder. One of these is implemented for each
+//!   folder. This defines how types of interest are folded.
 //!
-//! This means each traversal is a mixture of (a) generic traversal operations,
-//! and (b) custom fold/visit operations that are specific to the
-//! folder/visitor.
+//! This means each fold is a mixture of (a) generic folding operations, and (b)
+//! custom fold operations that are specific to the folder.
 //! - The `TypeFoldable` impls handle most of the traversal, and call into
-//!   `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
-//!   type of interest.
-//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may call into another
-//!   `TypeFoldable` impl, because some of the types of interest are recursive
-//!   and can contain other types of interest.
-//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call into
-//!   a `TypeSuperFoldable` impl, because each folder/visitor might provide
-//!   custom handling only for some types of interest, or only for some
-//!   variants of each type of interest, and then use default traversal for the
-//!   remaining cases.
+//!   `TypeFolder`/`FallibleTypeFolder` when they encounter a type of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may call into another `TypeFoldable`
+//!   impl, because some of the types of interest are recursive and can contain
+//!   other types of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder` may also call into a `TypeSuperFoldable`
+//!   impl, because each folder might provide custom handling only for some types
+//!   of interest, or only for some variants of each type of interest, and then
+//!   use default traversal for the remaining cases.
 //!
 //! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
-//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be visited like so:
+//! TypeFoldable`, and an instance `s = S(ty, u)`, it would be folded like so:
 //! ```text
-//! s.visit_with(visitor) calls
-//! - ty.visit_with(visitor) calls
-//!   - visitor.visit_ty(ty) may call
-//!     - ty.super_visit_with(visitor)
-//! - u.visit_with(visitor)
+//! s.fold_with(folder) calls
+//! - ty.fold_with(folder) calls
+//!   - folder.fold_ty(ty) may call
+//!     - ty.super_fold_with(folder)
+//! - u.fold_with(folder)
 //! ```
 use crate::mir;
-use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
-use rustc_errors::ErrorGuaranteed;
+use crate::ty::{self, Binder, Ty, TyCtxt, TypeVisitable};
 use rustc_hir::def_id::DefId;
 
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sso::SsoHashSet;
 use std::collections::BTreeMap;
-use std::fmt;
-use std::ops::ControlFlow;
 
-/// This trait is implemented for every type that can be folded/visited,
+/// This trait is implemented for every type that can be folded,
 /// providing the skeleton of the traversal.
 ///
 /// To implement this conveniently, use the derive macro located in
 /// `rustc_macros`.
-pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
+pub trait TypeFoldable<'tcx>: TypeVisitable<'tcx> {
     /// The entry point for folding. To fold a value `t` with a folder `f`
     /// call: `t.try_fold_with(f)`.
     ///
@@ -89,115 +73,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         self.try_fold_with(folder).into_ok()
     }
-
-    /// The entry point for visiting. To visit a value `t` with a visitor `v`
-    /// call: `t.visit_with(v)`.
-    ///
-    /// For most types, this just traverses the value, calling `visit_with` on
-    /// each field/element.
-    ///
-    /// For types of interest (such as `Ty`), the implementation of this method
-    /// that calls a visitor method specifically for that type (such as
-    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
-    /// `TypeVisitor`.
-    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
-
-    /// Returns `true` if `self` has any late-bound regions that are either
-    /// bound by `binder` or bound by some binder outside of `binder`.
-    /// If `binder` is `ty::INNERMOST`, this indicates whether
-    /// there are any late-bound regions that appear free.
-    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
-    }
-
-    /// Returns `true` if this `self` has any regions that escape `binder` (and
-    /// hence are not bound by it).
-    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.has_vars_bound_at_or_above(binder.shifted_in(1))
-    }
-
-    fn has_escaping_bound_vars(&self) -> bool {
-        self.has_vars_bound_at_or_above(ty::INNERMOST)
-    }
-
-    #[instrument(level = "trace")]
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
-    }
-    fn has_projections(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PROJECTION)
-    }
-    fn has_opaque_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
-    }
-    fn references_error(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_ERROR)
-    }
-    fn error_reported(&self) -> Option<ErrorGuaranteed> {
-        if self.references_error() {
-            Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
-        } else {
-            None
-        }
-    }
-    fn has_param_types_or_consts(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
-    }
-    fn has_infer_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_INFER)
-    }
-    fn has_infer_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER)
-    }
-    fn has_infer_types_or_consts(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
-    }
-    fn needs_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_INFER)
-    }
-    fn has_placeholders(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::HAS_RE_PLACEHOLDER
-                | TypeFlags::HAS_TY_PLACEHOLDER
-                | TypeFlags::HAS_CT_PLACEHOLDER,
-        )
-    }
-    fn needs_subst(&self) -> bool {
-        self.has_type_flags(TypeFlags::NEEDS_SUBST)
-    }
-    /// "Free" regions in this context means that it has any region
-    /// that is not (a) erased or (b) late-bound.
-    fn has_free_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
-
-    fn has_erased_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
-    }
-
-    /// True if there are any un-erased free regions.
-    fn has_erasable_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
-
-    /// Indicates whether this value references only 'global'
-    /// generic parameters that are the same regardless of what fn we are
-    /// in. This is used for caching.
-    fn is_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
-    }
-
-    /// True if there are any late-bound regions
-    fn has_late_bound_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
-    }
-
-    /// Indicates whether this value still has parameters/placeholders/inference variables
-    /// which could be replaced later, in a way that would change the results of `impl`
-    /// specialization.
-    fn still_further_specializable(&self) -> bool {
-        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
-    }
 }
 
 // This trait is implemented for types of interest.
@@ -219,14 +94,6 @@ pub trait TypeSuperFoldable<'tcx>: TypeFoldable<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
         self.try_super_fold_with(folder).into_ok()
     }
-
-    /// Provides a default visit for a type of interest. This should only be
-    /// called within `TypeVisitor` methods, when a non-custom traversal is
-    /// desired for the value of the type of interest passed to that method.
-    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
-    /// `ty.super_visit_with(self)`, but any other visiting should be done
-    /// with `xyz.visit_with(self)`.
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
 }
 
 /// This trait is implemented for every infallible folding traversal. There is
@@ -376,44 +243,6 @@ where
     }
 }
 
-/// This trait is implemented for every visiting traversal. There is a visit
-/// method defined for every type of interest. Each such method has a default
-/// that recurses into the type's fields in a non-custom fashion.
-pub trait TypeVisitor<'tcx>: Sized {
-    type BreakTy = !;
-
-    fn visit_binder<T: TypeFoldable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        r.super_visit_with(self)
-    }
-
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
-
-    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
-        uv.super_visit_with(self)
-    }
-
-    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        p.super_visit_with(self)
-    }
-
-    fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
-        c.super_visit_with(self)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Some sample folders
 
@@ -472,99 +301,6 @@ impl<'tcx> TyCtxt<'tcx> {
     {
         value.fold_with(&mut RegionFolder::new(self, &mut f))
     }
-
-    /// Invoke `callback` on every region appearing free in `value`.
-    pub fn for_each_free_region(
-        self,
-        value: &impl TypeFoldable<'tcx>,
-        mut callback: impl FnMut(ty::Region<'tcx>),
-    ) {
-        self.any_free_region_meets(value, |r| {
-            callback(r);
-            false
-        });
-    }
-
-    /// Returns `true` if `callback` returns true for every region appearing free in `value`.
-    pub fn all_free_regions_meet(
-        self,
-        value: &impl TypeFoldable<'tcx>,
-        mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
-    ) -> bool {
-        !self.any_free_region_meets(value, |r| !callback(r))
-    }
-
-    /// Returns `true` if `callback` returns true for some region appearing free in `value`.
-    pub fn any_free_region_meets(
-        self,
-        value: &impl TypeFoldable<'tcx>,
-        callback: impl FnMut(ty::Region<'tcx>) -> bool,
-    ) -> bool {
-        struct RegionVisitor<F> {
-            /// The index of a binder *just outside* the things we have
-            /// traversed. If we encounter a bound region bound by this
-            /// binder or one outer to it, it appears free. Example:
-            ///
-            /// ```ignore (illustrative)
-            ///       for<'a> fn(for<'b> fn(), T)
-            /// // ^          ^          ^     ^
-            /// // |          |          |     | here, would be shifted in 1
-            /// // |          |          | here, would be shifted in 2
-            /// // |          | here, would be `INNERMOST` shifted in by 1
-            /// // | here, initially, binder would be `INNERMOST`
-            /// ```
-            ///
-            /// You see that, initially, *any* bound value is free,
-            /// because we've not traversed any binders. As we pass
-            /// through a binder, we shift the `outer_index` by 1 to
-            /// account for the new binder that encloses us.
-            outer_index: ty::DebruijnIndex,
-            callback: F,
-        }
-
-        impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
-        where
-            F: FnMut(ty::Region<'tcx>) -> bool,
-        {
-            type BreakTy = ();
-
-            fn visit_binder<T: TypeFoldable<'tcx>>(
-                &mut self,
-                t: &Binder<'tcx, T>,
-            ) -> ControlFlow<Self::BreakTy> {
-                self.outer_index.shift_in(1);
-                let result = t.super_visit_with(self);
-                self.outer_index.shift_out(1);
-                result
-            }
-
-            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-                match *r {
-                    ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
-                        ControlFlow::CONTINUE
-                    }
-                    _ => {
-                        if (self.callback)(r) {
-                            ControlFlow::BREAK
-                        } else {
-                            ControlFlow::CONTINUE
-                        }
-                    }
-                }
-            }
-
-            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                // We're only interested in types involving regions
-                if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
-                    ty.super_visit_with(self)
-                } else {
-                    ControlFlow::CONTINUE
-                }
-            }
-        }
-
-        value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
-    }
 }
 
 /// Folds over the substructure of a type, visiting its component
@@ -861,45 +597,6 @@ impl<'tcx> TyCtxt<'tcx> {
         )
     }
 
-    /// Returns a set of all late-bound regions that are constrained
-    /// by `value`, meaning that if we instantiate those LBR with
-    /// variables and equate `value` with something else, those
-    /// variables will also be equated.
-    pub fn collect_constrained_late_bound_regions<T>(
-        self,
-        value: &Binder<'tcx, T>,
-    ) -> FxHashSet<ty::BoundRegionKind>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.collect_late_bound_regions(value, true)
-    }
-
-    /// Returns a set of all late-bound regions that appear in `value` anywhere.
-    pub fn collect_referenced_late_bound_regions<T>(
-        self,
-        value: &Binder<'tcx, T>,
-    ) -> FxHashSet<ty::BoundRegionKind>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.collect_late_bound_regions(value, false)
-    }
-
-    fn collect_late_bound_regions<T>(
-        self,
-        value: &Binder<'tcx, T>,
-        just_constraint: bool,
-    ) -> FxHashSet<ty::BoundRegionKind>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let mut collector = LateBoundRegionsCollector::new(just_constraint);
-        let result = value.as_ref().skip_binder().visit_with(&mut collector);
-        assert!(result.is_continue()); // should never have stopped early
-        collector.regions
-    }
-
     /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also
     /// method lookup and a few other places where precise region relationships are not required.
     pub fn erase_late_bound_regions<T>(self, value: Binder<'tcx, T>) -> T
@@ -940,103 +637,6 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-pub struct ValidateBoundVars<'tcx> {
-    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-    binder_index: ty::DebruijnIndex,
-    // We may encounter the same variable at different levels of binding, so
-    // this can't just be `Ty`
-    visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
-}
-
-impl<'tcx> ValidateBoundVars<'tcx> {
-    pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
-        ValidateBoundVars {
-            bound_vars,
-            binder_index: ty::INNERMOST,
-            visited: SsoHashSet::default(),
-        }
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
-    type BreakTy = ();
-
-    fn visit_binder<T: TypeFoldable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.binder_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.binder_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if t.outer_exclusive_binder() < self.binder_index
-            || !self.visited.insert((self.binder_index, t))
-        {
-            return ControlFlow::BREAK;
-        }
-        match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
-                if self.bound_vars.len() <= bound_ty.var.as_usize() {
-                    bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
-                }
-                let list_var = self.bound_vars[bound_ty.var.as_usize()];
-                match list_var {
-                    ty::BoundVariableKind::Ty(kind) => {
-                        if kind != bound_ty.kind {
-                            bug!(
-                                "Mismatched type kinds: {:?} doesn't var in list {:?}",
-                                bound_ty.kind,
-                                list_var
-                            );
-                        }
-                    }
-                    _ => {
-                        bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
-                    }
-                }
-            }
-
-            _ => (),
-        };
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match *r {
-            ty::ReLateBound(index, br) if index == self.binder_index => {
-                if self.bound_vars.len() <= br.var.as_usize() {
-                    bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
-                }
-                let list_var = self.bound_vars[br.var.as_usize()];
-                match list_var {
-                    ty::BoundVariableKind::Region(kind) => {
-                        if kind != br.kind {
-                            bug!(
-                                "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
-                                br.kind,
-                                list_var,
-                                self.bound_vars
-                            );
-                        }
-                    }
-                    _ => bug!(
-                        "Mismatched bound variable kinds! Expected region, found {:?}",
-                        list_var
-                    ),
-                }
-            }
-
-            _ => (),
-        };
-
-        r.super_visit_with(self)
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Shifter
 //
@@ -1141,301 +741,3 @@ where
 
     value.fold_with(&mut Shifter::new(tcx, amount))
 }
-
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-struct FoundEscapingVars;
-
-/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
-/// bound region or a bound type.
-///
-/// So, for example, consider a type like the following, which has two binders:
-///
-///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
-///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
-///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
-///
-/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
-/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
-/// fn type*, that type has an escaping region: `'a`.
-///
-/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
-/// we already use the term "free var". It refers to the regions or types that we use to represent
-/// bound regions or type params on a fn definition while we are type checking its body.
-///
-/// To clarify, conceptually there is no particular difference between
-/// an "escaping" var and a "free" var. However, there is a big
-/// difference in practice. Basically, when "entering" a binding
-/// level, one is generally required to do some sort of processing to
-/// a bound var, such as replacing it with a fresh/placeholder
-/// var, or making an entry in the environment to represent the
-/// scope to which it is attached, etc. An escaping var represents
-/// a bound var for which this processing has not yet been done.
-struct HasEscapingVarsVisitor {
-    /// Anything bound by `outer_index` or "above" is escaping.
-    outer_index: ty::DebruijnIndex,
-}
-
-impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
-    type BreakTy = FoundEscapingVars;
-
-    fn visit_binder<T: TypeFoldable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.outer_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.outer_index.shift_out(1);
-        result
-    }
-
-    #[inline]
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // If the outer-exclusive-binder is *strictly greater* than
-        // `outer_index`, that means that `t` contains some content
-        // bound at `outer_index` or above (because
-        // `outer_exclusive_binder` is always 1 higher than the
-        // content in `t`). Therefore, `t` has some escaping vars.
-        if t.outer_exclusive_binder() > self.outer_index {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // If the region is bound by `outer_index` or anything outside
-        // of outer index, then it escapes the binders we have
-        // visited.
-        if r.bound_at_or_above_binder(self.outer_index) {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // we don't have a `visit_infer_const` callback, so we have to
-        // hook in here to catch this case (annoying...), but
-        // otherwise we do want to remember to visit the rest of the
-        // const, as it has types/regions embedded in a lot of other
-        // places.
-        match ct.kind() {
-            ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
-                ControlFlow::Break(FoundEscapingVars)
-            }
-            _ => ct.super_visit_with(self),
-        }
-    }
-
-    #[inline]
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if predicate.outer_exclusive_binder() > self.outer_index {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-struct FoundFlags;
-
-// FIXME: Optimize for checking for infer flags
-struct HasTypeFlagsVisitor {
-    flags: ty::TypeFlags,
-}
-
-impl std::fmt::Debug for HasTypeFlagsVisitor {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.flags.fmt(fmt)
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
-    type BreakTy = FoundFlags;
-
-    #[inline]
-    #[instrument(skip(self), level = "trace")]
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = t.flags();
-        trace!(t.flags=?t.flags());
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(skip(self), level = "trace")]
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = r.type_flags();
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(level = "trace")]
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_const(c);
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(level = "trace")]
-    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = FlagComputation::for_unevaluated_const(uv);
-        trace!(r.flags=?flags);
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    #[instrument(level = "trace")]
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        debug!(
-            "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
-            predicate,
-            predicate.flags(),
-            self.flags
-        );
-        if predicate.flags().intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-}
-
-/// Collects all the late-bound regions at the innermost binding level
-/// into a hash set.
-struct LateBoundRegionsCollector {
-    current_index: ty::DebruijnIndex,
-    regions: FxHashSet<ty::BoundRegionKind>,
-
-    /// `true` if we only want regions that are known to be
-    /// "constrained" when you equate this type with another type. In
-    /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating
-    /// them constraints `'a == 'b`. But if you have `<&'a u32 as
-    /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
-    /// types may mean that `'a` and `'b` don't appear in the results,
-    /// so they are not considered *constrained*.
-    just_constrained: bool,
-}
-
-impl LateBoundRegionsCollector {
-    fn new(just_constrained: bool) -> Self {
-        LateBoundRegionsCollector {
-            current_index: ty::INNERMOST,
-            regions: Default::default(),
-            just_constrained,
-        }
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
-    fn visit_binder<T: TypeFoldable<'tcx>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.current_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.current_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // if we are only looking for "constrained" region, we have to
-        // ignore the inputs to a projection, as they may not appear
-        // in the normalized form
-        if self.just_constrained {
-            if let ty::Projection(..) = t.kind() {
-                return ControlFlow::CONTINUE;
-            }
-        }
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // if we are only looking for "constrained" region, we have to
-        // ignore the inputs of an unevaluated const, as they may not appear
-        // in the normalized form
-        if self.just_constrained {
-            if let ty::ConstKind::Unevaluated(..) = c.kind() {
-                return ControlFlow::CONTINUE;
-            }
-        }
-
-        c.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::ReLateBound(debruijn, br) = *r {
-            if debruijn == self.current_index {
-                self.regions.insert(br.kind);
-            }
-        }
-        ControlFlow::CONTINUE
-    }
-}
-
-/// Finds the max universe present
-pub struct MaxUniverse {
-    max_universe: ty::UniverseIndex,
-}
-
-impl MaxUniverse {
-    pub fn new() -> Self {
-        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
-    }
-
-    pub fn max_universe(self) -> ty::UniverseIndex {
-        self.max_universe
-    }
-}
-
-impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::Placeholder(placeholder) = t.kind() {
-            self.max_universe = ty::UniverseIndex::from_u32(
-                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
-            );
-        }
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
-            self.max_universe = ty::UniverseIndex::from_u32(
-                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
-            );
-        }
-
-        c.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if let ty::RePlaceholder(placeholder) = *r {
-            self.max_universe = ty::UniverseIndex::from_u32(
-                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
-            );
-        }
-
-        ControlFlow::CONTINUE
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e8dd179eac1..391abdbe84c 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,7 +1,9 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::subst::{InternalSubsts, Subst};
-use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use crate::ty::{
+    self, EarlyBinder, SubstsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitable,
+};
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -25,7 +27,7 @@ pub struct Instance<'tcx> {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable)]
+#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
 pub enum InstanceDef<'tcx> {
     /// A user-defined callable item.
     ///
@@ -496,12 +498,12 @@ impl<'tcx> Instance<'tcx> {
         def_id: DefId,
         substs: ty::SubstsRef<'tcx>,
         requested_kind: ty::ClosureKind,
-    ) -> Instance<'tcx> {
+    ) -> Option<Instance<'tcx>> {
         let actual_kind = substs.as_closure().kind();
 
         match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
             Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, substs),
-            _ => Instance::new(def_id, substs),
+            _ => Some(Instance::new(def_id, substs)),
         }
     }
 
@@ -515,7 +517,7 @@ impl<'tcx> Instance<'tcx> {
         tcx: TyCtxt<'tcx>,
         closure_did: DefId,
         substs: ty::SubstsRef<'tcx>,
-    ) -> Instance<'tcx> {
+    ) -> Option<Instance<'tcx>> {
         debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs);
         let fn_once = tcx.require_lang_item(LangItem::FnOnce, None);
         let call_once = tcx
@@ -531,12 +533,13 @@ impl<'tcx> Instance<'tcx> {
         let self_ty = tcx.mk_closure(closure_did, substs);
 
         let sig = substs.as_closure().sig();
-        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let sig =
+            tcx.try_normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig).ok()?;
         assert_eq!(sig.inputs().len(), 1);
         let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
 
         debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
-        Instance { def, substs }
+        Some(Instance { def, substs })
     }
 
     /// Depending on the kind of `InstanceDef`, the MIR body associated with an
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 3b05e42a53e..f87b6e4212d 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2,7 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::subst::Subst;
-use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, subst::SubstsRef, EarlyBinder, ReprOptions, Ty, TyCtxt, TypeVisitable};
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_hir as hir;
@@ -235,9 +235,8 @@ fn sanity_check_layout<'tcx>(
     if cfg!(debug_assertions) {
         fn check_layout_abi<'tcx>(tcx: TyCtxt<'tcx>, layout: Layout<'tcx>) {
             match layout.abi() {
-                Abi::Scalar(_scalar) => {
+                Abi::Scalar(scalar) => {
                     // No padding in scalars.
-                    /* FIXME(#96185):
                     assert_eq!(
                         layout.align().abi,
                         scalar.align(&tcx).abi,
@@ -247,7 +246,7 @@ fn sanity_check_layout<'tcx>(
                         layout.size(),
                         scalar.size(&tcx),
                         "size mismatch between ABI and layout in {layout:#?}"
-                    );*/
+                    );
                 }
                 Abi::Vector { count, element } => {
                     // No padding in vectors. Alignment can be strengthened, though.
@@ -1418,9 +1417,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                 if layout_variants.iter().all(|v| v.abi.is_uninhabited()) {
                     abi = Abi::Uninhabited;
-                } else if tag.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
-                    // Without latter check aligned enums with custom discriminant values
-                    // Would result in ICE see the issue #92464 for more info
+                } else if tag.size(dl) == size {
+                    // Make sure we only use scalar layout when the enum is entirely its
+                    // own tag (i.e. it has no padding nor any non-ZST variant fields).
                     abi = Abi::Scalar(tag);
                 } else {
                     // Try to use a ScalarPair for all tagged enums.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f73eca5bf61..f15108fb750 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -9,9 +9,8 @@
 //!
 //! ["The `ty` module: representing types"]: https://rustc-dev-guide.rust-lang.org/ty.html
 
-pub use self::fold::{
-    FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
-};
+pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
+pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 pub use self::AssocItemContainer::*;
 pub use self::BorrowKind::*;
 pub use self::IntVarValue::*;
@@ -110,6 +109,7 @@ pub mod relate;
 pub mod subst;
 pub mod trait_def;
 pub mod util;
+pub mod visit;
 pub mod vtable;
 pub mod walk;
 
@@ -206,7 +206,7 @@ impl MainDefinition {
 /// The "header" of an impl is everything outside the body: a Self type, a trait
 /// ref (in the case of a trait impl), and a set of predicates (from the
 /// bounds / where-clauses).
-#[derive(Clone, Debug, TypeFoldable)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct ImplHeader<'tcx> {
     pub impl_def_id: DefId,
     pub self_ty: Ty<'tcx>,
@@ -214,24 +214,14 @@ pub struct ImplHeader<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
 }
 
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub enum ImplSubject<'tcx> {
     Trait(TraitRef<'tcx>),
     Inherent(Ty<'tcx>),
 }
 
-#[derive(
-    Copy,
-    Clone,
-    PartialEq,
-    Eq,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    HashStable,
-    Debug,
-    TypeFoldable
-)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub enum ImplPolarity {
     /// `impl Trait for Type`
     Positive,
@@ -307,18 +297,8 @@ impl fmt::Display for BoundConstness {
     }
 }
 
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    Copy,
-    Hash,
-    TyEncodable,
-    TyDecodable,
-    HashStable,
-    TypeFoldable
-)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct ClosureSizeProfileData<'tcx> {
     /// Tuple containing the types of closure captures before the feature `capture_disjoint_fields`
     pub before_feature_tys: Ty<'tcx>,
@@ -611,8 +591,14 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
     }
 }
 
+impl rustc_errors::IntoDiagnosticArg for Predicate<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        rustc_errors::DiagnosticArgValue::Str(std::borrow::Cow::Owned(self.to_string()))
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub enum PredicateKind<'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`
@@ -784,7 +770,7 @@ impl<'tcx> Predicate<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct TraitPredicate<'tcx> {
     pub trait_ref: TraitRef<'tcx>,
 
@@ -863,7 +849,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
 pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
 pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
@@ -874,7 +860,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicat
 /// whether the `a` type is the type that we should label as "expected" when
 /// presenting user diagnostics.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct SubtypePredicate<'tcx> {
     pub a_is_expected: bool,
     pub a: Ty<'tcx>,
@@ -884,7 +870,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
 
 /// Encodes that we have to coerce *from* the `a` type to the `b` type.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct CoercePredicate<'tcx> {
     pub a: Ty<'tcx>,
     pub b: Ty<'tcx>,
@@ -892,7 +878,7 @@ pub struct CoercePredicate<'tcx> {
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub enum Term<'tcx> {
     Ty(Ty<'tcx>),
     Const(Const<'tcx>),
@@ -940,7 +926,7 @@ impl<'tcx> Term<'tcx> {
 /// Form #2 eventually yields one of these `ProjectionPredicate`
 /// instances to normalize the LHS.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
     pub term: Term<'tcx>,
@@ -1084,7 +1070,7 @@ impl<'tcx> Predicate<'tcx> {
 /// `[[], [U:Bar<T>]]`. Now if there were some particular reference
 /// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[],
 /// [usize:Bar<isize>]]`.
-#[derive(Clone, Debug, TypeFoldable)]
+#[derive(Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct InstantiatedPredicates<'tcx> {
     pub predicates: Vec<Predicate<'tcx>>,
     pub spans: Vec<Span>,
@@ -1100,24 +1086,15 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Debug,
-    PartialEq,
-    Eq,
-    HashStable,
-    TyEncodable,
-    TyDecodable,
-    TypeFoldable,
-    Lift
-)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)]
+#[derive(TypeFoldable, TypeVisitable)]
 pub struct OpaqueTypeKey<'tcx> {
+    // FIXME(oli-obk): make this a LocalDefId
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
 }
 
-#[derive(Copy, Clone, Debug, TypeFoldable, HashStable, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
 pub struct OpaqueHiddenType<'tcx> {
     /// The span of this particular definition of the opaque type. So
     /// for example:
@@ -1253,7 +1230,7 @@ pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
 /// except that instead of a `Ty` we bundle the `DefId` of the const parameter.
 /// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some`
 /// to get the type of `did`.
-#[derive(Copy, Clone, Debug, TypeFoldable, Lift, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)]
 #[derive(PartialEq, Eq, PartialOrd, Ord)]
 #[derive(Hash, HashStable)]
 pub struct WithOptConstParam<T> {
@@ -1409,7 +1386,9 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
             self.constness().try_fold_with(folder)?,
         ))
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ParamEnv<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.caller_bounds().visit_with(visitor)?;
         self.reveal().visit_with(visitor)?;
@@ -1536,7 +1515,7 @@ impl<'tcx> ParamEnv<'tcx> {
     /// `where Box<u32>: Copy`, which are clearly never
     /// satisfiable. We generally want to behave as if they were true,
     /// although the surrounding function is never reachable.
-    pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
+    pub fn and<T: TypeVisitable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
         match self.reveal() {
             Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
 
@@ -1569,7 +1548,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable, TypeVisitable)]
 pub struct ParamEnvAnd<'tcx, T> {
     pub param_env: ParamEnv<'tcx>,
     pub value: T,
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 66a0a192a87..9d8a8116594 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -112,6 +112,26 @@ impl<'tcx> TyCtxt<'tcx> {
         self.normalize_erasing_regions(param_env, value)
     }
 
+    /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
+    /// late-bound regions and then normalize the result, yielding up
+    /// a `T` (with regions erased). This is appropriate when the
+    /// binder is being instantiated at the call site.
+    ///
+    /// N.B., currently, higher-ranked type bounds inhibit
+    /// normalization. Therefore, each time we erase them in
+    /// codegen, we need to normalize the contents.
+    pub fn try_normalize_erasing_late_bound_regions<T>(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        value: ty::Binder<'tcx, T>,
+    ) -> Result<T, NormalizationError<'tcx>>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let value = self.erase_late_bound_regions(value);
+        self.try_normalize_erasing_regions(param_env, value)
+    }
+
     /// Monomorphizes a type from the AST by first applying the
     /// in-scope substitutions and then normalizing any associated
     /// types.
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7f3b0fdccc6..f721a175c98 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2,7 +2,7 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{
     self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
-    TypeSuperFoldable,
+    TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
 };
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -1355,10 +1355,6 @@ pub trait PrettyPrinter<'tcx>:
                     " as ",
                 )?;
             }
-            // For function type zsts just printing the path is enough
-            ty::FnDef(d, s) if int == ScalarInt::ZST => {
-                p!(print_value_path(*d, s))
-            }
             // Nontrivial types with scalar bit representation
             _ => {
                 let print = |mut this: Self| {
@@ -2277,14 +2273,14 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
 
     fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         struct LateBoundRegionNameCollector<'a, 'tcx> {
             used_region_names: &'a mut FxHashSet<Symbol>,
             type_collector: SsoHashSet<Ty<'tcx>>,
         }
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
+        impl<'tcx> ty::visit::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
             type BreakTy = ();
 
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -2388,7 +2384,7 @@ macro_rules! define_print_and_forward_display {
 /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
 /// the trait path. That is, it will print `Trait<U>` instead of
 /// `<T as Trait<U>>`.
-#[derive(Copy, Clone, TypeFoldable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
 
 impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
@@ -2400,7 +2396,7 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
 /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only
 /// the trait name. That is, it will print `Trait` instead of
 /// `<T as Trait<U>>`.
-#[derive(Copy, Clone, TypeFoldable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitRefPrintOnlyTraitName<'tcx>(ty::TraitRef<'tcx>);
 
 impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> {
@@ -2425,7 +2421,7 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
     }
 }
 
-#[derive(Copy, Clone, TypeFoldable, Lift)]
+#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
 pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
 
 impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 51980acd38f..818affa7113 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -345,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> {
     }
 }
 
-#[derive(Copy, Debug, Clone, TypeFoldable)]
+#[derive(Copy, Debug, Clone, TypeFoldable, TypeVisitable)]
 struct GeneratorWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>);
 
 impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 8ba5b882fdd..391a0a20c96 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -4,8 +4,9 @@
 
 use crate::mir::interpret;
 use crate::mir::ProjectionKind;
-use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir as hir;
@@ -183,7 +184,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
 // For things that don't carry any arena-allocated data (and are
 // copy...), just add them to this list.
 
-TrivialTypeFoldableAndLiftImpls! {
+TrivialTypeTraversalAndLiftImpls! {
     (),
     bool,
     usize,
@@ -452,7 +453,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
 
 impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T>
 where
-    <T as Lift<'tcx>>::Lifted: TypeFoldable<'tcx>,
+    <T as Lift<'tcx>>::Lifted: TypeVisitable<'tcx>,
 {
     type Lifted = ty::Binder<'tcx, T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -651,7 +652,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::AdtDef<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::AdtDef<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
@@ -664,7 +667,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for
     ) -> Result<(T, U), F::Error> {
         Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>, U: TypeVisitable<'tcx>> TypeVisitable<'tcx> for (T, U) {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)
@@ -684,7 +689,11 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>>
             self.2.try_fold_with(folder)?,
         ))
     }
+}
 
+impl<'tcx, A: TypeVisitable<'tcx>, B: TypeVisitable<'tcx>, C: TypeVisitable<'tcx>>
+    TypeVisitable<'tcx> for (A, B, C)
+{
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.0.visit_with(visitor)?;
         self.1.visit_with(visitor)?;
@@ -692,19 +701,31 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>>
     }
 }
 
-EnumTypeFoldableImpl! {
+EnumTypeTraversalImpl! {
     impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
         (Some)(a),
         (None),
     } where T: TypeFoldable<'tcx>
 }
+EnumTypeTraversalImpl! {
+    impl<'tcx, T> TypeVisitable<'tcx> for Option<T> {
+        (Some)(a),
+        (None),
+    } where T: TypeVisitable<'tcx>
+}
 
-EnumTypeFoldableImpl! {
+EnumTypeTraversalImpl! {
     impl<'tcx, T, E> TypeFoldable<'tcx> for Result<T, E> {
         (Ok)(a),
         (Err)(a),
     } where T: TypeFoldable<'tcx>, E: TypeFoldable<'tcx>,
 }
+EnumTypeTraversalImpl! {
+    impl<'tcx, T, E> TypeVisitable<'tcx> for Result<T, E> {
+        (Ok)(a),
+        (Err)(a),
+    } where T: TypeVisitable<'tcx>, E: TypeVisitable<'tcx>,
+}
 
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(
@@ -744,7 +765,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
             Ok(Rc::from_raw(Rc::into_raw(unique).cast()))
         }
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Rc<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
@@ -788,7 +811,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
             Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
         }
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Arc<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
@@ -798,7 +823,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|value| value.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         (**self).visit_with(visitor)
     }
@@ -808,7 +835,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|t| t.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Vec<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -818,7 +847,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|t| t.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for Box<[T]> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -828,7 +859,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::EarlyBinder<T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_bound(|ty| ty.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::EarlyBinder<T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.as_ref().0.visit_with(visitor)
     }
@@ -838,7 +871,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_binder(self)
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeVisitable<'tcx> for ty::Binder<'tcx, T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_binder(self)
     }
@@ -851,7 +886,9 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeSuperFoldable<'tcx> for ty::Binder<'tcx, T
     ) -> Result<Self, F::Error> {
         self.try_map_bound(|ty| ty.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>> TypeSuperVisitable<'tcx> for ty::Binder<'tcx, T> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.as_ref().skip_binder().visit_with(visitor)
     }
@@ -861,7 +898,11 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::Existentia
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v))
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx>
+    for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
+{
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
@@ -871,7 +912,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_projs(v))
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ProjectionKind> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -903,7 +946,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
             },
         })
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::instance::Instance<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         use crate::ty::InstanceDef::*;
         self.substs.visit_with(visitor)?;
@@ -929,7 +974,9 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(Self { instance: self.instance.try_fold_with(folder)?, promoted: self.promoted })
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for interpret::GlobalId<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.instance.visit_with(visitor)
     }
@@ -939,7 +986,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_ty(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for Ty<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_ty(*self)
     }
@@ -989,7 +1038,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for Ty<'tcx> {
 
         Ok(if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) })
     }
+}
 
+impl<'tcx> TypeSuperVisitable<'tcx> for Ty<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.kind() {
             ty::RawPtr(ref tm) => tm.visit_with(visitor),
@@ -1037,7 +1088,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_region(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::Region<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_region(*self)
     }
@@ -1050,7 +1103,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Region<'tcx> {
     ) -> Result<Self, F::Error> {
         Ok(self)
     }
+}
 
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Region<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
@@ -1060,7 +1115,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_predicate(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::Predicate<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_predicate(*self)
     }
@@ -1069,6 +1126,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
         self.outer_exclusive_binder() > binder
     }
 
+    #[inline]
     fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
         self.flags().intersects(flags)
     }
@@ -1082,7 +1140,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Predicate<'tcx> {
         let new = self.kind().try_fold_with(folder)?;
         Ok(folder.tcx().reuse_or_mk_predicate(self, new))
     }
+}
 
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Predicate<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.kind().visit_with(visitor)
     }
@@ -1092,7 +1152,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         ty::util::fold_list(self, folder, |tcx, v| tcx.intern_predicates(v))
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|p| p.visit_with(visitor))
     }
@@ -1102,7 +1164,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         self.try_map_id(|x| x.try_fold_with(folder))
     }
+}
 
+impl<'tcx, T: TypeVisitable<'tcx>, I: Idx> TypeVisitable<'tcx> for IndexVec<I, T> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -1112,7 +1176,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_const(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::Const<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_const(*self)
     }
@@ -1131,7 +1197,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Const<'tcx> {
             Ok(self)
         }
     }
+}
 
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Const<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.ty().visit_with(visitor)?;
         self.kind().visit_with(visitor)
@@ -1150,7 +1218,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
             | ty::ConstKind::Error(_) => self,
         })
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::ConstKind<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match *self {
             ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
@@ -1168,7 +1238,9 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _folder: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for InferConst<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
@@ -1178,7 +1250,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         folder.try_fold_unevaluated(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         visitor.visit_unevaluated(*self)
     }
@@ -1195,7 +1269,9 @@ impl<'tcx> TypeSuperFoldable<'tcx> for ty::Unevaluated<'tcx> {
             promoted: self.promoted,
         })
     }
+}
 
+impl<'tcx> TypeSuperVisitable<'tcx> for ty::Unevaluated<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.substs.visit_with(visitor)
     }
@@ -1205,7 +1281,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
         Ok(self.expand().try_fold_with(folder)?.shrink())
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for ty::Unevaluated<'tcx, ()> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.expand().visit_with(visitor)
     }
@@ -1215,7 +1293,9 @@ impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
     fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
         Ok(self)
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for hir::Constness {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
         ControlFlow::CONTINUE
     }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 296442e2436..4b51daadabf 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -3,11 +3,11 @@
 #![allow(rustc::usage_of_ty_tykind)]
 
 use crate::infer::canonical::Canonical;
-use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeSuperFoldable,
+    self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable,
     TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
@@ -38,7 +38,7 @@ pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
 pub type RegionKind<'tcx> = IrRegionKind<TyCtxt<'tcx>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct TypeAndMut<'tcx> {
     pub ty: Ty<'tcx>,
     pub mutbl: hir::Mutability,
@@ -201,7 +201,7 @@ static_assert_size!(TyKind<'_>, 32);
 /// * `GR`: The "return type", which is the type of value returned upon
 ///   completion of the generator.
 /// * `GW`: The "generator witness".
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct ClosureSubsts<'tcx> {
     /// Lifetime and type parameters from the enclosing function,
     /// concatenated with a tuple containing the types of the upvars.
@@ -328,7 +328,7 @@ impl<'tcx> ClosureSubsts<'tcx> {
 }
 
 /// Similar to `ClosureSubsts`; see the above documentation for more.
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct GeneratorSubsts<'tcx> {
     pub substs: SubstsRef<'tcx>,
 }
@@ -608,7 +608,7 @@ impl<'tcx> UpvarSubsts<'tcx> {
 /// type of the constant. The reason that `R` is represented as an extra type parameter
 /// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
 /// inline const can reference lifetimes that are internal to the creating function.
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct InlineConstSubsts<'tcx> {
     /// Generic parameters from the enclosing item,
     /// concatenated with the inferred type of the constant.
@@ -655,7 +655,7 @@ impl<'tcx> InlineConstSubsts<'tcx> {
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub enum ExistentialPredicate<'tcx> {
     /// E.g., `Iterator`.
     Trait(ExistentialTraitRef<'tcx>),
@@ -781,7 +781,7 @@ impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> {
 /// Trait references also appear in object types like `Foo<U>`, but in
 /// that case the `Self` parameter is absent from the substitutions.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct TraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -853,7 +853,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
 /// The substitutions don't include the erased `Self`, only trait
 /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct ExistentialTraitRef<'tcx> {
     pub def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -986,7 +986,7 @@ pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>);
 
 impl<'tcx, T> Binder<'tcx, T>
 where
-    T: TypeFoldable<'tcx>,
+    T: TypeVisitable<'tcx>,
 {
     /// Wraps `value` in a binder, asserting that `value` does not
     /// contain any bound vars that would be bound by the
@@ -1050,14 +1050,14 @@ impl<'tcx, T> Binder<'tcx, T> {
         Binder(value, self.1)
     }
 
-    pub fn map_bound_ref<F, U: TypeFoldable<'tcx>>(&self, f: F) -> Binder<'tcx, U>
+    pub fn map_bound_ref<F, U: TypeVisitable<'tcx>>(&self, f: F) -> Binder<'tcx, U>
     where
         F: FnOnce(&T) -> U,
     {
         self.as_ref().map_bound(f)
     }
 
-    pub fn map_bound<F, U: TypeFoldable<'tcx>>(self, f: F) -> Binder<'tcx, U>
+    pub fn map_bound<F, U: TypeVisitable<'tcx>>(self, f: F) -> Binder<'tcx, U>
     where
         F: FnOnce(T) -> U,
     {
@@ -1069,7 +1069,7 @@ impl<'tcx, T> Binder<'tcx, T> {
         Binder(value, self.1)
     }
 
-    pub fn try_map_bound<F, U: TypeFoldable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
+    pub fn try_map_bound<F, U: TypeVisitable<'tcx>, E>(self, f: F) -> Result<Binder<'tcx, U>, E>
     where
         F: FnOnce(T) -> Result<U, E>,
     {
@@ -1092,7 +1092,7 @@ impl<'tcx, T> Binder<'tcx, T> {
     /// in `bind`. This may be (debug) asserted in the future.
     pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U>
     where
-        U: TypeFoldable<'tcx>,
+        U: TypeVisitable<'tcx>,
     {
         if cfg!(debug_assertions) {
             let mut validator = ValidateBoundVars::new(self.bound_vars());
@@ -1113,7 +1113,7 @@ impl<'tcx, T> Binder<'tcx, T> {
     /// would not be that useful.)
     pub fn no_bound_vars(self) -> Option<T>
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
     }
@@ -1143,7 +1143,7 @@ impl<'tcx, T> Binder<'tcx, Option<T>> {
 /// Represents the projection of an associated type. In explicit UFCS
 /// form this would be written `<T as Trait<..>>::N`.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct ProjectionTy<'tcx> {
     /// The parameters of the associated item.
     pub substs: SubstsRef<'tcx>,
@@ -1192,7 +1192,7 @@ impl<'tcx> ProjectionTy<'tcx> {
     }
 }
 
-#[derive(Copy, Clone, Debug, TypeFoldable)]
+#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
     pub yield_ty: Ty<'tcx>,
@@ -1208,7 +1208,7 @@ pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>;
 /// - `output`: is the return type.
 /// - `c_variadic`: indicates whether this is a C-variadic function.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct FnSig<'tcx> {
     pub inputs_and_output: &'tcx List<Ty<'tcx>>,
     pub c_variadic: bool,
@@ -1315,6 +1315,7 @@ pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
 impl<'tcx> Deref for Region<'tcx> {
     type Target = RegionKind<'tcx>;
 
+    #[inline]
     fn deref(&self) -> &RegionKind<'tcx> {
         &self.0.0
     }
@@ -1385,7 +1386,7 @@ impl From<BoundVar> for BoundTy {
 
 /// A `ProjectionPredicate` for an `ExistentialTraitRef`.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
@@ -1570,6 +1571,19 @@ impl<'tcx> Region<'tcx> {
             _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
         }
     }
+
+    /// True for free regions other than `'static`.
+    pub fn is_free(self) -> bool {
+        matches!(*self, ty::ReEarlyBound(_) | ty::ReFree(_))
+    }
+
+    /// True if `self` is a free region or static.
+    pub fn is_free_or_static(self) -> bool {
+        match *self {
+            ty::ReStatic => true,
+            _ => self.is_free(),
+        }
+    }
 }
 
 /// Type utilities
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 1417c8a511c..3a524d7b0f3 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -2,10 +2,9 @@
 
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
-use crate::ty::fold::{
-    FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
-};
+use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
+use crate::ty::visit::{TypeVisitable, TypeVisitor};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
 use rustc_data_structures::intern::{Interned, WithStableHash};
@@ -205,7 +204,9 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
             GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
         }
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for GenericArg<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         match self.unpack() {
             GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
@@ -449,7 +450,9 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
             _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)),
         }
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for SubstsRef<'tcx> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -485,7 +488,9 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
             _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_type_list(v)),
         }
     }
+}
 
+impl<'tcx> TypeVisitable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
@@ -722,7 +727,7 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
 /// Stores the user-given substs to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct UserSubsts<'tcx> {
     /// The substitutions for the item as given by the user.
     pub substs: SubstsRef<'tcx>,
@@ -749,7 +754,7 @@ pub struct UserSubsts<'tcx> {
 /// the self type, giving `Foo<?A>`. Finally, we unify that with
 /// the self type here, which contains `?A` to be `&'static u32`
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, Lift)]
+#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct UserSelfTy<'tcx> {
     pub impl_def_id: DefId,
     pub self_ty: Ty<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index cb34b64660d..826c16dda4a 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -1,6 +1,6 @@
 use crate::traits::specialization_graph;
 use crate::ty::fast_reject::{self, SimplifiedType, TreatParams};
-use crate::ty::fold::TypeFoldable;
+use crate::ty::visit::TypeVisitable;
 use crate::ty::{Ident, Ty, TyCtxt};
 use hir::def_id::LOCAL_CRATE;
 use rustc_hir as hir;
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 38846031bad..52da6c3a8c0 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -6,6 +6,7 @@ use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitable,
 };
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
@@ -141,16 +142,16 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Creates a hash of the type `Ty` which will be the same no matter what crate
     /// context it's calculated within. This is used by the `type_id` intrinsic.
     pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
-        let mut hasher = StableHasher::new();
-        let mut hcx = self.create_stable_hashing_context();
-
         // We want the type_id be independent of the types free regions, so we
         // erase them. The erase_regions() call will also anonymize bound
         // regions, which is desirable too.
         let ty = self.erase_regions(ty);
 
-        hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher));
-        hasher.finish()
+        self.with_stable_hashing_context(|mut hcx| {
+            let mut hasher = StableHasher::new();
+            hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher));
+            hasher.finish()
+        })
     }
 
     pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
@@ -1041,6 +1042,7 @@ impl<'tcx> Ty<'tcx> {
         ty
     }
 
+    #[inline]
     pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
         self.0.outer_exclusive_binder
     }
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
new file mode 100644
index 00000000000..5365067209a
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -0,0 +1,745 @@
+//! A visiting traversal mechanism for complex data structures that contain type
+//! information.
+//!
+//! This is a read-only traversal of the data structure.
+//!
+//! This traversal has limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! visitation. These are the ones containing the most important type-related
+//! information, such as `Ty`, `Predicate`, `Region`, and `Const`.
+//!
+//! There are three groups of traits involved in each traversal.
+//! - `TypeVisitable`. This is implemented once for many types, including:
+//!   - Types of interest, for which the the methods delegate to the
+//!     visitor.
+//!   - All other types, including generic containers like `Vec` and `Option`.
+//!     It defines a "skeleton" of how they should be visited.
+//! - `TypeSuperVisitable`. This is implemented only for each type of interest,
+//!   and defines the visiting "skeleton" for these types.
+//! - `TypeVisitor`. This is implemented for each visitor. This defines how
+//!   types of interest are visited.
+//!
+//! This means each visit is a mixture of (a) generic visiting operations, and (b)
+//! custom visit operations that are specific to the visitor.
+//! - The `TypeVisitable` impls handle most of the traversal, and call into
+//!   `TypeVisitor` when they encounter a type of interest.
+//! - A `TypeVisitor` may call into another `TypeVisitable` impl, because some of
+//!   the types of interest are recursive and can contain other types of interest.
+//! - A `TypeVisitor` may also call into a `TypeSuperVisitable` impl, because each
+//!   visitor might provide custom handling only for some types of interest, or
+//!   only for some variants of each type of interest, and then use default
+//!   traversal for the remaining cases.
+//!
+//! For example, if you have `struct S(Ty, U)` where `S: TypeVisitable` and `U:
+//! TypeVisitable`, and an instance `s = S(ty, u)`, it would be visited like so:
+//! ```text
+//! s.visit_with(visitor) calls
+//! - ty.visit_with(visitor) calls
+//!   - visitor.visit_ty(ty) may call
+//!     - ty.super_visit_with(visitor)
+//! - u.visit_with(visitor)
+//! ```
+use crate::mir;
+use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
+use rustc_errors::ErrorGuaranteed;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sso::SsoHashSet;
+use std::fmt;
+use std::ops::ControlFlow;
+
+/// This trait is implemented for every type that can be visited,
+/// providing the skeleton of the traversal.
+///
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
+pub trait TypeVisitable<'tcx>: fmt::Debug + Clone {
+    /// The entry point for visiting. To visit a value `t` with a visitor `v`
+    /// call: `t.visit_with(v)`.
+    ///
+    /// For most types, this just traverses the value, calling `visit_with` on
+    /// each field/element.
+    ///
+    /// For types of interest (such as `Ty`), the implementation of this method
+    /// that calls a visitor method specifically for that type (such as
+    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+    /// `TypeVisitor`.
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+
+    /// Returns `true` if `self` has any late-bound regions that are either
+    /// bound by `binder` or bound by some binder outside of `binder`.
+    /// If `binder` is `ty::INNERMOST`, this indicates whether
+    /// there are any late-bound regions that appear free.
+    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
+    }
+
+    /// Returns `true` if this `self` has any regions that escape `binder` (and
+    /// hence are not bound by it).
+    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.has_vars_bound_at_or_above(binder.shifted_in(1))
+    }
+
+    fn has_escaping_bound_vars(&self) -> bool {
+        self.has_vars_bound_at_or_above(ty::INNERMOST)
+    }
+
+    #[instrument(level = "trace")]
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
+    }
+    fn has_projections(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PROJECTION)
+    }
+    fn has_opaque_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
+    }
+    fn references_error(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_ERROR)
+    }
+    fn error_reported(&self) -> Option<ErrorGuaranteed> {
+        if self.references_error() {
+            Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+        } else {
+            None
+        }
+    }
+    fn has_param_types_or_consts(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
+    }
+    fn has_infer_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_INFER)
+    }
+    fn has_infer_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INFER)
+    }
+    fn has_infer_types_or_consts(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
+    }
+    fn needs_infer(&self) -> bool {
+        self.has_type_flags(TypeFlags::NEEDS_INFER)
+    }
+    fn has_placeholders(&self) -> bool {
+        self.has_type_flags(
+            TypeFlags::HAS_RE_PLACEHOLDER
+                | TypeFlags::HAS_TY_PLACEHOLDER
+                | TypeFlags::HAS_CT_PLACEHOLDER,
+        )
+    }
+    fn needs_subst(&self) -> bool {
+        self.has_type_flags(TypeFlags::NEEDS_SUBST)
+    }
+    /// "Free" regions in this context means that it has any region
+    /// that is not (a) erased or (b) late-bound.
+    fn has_free_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+    }
+
+    fn has_erased_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
+    }
+
+    /// True if there are any un-erased free regions.
+    fn has_erasable_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+    }
+
+    /// Indicates whether this value references only 'global'
+    /// generic parameters that are the same regardless of what fn we are
+    /// in. This is used for caching.
+    fn is_global(&self) -> bool {
+        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+    }
+
+    /// True if there are any late-bound regions
+    fn has_late_bound_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
+    }
+
+    /// Indicates whether this value still has parameters/placeholders/inference variables
+    /// which could be replaced later, in a way that would change the results of `impl`
+    /// specialization.
+    fn still_further_specializable(&self) -> bool {
+        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
+    }
+}
+
+pub trait TypeSuperVisitable<'tcx>: TypeVisitable<'tcx> {
+    /// Provides a default visit for a type of interest. This should only be
+    /// called within `TypeVisitor` methods, when a non-custom traversal is
+    /// desired for the value of the type of interest passed to that method.
+    /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
+    /// `ty.super_visit_with(self)`, but any other visiting should be done
+    /// with `xyz.visit_with(self)`.
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+}
+
+/// This trait is implemented for every visiting traversal. There is a visit
+/// method defined for every type of interest. Each such method has a default
+/// that recurses into the type's fields in a non-custom fashion.
+pub trait TypeVisitor<'tcx>: Sized {
+    type BreakTy = !;
+
+    fn visit_binder<T: TypeVisitable<'tcx>>(
+        &mut self,
+        t: &Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        t.super_visit_with(self)
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        r.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        c.super_visit_with(self)
+    }
+
+    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+        uv.super_visit_with(self)
+    }
+
+    fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+        p.super_visit_with(self)
+    }
+
+    fn visit_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> ControlFlow<Self::BreakTy> {
+        c.super_visit_with(self)
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Region folder
+
+impl<'tcx> TyCtxt<'tcx> {
+    /// Invoke `callback` on every region appearing free in `value`.
+    pub fn for_each_free_region(
+        self,
+        value: &impl TypeVisitable<'tcx>,
+        mut callback: impl FnMut(ty::Region<'tcx>),
+    ) {
+        self.any_free_region_meets(value, |r| {
+            callback(r);
+            false
+        });
+    }
+
+    /// Returns `true` if `callback` returns true for every region appearing free in `value`.
+    pub fn all_free_regions_meet(
+        self,
+        value: &impl TypeVisitable<'tcx>,
+        mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
+    ) -> bool {
+        !self.any_free_region_meets(value, |r| !callback(r))
+    }
+
+    /// Returns `true` if `callback` returns true for some region appearing free in `value`.
+    pub fn any_free_region_meets(
+        self,
+        value: &impl TypeVisitable<'tcx>,
+        callback: impl FnMut(ty::Region<'tcx>) -> bool,
+    ) -> bool {
+        struct RegionVisitor<F> {
+            /// The index of a binder *just outside* the things we have
+            /// traversed. If we encounter a bound region bound by this
+            /// binder or one outer to it, it appears free. Example:
+            ///
+            /// ```ignore (illustrative)
+            ///       for<'a> fn(for<'b> fn(), T)
+            /// // ^          ^          ^     ^
+            /// // |          |          |     | here, would be shifted in 1
+            /// // |          |          | here, would be shifted in 2
+            /// // |          | here, would be `INNERMOST` shifted in by 1
+            /// // | here, initially, binder would be `INNERMOST`
+            /// ```
+            ///
+            /// You see that, initially, *any* bound value is free,
+            /// because we've not traversed any binders. As we pass
+            /// through a binder, we shift the `outer_index` by 1 to
+            /// account for the new binder that encloses us.
+            outer_index: ty::DebruijnIndex,
+            callback: F,
+        }
+
+        impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
+        where
+            F: FnMut(ty::Region<'tcx>) -> bool,
+        {
+            type BreakTy = ();
+
+            fn visit_binder<T: TypeVisitable<'tcx>>(
+                &mut self,
+                t: &Binder<'tcx, T>,
+            ) -> ControlFlow<Self::BreakTy> {
+                self.outer_index.shift_in(1);
+                let result = t.super_visit_with(self);
+                self.outer_index.shift_out(1);
+                result
+            }
+
+            fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+                match *r {
+                    ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
+                        ControlFlow::CONTINUE
+                    }
+                    _ => {
+                        if (self.callback)(r) {
+                            ControlFlow::BREAK
+                        } else {
+                            ControlFlow::CONTINUE
+                        }
+                    }
+                }
+            }
+
+            fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+                // We're only interested in types involving regions
+                if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
+                    ty.super_visit_with(self)
+                } else {
+                    ControlFlow::CONTINUE
+                }
+            }
+        }
+
+        value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
+    }
+
+    /// Returns a set of all late-bound regions that are constrained
+    /// by `value`, meaning that if we instantiate those LBR with
+    /// variables and equate `value` with something else, those
+    /// variables will also be equated.
+    pub fn collect_constrained_late_bound_regions<T>(
+        self,
+        value: &Binder<'tcx, T>,
+    ) -> FxHashSet<ty::BoundRegionKind>
+    where
+        T: TypeVisitable<'tcx>,
+    {
+        self.collect_late_bound_regions(value, true)
+    }
+
+    /// Returns a set of all late-bound regions that appear in `value` anywhere.
+    pub fn collect_referenced_late_bound_regions<T>(
+        self,
+        value: &Binder<'tcx, T>,
+    ) -> FxHashSet<ty::BoundRegionKind>
+    where
+        T: TypeVisitable<'tcx>,
+    {
+        self.collect_late_bound_regions(value, false)
+    }
+
+    fn collect_late_bound_regions<T>(
+        self,
+        value: &Binder<'tcx, T>,
+        just_constraint: bool,
+    ) -> FxHashSet<ty::BoundRegionKind>
+    where
+        T: TypeVisitable<'tcx>,
+    {
+        let mut collector = LateBoundRegionsCollector::new(just_constraint);
+        let result = value.as_ref().skip_binder().visit_with(&mut collector);
+        assert!(result.is_continue()); // should never have stopped early
+        collector.regions
+    }
+}
+
+pub struct ValidateBoundVars<'tcx> {
+    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+    binder_index: ty::DebruijnIndex,
+    // We may encounter the same variable at different levels of binding, so
+    // this can't just be `Ty`
+    visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
+}
+
+impl<'tcx> ValidateBoundVars<'tcx> {
+    pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
+        ValidateBoundVars {
+            bound_vars,
+            binder_index: ty::INNERMOST,
+            visited: SsoHashSet::default(),
+        }
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
+    type BreakTy = ();
+
+    fn visit_binder<T: TypeVisitable<'tcx>>(
+        &mut self,
+        t: &Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.binder_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.binder_index.shift_out(1);
+        result
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if t.outer_exclusive_binder() < self.binder_index
+            || !self.visited.insert((self.binder_index, t))
+        {
+            return ControlFlow::BREAK;
+        }
+        match *t.kind() {
+            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
+                if self.bound_vars.len() <= bound_ty.var.as_usize() {
+                    bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
+                }
+                let list_var = self.bound_vars[bound_ty.var.as_usize()];
+                match list_var {
+                    ty::BoundVariableKind::Ty(kind) => {
+                        if kind != bound_ty.kind {
+                            bug!(
+                                "Mismatched type kinds: {:?} doesn't var in list {:?}",
+                                bound_ty.kind,
+                                list_var
+                            );
+                        }
+                    }
+                    _ => {
+                        bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
+                    }
+                }
+            }
+
+            _ => (),
+        };
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match *r {
+            ty::ReLateBound(index, br) if index == self.binder_index => {
+                if self.bound_vars.len() <= br.var.as_usize() {
+                    bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
+                }
+                let list_var = self.bound_vars[br.var.as_usize()];
+                match list_var {
+                    ty::BoundVariableKind::Region(kind) => {
+                        if kind != br.kind {
+                            bug!(
+                                "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
+                                br.kind,
+                                list_var,
+                                self.bound_vars
+                            );
+                        }
+                    }
+                    _ => bug!(
+                        "Mismatched bound variable kinds! Expected region, found {:?}",
+                        list_var
+                    ),
+                }
+            }
+
+            _ => (),
+        };
+
+        r.super_visit_with(self)
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundEscapingVars;
+
+/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
+/// bound region or a bound type.
+///
+/// So, for example, consider a type like the following, which has two binders:
+///
+///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
+///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
+///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
+///
+/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
+/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
+/// fn type*, that type has an escaping region: `'a`.
+///
+/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
+/// we already use the term "free var". It refers to the regions or types that we use to represent
+/// bound regions or type params on a fn definition while we are type checking its body.
+///
+/// To clarify, conceptually there is no particular difference between
+/// an "escaping" var and a "free" var. However, there is a big
+/// difference in practice. Basically, when "entering" a binding
+/// level, one is generally required to do some sort of processing to
+/// a bound var, such as replacing it with a fresh/placeholder
+/// var, or making an entry in the environment to represent the
+/// scope to which it is attached, etc. An escaping var represents
+/// a bound var for which this processing has not yet been done.
+struct HasEscapingVarsVisitor {
+    /// Anything bound by `outer_index` or "above" is escaping.
+    outer_index: ty::DebruijnIndex,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
+    type BreakTy = FoundEscapingVars;
+
+    fn visit_binder<T: TypeVisitable<'tcx>>(
+        &mut self,
+        t: &Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.outer_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.outer_index.shift_out(1);
+        result
+    }
+
+    #[inline]
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // If the outer-exclusive-binder is *strictly greater* than
+        // `outer_index`, that means that `t` contains some content
+        // bound at `outer_index` or above (because
+        // `outer_exclusive_binder` is always 1 higher than the
+        // content in `t`). Therefore, `t` has some escaping vars.
+        if t.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    #[inline]
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // If the region is bound by `outer_index` or anything outside
+        // of outer index, then it escapes the binders we have
+        // visited.
+        if r.bound_at_or_above_binder(self.outer_index) {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // we don't have a `visit_infer_const` callback, so we have to
+        // hook in here to catch this case (annoying...), but
+        // otherwise we do want to remember to visit the rest of the
+        // const, as it has types/regions embedded in a lot of other
+        // places.
+        match ct.kind() {
+            ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
+                ControlFlow::Break(FoundEscapingVars)
+            }
+            _ => ct.super_visit_with(self),
+        }
+    }
+
+    #[inline]
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if predicate.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundFlags;
+
+// FIXME: Optimize for checking for infer flags
+struct HasTypeFlagsVisitor {
+    flags: ty::TypeFlags,
+}
+
+impl std::fmt::Debug for HasTypeFlagsVisitor {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.flags.fmt(fmt)
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
+    type BreakTy = FoundFlags;
+
+    #[inline]
+    #[instrument(skip(self), level = "trace")]
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let flags = t.flags();
+        trace!(t.flags=?t.flags());
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    #[inline]
+    #[instrument(skip(self), level = "trace")]
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let flags = r.type_flags();
+        trace!(r.flags=?flags);
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    #[inline]
+    #[instrument(level = "trace")]
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let flags = FlagComputation::for_const(c);
+        trace!(r.flags=?flags);
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    #[inline]
+    #[instrument(level = "trace")]
+    fn visit_unevaluated(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+        let flags = FlagComputation::for_unevaluated_const(uv);
+        trace!(r.flags=?flags);
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+
+    #[inline]
+    #[instrument(level = "trace")]
+    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+        debug!(
+            "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+            predicate,
+            predicate.flags(),
+            self.flags
+        );
+        if predicate.flags().intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::CONTINUE
+        }
+    }
+}
+
+/// Collects all the late-bound regions at the innermost binding level
+/// into a hash set.
+struct LateBoundRegionsCollector {
+    current_index: ty::DebruijnIndex,
+    regions: FxHashSet<ty::BoundRegionKind>,
+
+    /// `true` if we only want regions that are known to be
+    /// "constrained" when you equate this type with another type. In
+    /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating
+    /// them constraints `'a == 'b`. But if you have `<&'a u32 as
+    /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
+    /// types may mean that `'a` and `'b` don't appear in the results,
+    /// so they are not considered *constrained*.
+    just_constrained: bool,
+}
+
+impl LateBoundRegionsCollector {
+    fn new(just_constrained: bool) -> Self {
+        LateBoundRegionsCollector {
+            current_index: ty::INNERMOST,
+            regions: Default::default(),
+            just_constrained,
+        }
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
+    fn visit_binder<T: TypeVisitable<'tcx>>(
+        &mut self,
+        t: &Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.current_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.current_index.shift_out(1);
+        result
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // if we are only looking for "constrained" region, we have to
+        // ignore the inputs to a projection, as they may not appear
+        // in the normalized form
+        if self.just_constrained {
+            if let ty::Projection(..) = t.kind() {
+                return ControlFlow::CONTINUE;
+            }
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        // if we are only looking for "constrained" region, we have to
+        // ignore the inputs of an unevaluated const, as they may not appear
+        // in the normalized form
+        if self.just_constrained {
+            if let ty::ConstKind::Unevaluated(..) = c.kind() {
+                return ControlFlow::CONTINUE;
+            }
+        }
+
+        c.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::ReLateBound(debruijn, br) = *r {
+            if debruijn == self.current_index {
+                self.regions.insert(br.kind);
+            }
+        }
+        ControlFlow::CONTINUE
+    }
+}
+
+/// Finds the max universe present
+pub struct MaxUniverse {
+    max_universe: ty::UniverseIndex,
+}
+
+impl MaxUniverse {
+    pub fn new() -> Self {
+        MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
+    }
+
+    pub fn max_universe(self) -> ty::UniverseIndex {
+        self.max_universe
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::Placeholder(placeholder) = t.kind() {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        c.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+        if let ty::RePlaceholder(placeholder) = *r {
+            self.max_universe = ty::UniverseIndex::from_u32(
+                self.max_universe.as_u32().max(placeholder.universe.as_u32()),
+            );
+        }
+
+        ControlFlow::CONTINUE
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 3d6e50f0c06..648d10b9e42 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -49,11 +49,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         inferred_ty: ty,
                     })
                 });
-
                 let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
 
                 Constant { span, user_ty: user_ty, literal }
             }
+            ExprKind::ZstLiteral { user_ty } => {
+                let user_ty = user_ty.map(|user_ty| {
+                    this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
+                        span,
+                        user_ty,
+                        inferred_ty: ty,
+                    })
+                });
+                let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
+
+                Constant { span, user_ty: user_ty, literal }
+            }
             ExprKind::NamedConst { def_id, substs, user_ty } => {
                 let user_ty = user_ty.map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index e77f5931dd6..e88f9dc1f08 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -603,6 +603,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. }
             | ExprKind::StaticRef { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 8e87ecd27d2..15f2d17c4e0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,6 +1,7 @@
 //! See docs in `build/expr/mod.rs`.
 
 use rustc_index::vec::Idx;
+use rustc_middle::ty::util::IntTypeExt;
 
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
@@ -190,7 +191,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Cast { source } => {
                 let source = &this.thir[source];
-                let from_ty = CastTy::from_ty(source.ty);
+
+                // Casting an enum to an integer is equivalent to computing the discriminant and casting the
+                // discriminant. Previously every backend had to repeat the logic for this operation. Now we
+                // create all the steps directly in MIR with operations all backends need to support anyway.
+                let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() {
+                    let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
+                    let place = unpack!(block = this.as_place(block, source));
+                    let discr = this.temp(discr_ty, source.span);
+                    this.cfg.push_assign(
+                        block,
+                        source_info,
+                        discr,
+                        Rvalue::Discriminant(place),
+                    );
+
+                    (Operand::Move(discr), discr_ty)
+                } else {
+                    let ty = source.ty;
+                    let source = unpack!(
+                        block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
+                    );
+                    (source, ty)
+                };
+                let from_ty = CastTy::from_ty(ty);
                 let cast_ty = CastTy::from_ty(expr.ty);
                 let cast_kind = match (from_ty, cast_ty) {
                     (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
@@ -201,9 +225,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     }
                     (_, _) => CastKind::Misc,
                 };
-                let source = unpack!(
-                    block = this.as_operand(block, scope, source, None, NeedsTemporary::No)
-                );
                 block.and(Rvalue::Cast(cast_kind, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
@@ -394,6 +415,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. }
             | ExprKind::StaticRef { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index b1a70643934..a4386319dc1 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -72,6 +72,7 @@ impl Category {
             ExprKind::ConstBlock { .. }
             | ExprKind::Literal { .. }
             | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::StaticRef { .. }
             | ExprKind::NamedConst { .. } => Some(Category::Constant),
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index cffb67ef013..017d43d10a9 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -559,6 +559,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::StaticRef { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index cdacf3ad892..e6d42af9817 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -20,7 +20,7 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_span::Symbol;
@@ -997,7 +997,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 continue;
             };
             let pat = match tcx.hir().get(arg.pat.hir_id) {
-                Node::Pat(pat) | Node::Binding(pat) => pat,
+                Node::Pat(pat) => pat,
                 node => bug!("pattern became {:?}", node),
             };
             let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 94b2722dca8..8585199faaf 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -307,6 +307,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
             | ExprKind::Literal { .. }
             | ExprKind::NamedConst { .. }
             | ExprKind::NonHirLiteral { .. }
+            | ExprKind::ZstLiteral { .. }
             | ExprKind::ConstParam { .. }
             | ExprKind::ConstBlock { .. }
             | ExprKind::Deref { .. }
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index 5470cc1262e..d21a8c4f9b9 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
 use rustc_hir::intravisit::FnKind;
-use rustc_middle::mir::{BasicBlock, Body, Operand, TerminatorKind};
+use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
 use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
@@ -30,7 +30,9 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         };
 
         let mut vis = Search { tcx, body, reachable_recursive_calls: vec![], trait_substs };
-        if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
+        if let Some(NonRecursive) =
+            TriColorDepthFirstSearch::new(&body.basic_blocks).run_from_start(&mut vis)
+        {
             return;
         }
         if vis.reachable_recursive_calls.is_empty() {
@@ -101,7 +103,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
     }
 }
 
-impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
+impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {
     type BreakVal = NonRecursive;
 
     fn node_examined(
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 08b66d0abc7..4eb3607e9cc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -32,13 +32,14 @@ impl<'tcx> Cx<'tcx> {
         exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
     }
 
+    #[instrument(level = "trace", skip(self, hir_expr))]
     pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         let temp_lifetime =
             self.rvalue_scopes.temporary_scope(self.region_scope_tree, hir_expr.hir_id.local_id);
         let expr_scope =
             region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
 
-        debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span);
+        trace!(?hir_expr.hir_id, ?hir_expr.span);
 
         let mut expr = self.make_mirror_unadjusted(hir_expr);
 
@@ -49,7 +50,7 @@ impl<'tcx> Cx<'tcx> {
 
         // Now apply adjustments, if any.
         for adjustment in self.typeck_results.expr_adjustments(hir_expr) {
-            debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
+            trace!(?expr, ?adjustment);
             let span = expr.span;
             expr =
                 self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span));
@@ -798,7 +799,7 @@ impl<'tcx> Cx<'tcx> {
             }
         };
         let ty = self.tcx().mk_fn_def(def_id, substs);
-        Expr { temp_lifetime, ty, span, kind: ExprKind::zero_sized_literal(user_ty) }
+        Expr { temp_lifetime, ty, span, kind: ExprKind::ZstLiteral { user_ty } }
     }
 
     fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
@@ -827,7 +828,7 @@ impl<'tcx> Cx<'tcx> {
             | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
             | Res::SelfCtor(_) => {
                 let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
-                ExprKind::zero_sized_literal(user_ty)
+                ExprKind::ZstLiteral { user_ty }
             }
 
             Res::Def(DefKind::ConstParam, def_id) => {
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 62f6a43d1f2..35a0afd6813 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -80,7 +80,7 @@ impl<'tcx> Cx<'tcx> {
     #[tracing::instrument(level = "debug", skip(self))]
     pub(crate) fn pattern_from_hir(&mut self, p: &hir::Pat<'_>) -> Pat<'tcx> {
         let p = match self.tcx.hir().get(p.hir_id) {
-            Node::Pat(p) | Node::Binding(p) => p,
+            Node::Pat(p) => p,
             node => bug!("pattern became {:?}", node),
         };
         pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 61ac3d14e50..75fd156ebfd 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -432,7 +432,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
                 "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
                  an `enum` with only one variant",
             );
-            if self.tcx.sess.source_map().span_to_snippet(span).is_ok() {
+            if self.tcx.sess.source_map().is_span_accessible(span) {
                 let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
                 let start_span = span.shrink_to_lo();
                 let end_span = semi_span.shrink_to_lo();
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 845be2ab264..e32e0b11ba4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -120,32 +120,37 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
     }
 
     fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
-        traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
-            with_no_trimmed_paths!(match non_sm_ty.kind {
-                traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
-                traits::NonStructuralMatchTyKind::Dynamic => {
-                    "trait objects cannot be used in patterns".to_string()
-                }
-                traits::NonStructuralMatchTyKind::Opaque => {
-                    "opaque types cannot be used in patterns".to_string()
-                }
-                traits::NonStructuralMatchTyKind::Closure => {
-                    "closures cannot be used in patterns".to_string()
-                }
-                traits::NonStructuralMatchTyKind::Generator => {
-                    "generators cannot be used in patterns".to_string()
-                }
-                traits::NonStructuralMatchTyKind::Param => {
-                    bug!("use of a constant whose type is a parameter inside a pattern")
-                }
-                traits::NonStructuralMatchTyKind::Projection => {
-                    bug!("use of a constant whose type is a projection inside a pattern")
-                }
-                traits::NonStructuralMatchTyKind::Foreign => {
-                    bug!("use of a value of a foreign type inside a pattern")
-                }
-            })
-        })
+        traits::search_for_structural_match_violation(self.span, self.tcx(), ty, true).map(
+            |non_sm_ty| {
+                with_no_trimmed_paths!(match non_sm_ty.kind {
+                    traits::NonStructuralMatchTyKind::Adt(adt) => self.adt_derive_msg(adt),
+                    traits::NonStructuralMatchTyKind::Dynamic => {
+                        "trait objects cannot be used in patterns".to_string()
+                    }
+                    traits::NonStructuralMatchTyKind::Opaque => {
+                        "opaque types cannot be used in patterns".to_string()
+                    }
+                    traits::NonStructuralMatchTyKind::Closure => {
+                        "closures cannot be used in patterns".to_string()
+                    }
+                    traits::NonStructuralMatchTyKind::Generator => {
+                        "generators cannot be used in patterns".to_string()
+                    }
+                    traits::NonStructuralMatchTyKind::Float => {
+                        "floating-point numbers cannot be used in patterns".to_string()
+                    }
+                    traits::NonStructuralMatchTyKind::Param => {
+                        bug!("use of a constant whose type is a parameter inside a pattern")
+                    }
+                    traits::NonStructuralMatchTyKind::Projection => {
+                        bug!("use of a constant whose type is a projection inside a pattern")
+                    }
+                    traits::NonStructuralMatchTyKind::Foreign => {
+                        bug!("use of a value of a foreign type inside a pattern")
+                    }
+                })
+            },
+        )
     }
 
     fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
@@ -550,7 +555,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
                         id,
                         span,
                         |lint| {
-                            lint.build(&msg).emit();
+                            lint.build(msg).emit();
                         },
                     );
                 }
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 05a4d7bbf3e..5c77f3ea395 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -228,7 +228,7 @@ impl Direction for Backward {
     ) where
         A: Analysis<'tcx>,
     {
-        for pred in body.predecessors()[bb].iter().copied() {
+        for pred in body.basic_blocks.predecessors()[bb].iter().copied() {
             match body[pred].terminator().kind {
                 // Apply terminator-specific edge effects.
                 //
@@ -316,7 +316,7 @@ where
     fn apply(&mut self, mut apply_edge_effect: impl FnMut(&mut D, SwitchIntTarget)) {
         assert!(!self.effects_applied);
 
-        let values = &self.body.switch_sources()[&(self.bb, self.pred)];
+        let values = &self.body.basic_blocks.switch_sources()[&(self.bb, self.pred)];
         let targets = values.iter().map(|&value| SwitchIntTarget { value, target: self.bb });
 
         let mut tmp = None;
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 20e14a77c1e..180376d648a 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -101,7 +101,7 @@ where
         // transfer function for each block exactly once (assuming that we process blocks in RPO).
         //
         // In this case, there's no need to compute the block transfer functions ahead of time.
-        if !body.is_cfg_cyclic() {
+        if !body.basic_blocks.is_cfg_cyclic() {
             return Self::new(tcx, body, analysis, None);
         }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 9a462f6e1a4..d6b89eb8227 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -199,14 +199,16 @@ impl<T: JoinSemiLattice> MeetSemiLattice for Dual<T> {
 }
 
 /// Extends a type `T` with top and bottom elements to make it a partially ordered set in which no
-/// value of `T` is comparable with any other. A flat set has the following [Hasse diagram]:
+/// value of `T` is comparable with any other.
+///
+/// A flat set has the following [Hasse diagram]:
 ///
 /// ```text
-///         top
-///       / /  \ \
+///          top
+///  / ... / /  \ \ ... \
 /// all possible values of `T`
-///       \ \  / /
-///        bottom
+///  \ ... \ \  / / ... /
+///         bottom
 /// ```
 ///
 /// [Hasse diagram]: https://en.wikipedia.org/wiki/Hasse_diagram
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 67c16e6c084..f9fd6c9c56b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -1,7 +1,7 @@
 //! A framework that can express both [gen-kill] and generic dataflow problems.
 //!
-//! To actually use this framework, you must implement either the `Analysis` or the
-//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill
+//! To use this framework, implement either the [`Analysis`] or the
+//! [`GenKillAnalysis`] trait. If your transfer function can be expressed with only gen/kill
 //! operations, prefer `GenKillAnalysis` since it will run faster while iterating to fixpoint. The
 //! `impls` module contains several examples of gen/kill dataflow analyses.
 //!
@@ -96,7 +96,7 @@ impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> {
     }
 }
 
-/// Define the domain of a dataflow problem.
+/// Defines the domain of a dataflow problem.
 ///
 /// This trait specifies the lattice on which this analysis operates (the domain) as well as its
 /// initial value at the entry point of each basic block.
@@ -113,12 +113,12 @@ pub trait AnalysisDomain<'tcx> {
     /// suitable as part of a filename.
     const NAME: &'static str;
 
-    /// The initial value of the dataflow state upon entry to each basic block.
+    /// Returns the initial value of the dataflow state upon entry to each basic block.
     fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain;
 
     /// Mutates the initial value of the dataflow state upon entry to the `START_BLOCK`.
     ///
-    /// For backward analyses, initial state besides the bottom value is not yet supported. Trying
+    /// For backward analyses, initial state (besides the bottom value) is not yet supported. Trying
     /// to mutate the initial state will result in a panic.
     //
     // FIXME: For backward dataflow analyses, the initial state should be applied to every basic
@@ -155,9 +155,9 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     /// Updates the current dataflow state with an effect that occurs immediately *before* the
     /// given statement.
     ///
-    /// This method is useful if the consumer of the results of this analysis needs only to observe
+    /// This method is useful if the consumer of the results of this analysis only needs to observe
     /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
-    /// analyses should not implement this without implementing `apply_statement_effect`.
+    /// analyses should not implement this without also implementing `apply_statement_effect`.
     fn apply_before_statement_effect(
         &self,
         _state: &mut Self::Domain,
@@ -184,7 +184,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
     ///
     /// This method is useful if the consumer of the results of this analysis needs only to observe
     /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
-    /// analyses should not implement this without implementing `apply_terminator_effect`.
+    /// analyses should not implement this without also implementing `apply_terminator_effect`.
     fn apply_before_terminator_effect(
         &self,
         _state: &mut Self::Domain,
diff --git a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
index 584ab9718ed..83ce4c44b71 100644
--- a/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/init_locals.rs
@@ -81,7 +81,7 @@ where
     // deinitialized, although clearly it is only partially deinitialized. This analysis is not
     // actually used anywhere at the moment, so this is not critical, but this does need to be fixed
     // before it starts being used again.
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, NonUseContext};
         match context {
             // These are handled specially in `call_return_effect` and `yield_resume_effect`.
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 35febb5d330..e64136928cc 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -111,7 +111,7 @@ where
         }
     }
 
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         // Because we do not call `super_place` above, `visit_local` is only called for locals that
         // do not appear as part of  a `Place` in the MIR. This handles cases like the implicit use
         // of the return place in a `Return` terminator or the index in an `Index` projection.
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 33d29418147..f6b5af90a85 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -153,7 +153,7 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
         _: &mir::Statement<'tcx>,
         loc: Location,
     ) {
-        // If we move from a place then only stops needing storage *after*
+        // If we move from a place then it only stops needing storage *after*
         // that statement.
         self.check_for_move(trans, loc);
     }
@@ -288,12 +288,12 @@ impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
 where
     T: GenKill<Local>,
 {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, loc: Location) {
         if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
             let mut borrowed_locals = self.borrowed_locals.borrow_mut();
             borrowed_locals.seek_before_primary_effect(loc);
-            if !borrowed_locals.contains(*local) {
-                self.trans.kill(*local);
+            if !borrowed_locals.contains(local) {
+                self.trans.kill(local);
             }
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/storage.rs b/compiler/rustc_mir_dataflow/src/storage.rs
index 4a354c4c65b..566c9d2d505 100644
--- a/compiler/rustc_mir_dataflow/src/storage.rs
+++ b/compiler/rustc_mir_dataflow/src/storage.rs
@@ -7,7 +7,7 @@ use rustc_middle::mir::{self, Local};
 //
 // FIXME: Currently, we need to traverse the entire MIR to compute this. We should instead store it
 // as a field in the `LocalDecl` for each `Local`.
-pub fn always_live_locals(body: &mir::Body<'_>) -> BitSet<Local> {
+pub fn always_storage_live_locals(body: &mir::Body<'_>) -> BitSet<Local> {
     let mut always_live_locals = BitSet::new_filled(body.local_decls.len());
 
     for block in body.basic_blocks() {
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index 11980382ffd..2c8389e532d 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,6 +1,5 @@
 use crate::MirPass;
 use rustc_ast::InlineAsmOptions;
-use rustc_hir::def::DefKind;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
@@ -31,11 +30,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
 
         // We don't simplify the MIR of constants at this time because that
         // namely results in a cyclic query when we call `tcx.type_of` below.
-        let is_function = match kind {
-            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
-            _ => tcx.is_closure(def_id),
-        };
-        if !is_function {
+        if !kind.is_fn_like() {
             return;
         }
 
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index 10d52271734..f12c8560c0e 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -39,7 +39,7 @@ impl<'tcx> MirPass<'tcx> for AddCallGuards {
 impl AddCallGuards {
     pub fn add_call_guards(&self, body: &mut Body<'_>) {
         let mut pred_count: IndexVec<_, _> =
-            body.predecessors().iter().map(|ps| ps.len()).collect();
+            body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect();
         pred_count[START_BLOCK] += 1;
 
         // We need a place to store the new blocks generated
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 0f87e638d26..5d15f03491d 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -91,7 +91,8 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
         super::add_call_guards::AllCallEdges.run_pass(tcx, body);
 
         let (span, arg_count) = (body.span, body.arg_count);
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+        let basic_blocks = body.basic_blocks.as_mut();
+        let local_decls = &body.local_decls;
         let needs_retag = |place: &Place<'tcx>| {
             // FIXME: Instead of giving up for unstable places, we should introduce
             // a temporary and retag on that.
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 097a6186cd5..8838b14c53a 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -1,5 +1,4 @@
-use rustc_errors::DiagnosticBuilder;
-use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 4bf66cd4c9f..2eb38941f1a 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -39,13 +39,11 @@ fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
             "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
              type or const parameters (error E0133)"
-                .to_string()
         } else {
             "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
              does not derive Copy (error E0133)"
-                .to_string()
         };
-        lint.build(&message).emit();
+        lint.build(message).emit();
     });
 }
 
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index 8944ebed9a7..48aea61b191 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -88,12 +88,12 @@ fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Consta
 }
 
 impl Visitor<'_> for LocalUseVisitor {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) {
         if context.is_mutating_use() {
-            self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1);
+            self.local_mutating_uses[local] = self.local_mutating_uses[local].saturating_add(1);
 
             if context.is_place_assignment() {
-                self.local_assignment_locations[*local] = Some(location);
+                self.local_assignment_locations[local] = Some(location);
             }
         }
     }
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 412a5b4fc91..fb5423dd157 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -19,19 +19,18 @@ use rustc_middle::mir::{
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeFoldable,
+    self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_target::spec::abi::Abi;
+use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
+use rustc_target::spec::abi::Abi as CallAbi;
 use rustc_trait_selection::traits;
 
 use crate::MirPass;
 use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
-    ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
-    Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
-    StackPopUnwind,
+    ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemoryKind, OpTy, PlaceTy,
+    Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
 };
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -60,11 +59,8 @@ macro_rules! throw_machine_stop_str {
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
-    fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
-        // FIXME(#70073): Unlike the other passes in "optimizations", this one emits errors, so it
-        // runs even when MIR optimizations are disabled. We should separate the lint out from the
-        // transform and move the lint as early in the pipeline as possible.
-        true
+    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+        sess.mir_opt_level() >= 1
     }
 
     #[instrument(skip(self, tcx), level = "debug")]
@@ -199,7 +195,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
-        _abi: Abi,
+        _abi: CallAbi,
         _args: &[OpTy<'tcx>],
         _destination: &PlaceTy<'tcx>,
         _target: Option<BasicBlock>,
@@ -237,15 +233,19 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn access_local(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+    fn access_local<'a>(
+        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
         local: Local,
-    ) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> {
         let l = &frame.locals[local];
 
-        if l.value == LocalValue::Unallocated {
-            throw_machine_stop_str!("tried to access an unallocated local")
+        if matches!(
+            l.value,
+            LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
+        ) {
+            // For us "uninit" means "we don't know its value, might be initiailized or not".
+            // So stop here.
+            throw_machine_stop_str!("tried to access alocal with unknown value ")
         }
 
         l.access()
@@ -255,8 +255,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: Local,
-    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
-    {
+    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> {
         if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
             throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
         }
@@ -391,7 +390,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
-            .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
+            // I don't know how return types can seem to be unsized but this happens in the
+            // `type/type-unsatisfiable.rs` test.
+            .filter(|ret_layout| {
+                !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
+            })
             .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
 
         let ret = ecx
@@ -436,8 +439,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     /// Remove `local` from the pool of `Locals`. Allows writing to them,
     /// but not reading from them anymore.
     fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
-        ecx.frame_mut().locals[local] =
-            LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) };
+        ecx.frame_mut().locals[local] = LocalState {
+            value: LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)),
+            layout: Cell::new(None),
+        };
     }
 
     fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
@@ -654,6 +659,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     (Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
                 };
 
+                if !matches!(const_arg.layout.abi, abi::Abi::Scalar(..)) {
+                    // We cannot handle Scalar Pair stuff.
+                    return this.ecx.eval_rvalue_into_place(rvalue, place);
+                }
+
                 let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
                 let dest = this.ecx.eval_place(place)?;
 
@@ -786,12 +796,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
     /// Returns `true` if and only if this `op` should be const-propagated into.
     fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
-        let mir_opt_level = self.tcx.sess.mir_opt_level();
-
-        if mir_opt_level == 0 {
-            return false;
-        }
-
         if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) {
             return false;
         }
@@ -882,7 +886,7 @@ impl CanConstProp {
 }
 
 impl Visitor<'_> for CanConstProp {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
             // Projections are fine, because `&mut foo.x` will be caught by
@@ -1042,7 +1046,9 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
                     let frame = self.ecx.frame_mut();
                     frame.locals[local].value =
                         if let StatementKind::StorageLive(_) = statement.kind {
-                            LocalValue::Unallocated
+                            LocalValue::Live(interpret::Operand::Immediate(
+                                interpret::Immediate::Uninit,
+                            ))
                         } else {
                             LocalValue::Dead
                         };
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 15ad13009e5..09a5cb8280f 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -18,20 +18,21 @@ use rustc_middle::mir::{
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
+    self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt,
+    TypeVisitable,
 };
 use rustc_session::lint;
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_target::spec::abi::Abi;
+use rustc_target::spec::abi::Abi as CallAbi;
 use rustc_trait_selection::traits;
 
 use crate::MirLint;
 use rustc_const_eval::const_eval::ConstEvalErr;
 use rustc_const_eval::interpret::{
     self, compile_time_machine, AllocId, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult,
-    LocalState, LocalValue, MemPlace, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
-    Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
+    LocalState, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
+    StackPopCleanup, StackPopUnwind,
 };
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -190,7 +191,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     fn find_mir_or_eval_fn(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
-        _abi: Abi,
+        _abi: CallAbi,
         _args: &[OpTy<'tcx>],
         _destination: &PlaceTy<'tcx>,
         _target: Option<BasicBlock>,
@@ -228,15 +229,19 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn access_local(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
+    fn access_local<'a>(
+        frame: &'a Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
         local: Local,
-    ) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
+    ) -> InterpResult<'tcx, &'a interpret::Operand<Self::PointerTag>> {
         let l = &frame.locals[local];
 
-        if l.value == LocalValue::Unallocated {
-            throw_machine_stop_str!("tried to access an uninitialized local")
+        if matches!(
+            l.value,
+            LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit))
+        ) {
+            // For us "uninit" means "we don't know its value, might be initiailized or not".
+            // So stop here.
+            throw_machine_stop_str!("tried to access a local with unknown value")
         }
 
         l.access()
@@ -246,8 +251,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
         frame: usize,
         local: Local,
-    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
-    {
+    ) -> InterpResult<'tcx, &'a mut interpret::Operand<Self::PointerTag>> {
         if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
             throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
         }
@@ -383,7 +387,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
-            .filter(|ret_layout| ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT))
+            // I don't know how return types can seem to be unsized but this happens in the
+            // `type/type-unsatisfiable.rs` test.
+            .filter(|ret_layout| {
+                !ret_layout.is_unsized() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
+            })
             .unwrap_or_else(|| ecx.layout_of(tcx.types.unit).unwrap());
 
         let ret = ecx
@@ -429,8 +437,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     /// Remove `local` from the pool of `Locals`. Allows writing to them,
     /// but not reading from them anymore.
     fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
-        ecx.frame_mut().locals[local] =
-            LocalState { value: LocalValue::Unallocated, layout: Cell::new(None) };
+        ecx.frame_mut().locals[local] = LocalState {
+            value: LocalValue::Live(interpret::Operand::Immediate(interpret::Immediate::Uninit)),
+            layout: Cell::new(None),
+        };
     }
 
     fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
@@ -773,7 +783,7 @@ impl CanConstProp {
 }
 
 impl Visitor<'_> for CanConstProp {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
             // Projections are fine, because `&mut foo.x` will be caught by
@@ -914,7 +924,9 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
                     let frame = self.ecx.frame_mut();
                     frame.locals[local].value =
                         if let StatementKind::StorageLive(_) = statement.kind {
-                            LocalValue::Unallocated
+                            LocalValue::Live(interpret::Operand::Immediate(
+                                interpret::Immediate::Uninit,
+                            ))
                         } else {
                             LocalValue::Dead
                         };
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 510f1e64ed1..759ea7cd328 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -80,7 +80,7 @@ impl CoverageGraph {
         IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
         IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
     ) {
-        let num_basic_blocks = mir_body.num_nodes();
+        let num_basic_blocks = mir_body.basic_blocks.len();
         let mut bcbs = IndexVec::with_capacity(num_basic_blocks);
         let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks);
 
@@ -95,7 +95,7 @@ impl CoverageGraph {
         let mut basic_blocks = Vec::new();
         for (bb, data) in mir_cfg_without_unwind {
             if let Some(last) = basic_blocks.last() {
-                let predecessors = &mir_body.predecessors()[bb];
+                let predecessors = &mir_body.basic_blocks.predecessors()[bb];
                 if predecessors.len() > 1 || !predecessors.contains(last) {
                     // The `bb` has more than one _incoming_ edge, and should start its own
                     // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 782b620e28f..88ad5b7ef14 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -15,7 +15,6 @@ use spans::{CoverageSpan, CoverageSpans};
 use crate::MirPass;
 
 use rustc_data_structures::graph::WithNumNodes;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_index::vec::IndexVec;
 use rustc_middle::hir;
@@ -576,12 +575,6 @@ fn get_body_span<'tcx>(
 
 fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
     // FIXME(cjgillot) Stop hashing HIR manually here.
-    let mut hcx = tcx.create_no_span_stable_hashing_context();
-    let mut stable_hasher = StableHasher::new();
     let owner = hir_body.id().hir_id.owner;
-    let bodies = &tcx.hir_owner_nodes(owner).unwrap().bodies;
-    hcx.with_hir_bodies(false, owner, bodies, |hcx| {
-        hir_body.value.hash_stable(hcx, &mut stable_hasher)
-    });
-    stable_hasher.finish()
+    tcx.hir_owner_nodes(owner).unwrap().hash_including_bodies.to_smaller_hash()
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 82070b90325..423e78317aa 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -321,7 +321,8 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
     }
 
     fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
-        let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
+        let mut initial_spans =
+            Vec::<CoverageSpan>::with_capacity(self.mir_body.basic_blocks.len() * 2);
         for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
             initial_spans.extend(self.bcb_to_initial_coverage_spans(bcb, bcb_data));
         }
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 213bb6608e1..6380f03528a 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -222,6 +222,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
                         bb,
                         debug::term_type(&data.terminator().kind),
                         mir_body
+                            .basic_blocks
                             .successors(bb)
                             .map(|successor| { format!("    {:?} -> {:?};", bb, successor) })
                             .join("\n")
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 28f3790914b..9163672f570 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -66,7 +66,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
         return;
     }
 
-    let bbs = body.basic_blocks_mut();
+    let bbs = body.basic_blocks.as_mut_preserves_cfg();
     for Location { block, statement_index } in patch {
         bbs[block].statements[statement_index].make_nop();
     }
diff --git a/compiler/rustc_mir_transform/src/deaggregator.rs b/compiler/rustc_mir_transform/src/deaggregator.rs
index 616ba819982..b93fe5879f4 100644
--- a/compiler/rustc_mir_transform/src/deaggregator.rs
+++ b/compiler/rustc_mir_transform/src/deaggregator.rs
@@ -11,8 +11,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let local_decls = &*local_decls;
+        let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
         for bb in basic_blocks {
             bb.expand_statements(|stmt| {
                 // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
@@ -37,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
                 Some(expand_aggregate(
                     lhs,
                     operands.into_iter().map(|op| {
-                        let ty = op.ty(local_decls, tcx);
+                        let ty = op.ty(&body.local_decls, tcx);
                         (op, ty)
                     }),
                     *kind,
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index a80d2fbd644..44e3945d6fc 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -110,13 +110,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
 
             let patch = MirPatch::new(body);
 
-            let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+            let local_decls = &mut body.local_decls;
 
             let mut visitor =
                 ElaborateBoxDerefVisitor { tcx, unique_did, nonnull_did, local_decls, patch };
 
             for (block, BasicBlockData { statements, terminator, .. }) in
-                basic_blocks.iter_enumerated_mut()
+                body.basic_blocks.as_mut().iter_enumerated_mut()
             {
                 let mut index = 0;
                 for statement in statements {
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
new file mode 100644
index 00000000000..7728fdaffb0
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -0,0 +1,170 @@
+use rustc_hir::def_id::{CrateNum, LocalDefId, LOCAL_CRATE};
+use rustc_middle::mir::*;
+use rustc_middle::ty::layout;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
+use rustc_target::spec::abi::Abi;
+use rustc_target::spec::PanicStrategy;
+
+fn abi_can_unwind(abi: Abi) -> bool {
+    use Abi::*;
+    match abi {
+        C { unwind }
+        | System { unwind }
+        | Cdecl { unwind }
+        | Stdcall { unwind }
+        | Fastcall { unwind }
+        | Vectorcall { unwind }
+        | Thiscall { unwind }
+        | Aapcs { unwind }
+        | Win64 { unwind }
+        | SysV64 { unwind } => unwind,
+        PtxKernel
+        | Msp430Interrupt
+        | X86Interrupt
+        | AmdGpuKernel
+        | EfiApi
+        | AvrInterrupt
+        | AvrNonBlockingInterrupt
+        | CCmseNonSecureCall
+        | Wasm
+        | RustIntrinsic
+        | PlatformIntrinsic
+        | Unadjusted => false,
+        Rust | RustCall | RustCold => true,
+    }
+}
+
+// Check if the body of this def_id can possibly leak a foreign unwind into Rust code.
+fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
+    debug!("has_ffi_unwind_calls({local_def_id:?})");
+
+    // Only perform check on functions because constants cannot call FFI functions.
+    let def_id = local_def_id.to_def_id();
+    let kind = tcx.def_kind(def_id);
+    if !kind.is_fn_like() {
+        return false;
+    }
+
+    let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow();
+
+    let body_ty = tcx.type_of(def_id);
+    let body_abi = match body_ty.kind() {
+        ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
+        ty::Closure(..) => Abi::RustCall,
+        ty::Generator(..) => Abi::Rust,
+        _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
+    };
+    let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi);
+
+    // Foreign unwinds cannot leak past functions that themselves cannot unwind.
+    if !body_can_unwind {
+        return false;
+    }
+
+    let mut tainted = false;
+
+    for block in body.basic_blocks() {
+        if block.is_cleanup {
+            continue;
+        }
+        let Some(terminator) = &block.terminator else { continue };
+        let TerminatorKind::Call { func, .. } = &terminator.kind else { continue };
+
+        let ty = func.ty(body, tcx);
+        let sig = ty.fn_sig(tcx);
+
+        // Rust calls cannot themselves create foreign unwinds.
+        if let Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() {
+            continue;
+        };
+
+        let fn_def_id = match ty.kind() {
+            ty::FnPtr(_) => None,
+            &ty::FnDef(def_id, _) => {
+                // Rust calls cannot themselves create foreign unwinds.
+                if !tcx.is_foreign_item(def_id) {
+                    continue;
+                }
+                Some(def_id)
+            }
+            _ => bug!("invalid callee of type {:?}", ty),
+        };
+
+        if layout::fn_can_unwind(tcx, fn_def_id, sig.abi()) && abi_can_unwind(sig.abi()) {
+            // We have detected a call that can possibly leak foreign unwind.
+            //
+            // Because the function body itself can unwind, we are not aborting this function call
+            // upon unwind, so this call can possibly leak foreign unwind into Rust code if the
+            // panic runtime linked is panic-abort.
+
+            let lint_root = body.source_scopes[terminator.source_info.scope]
+                .local_data
+                .as_ref()
+                .assert_crate_local()
+                .lint_root;
+            let span = terminator.source_info.span;
+
+            tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| {
+                let msg = match fn_def_id {
+                    Some(_) => "call to foreign function with FFI-unwind ABI",
+                    None => "call to function pointer with FFI-unwind ABI",
+                };
+                let mut db = lint.build(msg);
+                db.span_label(span, msg);
+                db.emit();
+            });
+
+            tainted = true;
+        }
+    }
+
+    tainted
+}
+
+fn required_panic_strategy(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<PanicStrategy> {
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    if tcx.is_panic_runtime(LOCAL_CRATE) {
+        return Some(tcx.sess.panic_strategy());
+    }
+
+    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
+        return Some(PanicStrategy::Abort);
+    }
+
+    for def_id in tcx.hir().body_owners() {
+        if tcx.has_ffi_unwind_calls(def_id) {
+            // Given that this crate is compiled in `-C panic=unwind`, the `AbortUnwindingCalls`
+            // MIR pass will not be run on FFI-unwind call sites, therefore a foreign exception
+            // can enter Rust through these sites.
+            //
+            // On the other hand, crates compiled with `-C panic=abort` expects that all Rust
+            // functions cannot unwind (whether it's caused by Rust panic or foreign exception),
+            // and this expectation mismatch can cause unsoundness (#96926).
+            //
+            // To address this issue, we enforce that if FFI-unwind calls are used in a crate
+            // compiled with `panic=unwind`, then the final panic strategy must be `panic=unwind`.
+            // This will ensure that no crates will have wrong unwindability assumption.
+            //
+            // It should be noted that it is okay to link `panic=unwind` into a `panic=abort`
+            // program if it contains no FFI-unwind calls. In such case foreign exception can only
+            // enter Rust in a `panic=abort` crate, which will lead to an abort. There will also
+            // be no exceptions generated from Rust, so the assumption which `panic=abort` crates
+            // make, that no Rust function can unwind, indeed holds for crates compiled with
+            // `panic=unwind` as well. In such case this function returns `None`, indicating that
+            // the crate does not require a particular final panic strategy, and can be freely
+            // linked to crates with either strategy (we need such ability for libstd and its
+            // dependencies).
+            return Some(PanicStrategy::Unwind);
+        }
+    }
+
+    // This crate can be linked with either runtime.
+    None
+}
+
+pub(crate) fn provide(providers: &mut Providers) {
+    *providers = Providers { has_ffi_unwind_calls, required_panic_strategy, ..*providers };
+}
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 9078b8a1cb7..9fdea835967 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -67,7 +67,7 @@ use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
-use rustc_mir_dataflow::storage;
+use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
@@ -1379,7 +1379,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
             },
         );
 
-        let always_live_locals = storage::always_live_locals(&body);
+        let always_live_locals = always_storage_live_locals(&body);
 
         let liveness_info =
             locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 49403ba03a4..8f049a182ee 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -1,14 +1,15 @@
 //! Inlining pass for MIR functions
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
+use rustc_const_eval::transform::validate::equal_up_to_regions;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
 use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
 use rustc_target::spec::abi::Abi;
 
@@ -43,7 +44,15 @@ impl<'tcx> MirPass<'tcx> for Inline {
             return enabled;
         }
 
-        sess.opts.mir_opt_level() >= 3
+        match sess.mir_opt_level() {
+            0 | 1 => false,
+            2 => {
+                (sess.opts.optimize == OptLevel::Default
+                    || sess.opts.optimize == OptLevel::Aggressive)
+                    && sess.opts.incremental == None
+            }
+            _ => true,
+        }
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -76,13 +85,6 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     }
 
     let param_env = tcx.param_env_reveal_all_normalized(def_id);
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
-        tcx,
-        def_id.to_def_id(),
-        param_env,
-        ObligationCause::misc(body.span, hir_id),
-    );
 
     let mut this = Inliner {
         tcx,
@@ -166,6 +168,49 @@ impl<'tcx> Inliner<'tcx> {
             return Err("failed to normalize callee body");
         };
 
+        // Check call signature compatibility.
+        // Normally, this shouldn't be required, but trait normalization failure can create a
+        // validation ICE.
+        let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
+        let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
+        let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
+        let output_type = callee_body.return_ty();
+        if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) {
+            trace!(?output_type, ?destination_ty);
+            return Err("failed to normalize return type");
+        }
+        if callsite.fn_sig.abi() == Abi::RustCall {
+            let (arg_tuple, skipped_args) = match &args[..] {
+                [arg_tuple] => (arg_tuple, 0),
+                [_, arg_tuple] => (arg_tuple, 1),
+                _ => bug!("Expected `rust-call` to have 1 or 2 args"),
+            };
+
+            let arg_tuple_ty = arg_tuple.ty(&caller_body.local_decls, self.tcx);
+            let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else {
+                bug!("Closure arguments are not passed as a tuple");
+            };
+
+            for (arg_ty, input) in
+                arg_tuple_tys.iter().zip(callee_body.args_iter().skip(skipped_args))
+            {
+                let input_type = callee_body.local_decls[input].ty;
+                if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) {
+                    trace!(?arg_ty, ?input_type);
+                    return Err("failed to normalize tuple argument type");
+                }
+            }
+        } else {
+            for (arg, input) in args.iter().zip(callee_body.args_iter()) {
+                let input_type = callee_body.local_decls[input].ty;
+                let arg_ty = arg.ty(&caller_body.local_decls, self.tcx);
+                if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) {
+                    trace!(?arg_ty, ?input_type);
+                    return Err("failed to normalize argument type");
+                }
+            }
+        }
+
         let old_blocks = caller_body.basic_blocks().next_index();
         self.inline_call(caller_body, &callsite, callee_body);
         let new_blocks = old_blocks..caller_body.basic_blocks().next_index();
@@ -263,6 +308,10 @@ impl<'tcx> Inliner<'tcx> {
                     return None;
                 }
 
+                if self.history.contains(&callee) {
+                    return None;
+                }
+
                 let fn_sig = self.tcx.bound_fn_sig(def_id).subst(self.tcx, substs);
 
                 return Some(CallSite {
@@ -285,8 +334,14 @@ impl<'tcx> Inliner<'tcx> {
         callsite: &CallSite<'tcx>,
         callee_attrs: &CodegenFnAttrs,
     ) -> Result<(), &'static str> {
-        if let InlineAttr::Never = callee_attrs.inline {
-            return Err("never inline hint");
+        match callee_attrs.inline {
+            InlineAttr::Never => return Err("never inline hint"),
+            InlineAttr::Always | InlineAttr::Hint => {}
+            InlineAttr::None => {
+                if self.tcx.sess.mir_opt_level() <= 2 {
+                    return Err("at mir-opt-level=2, only #[inline] is inlined");
+                }
+            }
         }
 
         // Only inline local functions if they would be eligible for cross-crate
@@ -407,22 +462,9 @@ impl<'tcx> Inliner<'tcx> {
                 }
 
                 TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => {
-                    if let ty::FnDef(def_id, substs) =
+                    if let ty::FnDef(def_id, _) =
                         *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind()
                     {
-                        if let Ok(substs) =
-                            self.tcx.try_normalize_erasing_regions(self.param_env, substs)
-                        {
-                            if let Ok(Some(instance)) =
-                                Instance::resolve(self.tcx, self.param_env, def_id, substs)
-                            {
-                                if callsite.callee.def_id() == instance.def_id() {
-                                    return Err("self-recursion");
-                                } else if self.history.contains(&instance) {
-                                    return Err("already inlined");
-                                }
-                            }
-                        }
                         // Don't give intrinsics the extra penalty for calls
                         if tcx.is_intrinsic(def_id) {
                             cost += INSTR_COST;
@@ -482,14 +524,12 @@ impl<'tcx> Inliner<'tcx> {
         if let InlineAttr::Always = callee_attrs.inline {
             debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost);
             Ok(())
+        } else if cost <= threshold {
+            debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
+            Ok(())
         } else {
-            if cost <= threshold {
-                debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
-                Ok(())
-            } else {
-                debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold);
-                Err("cost above threshold")
-            }
+            debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold);
+            Err("cost above threshold")
         }
     }
 
@@ -548,7 +588,7 @@ impl<'tcx> Inliner<'tcx> {
                 );
                 expn_data.def_site = callee_body.span;
                 let expn_data =
-                    LocalExpnId::fresh(expn_data, self.tcx.create_stable_hashing_context());
+                    self.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
                 let mut integrator = Integrator {
                     args: &args,
                     new_locals: Local::new(caller_body.local_decls.len())..,
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index fd7de2bd1dc..a3a35f95071 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir::TerminatorKind;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
 use rustc_session::Limit;
 
@@ -48,7 +48,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
                 trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
                 continue;
             };
-            let Some(callee) = ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() else {
+            let Ok(Some(callee)) = ty::Instance::resolve(tcx, param_env, callee, substs) else {
                 trace!(?callee, "cannot resolve, skipping");
                 continue;
             };
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instcombine.rs
index ea10ec5f25c..2f3c65869ef 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instcombine.rs
@@ -16,9 +16,8 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let ctx = InstCombineContext { tcx, local_decls };
-        for block in basic_blocks.iter_mut() {
+        let ctx = InstCombineContext { tcx, local_decls: &body.local_decls };
+        for block in body.basic_blocks.as_mut() {
             for statement in block.statements.iter_mut() {
                 match statement.kind {
                     StatementKind::Assign(box (_place, ref mut rvalue)) => {
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index b7caa61ef07..0887775aae5 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -28,7 +28,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_span::{Span, Symbol};
 
 #[macro_use]
@@ -59,6 +59,7 @@ pub mod dump_mir;
 mod early_otherwise_branch;
 mod elaborate_box_derefs;
 mod elaborate_drops;
+mod ffi_unwind_calls;
 mod function_item_references;
 mod generator;
 mod inline;
@@ -98,6 +99,7 @@ pub fn provide(providers: &mut Providers) {
     check_unsafety::provide(providers);
     check_packed_ref::provide(providers);
     coverage::query::provide(providers);
+    ffi_unwind_calls::provide(providers);
     shim::provide(providers);
     *providers = Providers {
         mir_keys,
@@ -171,7 +173,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
             intravisit::walk_struct_def(self, v)
         }
     }
-    tcx.hir().deep_visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set });
+    tcx.hir().visit_all_item_likes_in_crate(&mut GatherCtors { tcx, set: &mut set });
 
     set
 }
@@ -223,6 +225,9 @@ fn mir_const<'tcx>(
         }
     }
 
+    // has_ffi_unwind_calls query uses the raw mir, so make sure it is run.
+    tcx.ensure().has_ffi_unwind_calls(def.did);
+
     let mut body = tcx.mir_built(def).steal();
 
     rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 989b94b68c1..b7ba616510c 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -11,8 +11,8 @@ pub struct LowerIntrinsics;
 
 impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks {
+        let local_decls = &body.local_decls;
+        for block in body.basic_blocks.as_mut() {
             let terminator = block.terminator.as_mut().unwrap();
             if let TerminatorKind::Call { func, args, destination, target, .. } =
                 &mut terminator.kind
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 07163cfe575..47848cfa497 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -26,11 +26,11 @@ pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         return;
     };
 
-    let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-
+    // The one successor remains unchanged, so no need to invalidate
+    let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
     for block in basic_blocks {
         // lower `<[_]>::len` calls
-        lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id);
+        lower_slice_len_call(tcx, block, &body.local_decls, slice_len_fn_item_def_id);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 7cd7d26328a..a0ba69c89b0 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -48,7 +48,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
         let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
 
-        let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
+        let bbs = body.basic_blocks.as_mut();
         let mut should_cleanup = false;
         'outer: for bb_idx in bbs.indices() {
             if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) {
@@ -108,7 +108,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
 
             // Introduce a temporary for the discriminant value.
             let source_info = bbs[bb_idx].terminator().source_info;
-            let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span));
+            let discr_local = body.local_decls.push(LocalDecl::new(switch_ty, source_info.span));
 
             // We already checked that first and second are different blocks,
             // and bb_idx has a different terminator from both of them.
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 0f45711baa3..c0217a10541 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -32,7 +32,9 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
 }
 
 pub fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+    // We don't ever touch terminators, so no need to invalidate the CFG cache
+    let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
+    let local_decls = &mut body.local_decls;
 
     // do a preliminary analysis to see if we ever have locals of type `[T;N]` or `&[T;N]`
     let mut interesting_locals = BitSet::new_empty(local_decls.len());
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 444b4126e88..bb063915f55 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -133,7 +133,7 @@ fn find_local_assigned_to_return_place(
             return local;
         }
 
-        match body.predecessors()[block].as_slice() {
+        match body.basic_blocks.predecessors()[block].as_slice() {
             &[pred] => block = pred,
             _ => return None,
         }
@@ -219,7 +219,7 @@ impl IsReturnPlaceRead {
 }
 
 impl<'tcx> Visitor<'tcx> for IsReturnPlaceRead {
-    fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) {
+    fn visit_local(&mut self, l: Local, ctxt: PlaceContext, _: Location) {
         if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() {
             self.0 = true;
         }
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index c9b6e1459d3..dbe082e9093 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -17,7 +17,7 @@ impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
         }
 
         trace!("Running RemoveStorageMarkers on {:?}", body.source);
-        for data in body.basic_blocks_mut() {
+        for data in body.basic_blocks.as_mut_preserves_cfg() {
             data.statements.retain(|statement| match statement.kind {
                 StatementKind::StorageLive(..)
                 | StatementKind::StorageDead(..)
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 921a11a3a06..84ccf6e1f61 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -20,11 +20,10 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
         let param_env = tcx.param_env_reveal_all_normalized(did);
         let mut should_simplify = false;
 
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks {
+        for block in body.basic_blocks.as_mut() {
             let terminator = block.terminator_mut();
             if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
-                let ty = place.ty(local_decls, tcx);
+                let ty = place.ty(&body.local_decls, tcx);
                 if ty.ty.needs_drop(tcx, param_env) {
                     continue;
                 }
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index aaee6f491cd..40be4f146db 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -18,8 +18,9 @@ impl<'tcx> MirPass<'tcx> for RemoveZsts {
             return;
         }
         let param_env = tcx.param_env(body.source.def_id());
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks.iter_mut() {
+        let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
+        let local_decls = &body.local_decls;
+        for block in basic_blocks {
             for statement in block.statements.iter_mut() {
                 if let StatementKind::Assign(box (place, _)) | StatementKind::Deinit(box place) =
                     statement.kind
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index 33ea1c4ba2f..194c2794aac 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -61,7 +61,7 @@ impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
 /// Returns the amount of blocks that were duplicated
 pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
     let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
-    let predecessors = body.predecessors();
+    let predecessors = body.basic_blocks.predecessors();
     'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
         if let TerminatorKind::SwitchInt {
             discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 8a78ea5c82b..980af984362 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -509,12 +509,12 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
         }
     }
 
-    fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) {
+    fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) {
         if self.increment {
-            self.use_count[*local] += 1;
+            self.use_count[local] += 1;
         } else {
-            assert_ne!(self.use_count[*local], 0);
-            self.use_count[*local] -= 1;
+            assert_ne!(self.use_count[local], 0);
+            self.use_count[local] -= 1;
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/simplify_try.rs b/compiler/rustc_mir_transform/src/simplify_try.rs
index b3d45c7a221..fca9f7eeb24 100644
--- a/compiler/rustc_mir_transform/src/simplify_try.rs
+++ b/compiler/rustc_mir_transform/src/simplify_try.rs
@@ -386,14 +386,17 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
         trace!("running SimplifyArmIdentity on {:?}", source);
 
         let local_uses = LocalUseCounter::get_local_uses(body);
-        let (basic_blocks, local_decls, debug_info) =
-            body.basic_blocks_local_decls_mut_and_var_debug_info();
-        for bb in basic_blocks {
+        for bb in body.basic_blocks.as_mut() {
             if let Some(opt_info) =
-                get_arm_identity_info(&bb.statements, local_decls.len(), debug_info)
+                get_arm_identity_info(&bb.statements, body.local_decls.len(), &body.var_debug_info)
             {
                 trace!("got opt_info = {:#?}", opt_info);
-                if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) {
+                if !optimization_applies(
+                    &opt_info,
+                    &body.local_decls,
+                    &local_uses,
+                    &body.var_debug_info,
+                ) {
                     debug!("optimization skipped for {:?}", source);
                     continue;
                 }
@@ -431,7 +434,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
 
                 // Fix the debug info to point to the right local
                 for dbg_index in opt_info.dbg_info_to_adjust {
-                    let dbg_info = &mut debug_info[dbg_index];
+                    let dbg_info = &mut body.var_debug_info[dbg_index];
                     assert!(
                         matches!(dbg_info.value, VarDebugInfoContents::Place(_)),
                         "value was not a Place"
@@ -462,14 +465,14 @@ impl LocalUseCounter {
 }
 
 impl Visitor<'_> for LocalUseCounter {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _location: Location) {
         if context.is_storage_marker()
             || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo)
         {
             return;
         }
 
-        self.local_uses[*local] += 1;
+        self.local_uses[local] += 1;
     }
 }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 2af22e129a5..b3ac0f4cbea 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -194,7 +194,9 @@ use rustc_middle::mir::{self, Local, Location};
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, VtblEntry};
+use rustc_middle::ty::{
+    self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitable, VtblEntry,
+};
 use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
 use rustc_session::config::EntryFnType;
 use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
@@ -730,7 +732,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                             def_id,
                             substs,
                             ty::ClosureKind::FnOnce,
-                        );
+                        )
+                        .expect("failed to normalize and resolve closure during codegen");
                         if should_codegen_locally(self.tcx, &instance) {
                             self.output.push(create_fn_mono_item(self.tcx, instance, span));
                         }
@@ -928,7 +931,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
     fn visit_local(
         &mut self,
-        _place_local: &Local,
+        _place_local: Local,
         _context: mir::visit::PlaceContext,
         _location: Location,
     ) {
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 320765e7af3..9190e5fe4eb 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -9,7 +9,7 @@ use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, Linkage, Visibility};
 use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::ty::print::characteristic_def_id_of_type;
-use rustc_middle::ty::{self, fold::TypeFoldable, DefIdTree, InstanceDef, TyCtxt};
+use rustc_middle::ty::{self, visit::TypeVisitable, DefIdTree, InstanceDef, TyCtxt};
 use rustc_span::symbol::Symbol;
 
 use super::PartitioningCx;
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index f29143b4480..aaa924d7fa0 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -13,9 +13,9 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::{
     self,
-    fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor},
     query::Providers,
     subst::SubstsRef,
+    visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
     Const, Ty, TyCtxt,
 };
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 0869ed65ad2..63055c56c5c 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -357,7 +357,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
 }
 
 impl<'a> Parser<'a> {
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub(super) fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -366,7 +366,7 @@ impl<'a> Parser<'a> {
         err.span_err(sp, self.diagnostic())
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index bf685aa8cad..87bc0d9762e 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -271,8 +271,7 @@ impl<'a> Parser<'a> {
             // MACRO_RULES ITEM
             self.parse_item_macro_rules(vis, has_bang)?
         } else if self.isnt_macro_invocation()
-            && (self.token.is_ident_named(Symbol::intern("import"))
-                || self.token.is_ident_named(Symbol::intern("using")))
+            && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
         {
             return self.recover_import_as_use();
         } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 00002f6f59b..67e6402c0ae 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1353,7 +1353,16 @@ impl<'a> Parser<'a> {
 
     /// Parses `extern string_literal?`.
     fn parse_extern(&mut self) -> Extern {
-        if self.eat_keyword(kw::Extern) { Extern::from_abi(self.parse_abi()) } else { Extern::None }
+        if self.eat_keyword(kw::Extern) {
+            let mut extern_span = self.prev_token.span;
+            let abi = self.parse_abi();
+            if let Some(abi) = abi {
+                extern_span = extern_span.to(abi.span);
+            }
+            Extern::from_abi(abi, extern_span)
+        } else {
+            Extern::None
+        }
     }
 
     /// Parses a string literal as an ABI spec.
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 40545b19b24..d0723c68a77 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1163,7 +1163,7 @@ impl CheckAttrVisitor<'_> {
                         hir_id,
                         meta.span(),
                         |lint| {
-                            lint.build(&"invalid `doc` attribute").emit();
+                            lint.build("invalid `doc` attribute").emit();
                         },
                     );
                     is_valid = false;
@@ -2428,7 +2428,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let check_attr_visitor = &mut CheckAttrVisitor { tcx };
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, check_attr_visitor);
+    tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 996ca66de0e..31c159c1f75 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -56,7 +56,7 @@ impl NonConstExpr {
 
 fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
     let mut vis = CheckConstVisitor::new(tcx);
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut vis);
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis);
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index f9e67310452..1add91fc9c5 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -1,4 +1,4 @@
-use rustc_ast::entry::EntryPointType;
+use rustc_ast::{entry::EntryPointType, Attribute};
 use rustc_errors::struct_span_err;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
@@ -7,9 +7,8 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_session::config::{CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
 
 struct EntryContext<'tcx> {
     tcx: TyCtxt<'tcx>,
@@ -72,9 +71,16 @@ fn entry_point_type(ctxt: &EntryContext<'_>, id: ItemId, at_root: bool) -> Entry
     }
 }
 
-fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
-    sess.struct_span_err(span, &format!("`{}` attribute can only be used on functions", attr))
-        .emit();
+fn err_if_attr_found(ctxt: &EntryContext<'_>, attrs: &[Attribute], sym: Symbol) {
+    if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym) {
+        ctxt.tcx
+            .sess
+            .struct_span_err(
+                attr.span,
+                &format!("`{}` attribute can only be used on functions", sym.as_str()),
+            )
+            .emit();
+    }
 }
 
 fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
@@ -84,12 +90,8 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         EntryPointType::None => (),
         _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
             let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::start) {
-                throw_attr_err(&ctxt.tcx.sess, attr.span, "start");
-            }
-            if let Some(attr) = ctxt.tcx.sess.find_by_name(attrs, sym::rustc_main) {
-                throw_attr_err(&ctxt.tcx.sess, attr.span, "rustc_main");
-            }
+            err_if_attr_found(ctxt, attrs, sym::start);
+            err_if_attr_found(ctxt, attrs, sym::rustc_main);
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 23ff0a91159..9deb0042ff3 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -1,9 +1,9 @@
-use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lock;
 use rustc_hir as hir;
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit;
 use rustc_hir::{HirId, ItemLocalId};
+use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
@@ -15,32 +15,35 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         crate::hir_stats::print_hir_stats(tcx);
     }
 
-    let errors = Lock::new(Vec::new());
-    let hir_map = tcx.hir();
+    #[cfg(debug_assertions)]
+    {
+        let errors = Lock::new(Vec::new());
+        let hir_map = tcx.hir();
 
-    hir_map.par_for_each_module(|module_id| {
-        let mut v = HirIdValidator {
-            hir_map,
-            owner: None,
-            hir_ids_seen: Default::default(),
-            errors: &errors,
-        };
+        hir_map.par_for_each_module(|module_id| {
+            let mut v = HirIdValidator {
+                hir_map,
+                owner: None,
+                hir_ids_seen: Default::default(),
+                errors: &errors,
+            };
 
-        tcx.hir().deep_visit_item_likes_in_module(module_id, &mut v);
-    });
+            tcx.hir().visit_item_likes_in_module(module_id, &mut v);
+        });
 
-    let errors = errors.into_inner();
+        let errors = errors.into_inner();
 
-    if !errors.is_empty() {
-        let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2);
-        tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message);
+        if !errors.is_empty() {
+            let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2);
+            tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message);
+        }
     }
 }
 
 struct HirIdValidator<'a, 'hir> {
     hir_map: Map<'hir>,
     owner: Option<LocalDefId>,
-    hir_ids_seen: FxHashSet<ItemLocalId>,
+    hir_ids_seen: GrowableBitSet<ItemLocalId>,
     errors: &'a Lock<Vec<String>>,
 }
 
@@ -80,7 +83,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
         if max != self.hir_ids_seen.len() - 1 {
             // Collect the missing ItemLocalIds
             let missing: Vec<_> = (0..=max as u32)
-                .filter(|&i| !self.hir_ids_seen.contains(&ItemLocalId::from_u32(i)))
+                .filter(|&i| !self.hir_ids_seen.contains(ItemLocalId::from_u32(i)))
                 .collect();
 
             // Try to map those to something more useful
@@ -106,7 +109,7 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> {
                     missing_items,
                     self.hir_ids_seen
                         .iter()
-                        .map(|&local_id| HirId { owner, local_id })
+                        .map(|local_id| HirId { owner, local_id })
                         .map(|h| format!("({:?} {})", h, self.hir_map.node_to_string(h)))
                         .collect::<Vec<_>>()
                 )
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 80a263f4cb2..0070c0699a4 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -140,7 +140,7 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
 }
 
 fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx));
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 9cfef26fd03..68b2a052391 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -31,7 +31,7 @@ struct CheckLoopVisitor<'a, 'hir> {
 }
 
 fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().deep_visit_item_likes_in_module(
+    tcx.hir().visit_item_likes_in_module(
         module_def_id,
         &mut CheckLoopVisitor { sess: &tcx.sess, hir_map: tcx.hir(), cx: Normal },
     );
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 40844b84af0..20765abf392 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -14,7 +14,7 @@ use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckNakedFunctions { tcx });
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 9eaefc8b8aa..12050dceb60 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -660,7 +660,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -890,7 +890,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
         tcx.hir().walk_toplevel_module(&mut missing);
-        tcx.hir().deep_visit_all_item_likes(&mut missing);
+        tcx.hir().visit_all_item_likes_in_crate(&mut missing);
     }
 
     let declared_lang_features = &tcx.features().declared_lang_features;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index f5e323e2bc4..5560d44aa0d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -27,7 +27,7 @@ use rustc_middle::thir::abstract_const::Node as ACNode;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
-use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
 use rustc_span::symbol::{kw, Ident};
@@ -80,7 +80,7 @@ trait DefIdVisitor<'tcx> {
             dummy: Default::default(),
         }
     }
-    fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit(&mut self, ty_fragment: impl TypeVisitable<'tcx>) -> ControlFlow<Self::BreakTy> {
         ty_fragment.visit_with(&mut self.skeleton())
     }
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -467,7 +467,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         }
 
         let macro_module_def_id = self.tcx.local_parent(local_def_id);
-        if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
+        if self.tcx.opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
             // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
             return;
         }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index d06eb97798e..7c1fdc4e306 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -27,6 +27,8 @@ use rustc_span::Span;
 mod plumbing;
 pub use plumbing::QueryCtxt;
 use rustc_query_system::query::*;
+#[cfg(parallel_compiler)]
+pub use rustc_query_system::query::{deadlock, QueryContext};
 
 mod keys;
 use keys::Key;
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index b01c512a3b4..4c25075327f 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -653,12 +653,11 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
             #[cfg(debug_assertions)]
             {
                 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-                let mut hcx = decoder.tcx.create_stable_hashing_context();
-                let mut hasher = StableHasher::new();
-                hcx.while_hashing_spans(true, |hcx| {
-                    expn_id.expn_data().hash_stable(hcx, &mut hasher)
+                let local_hash: u64 = decoder.tcx.with_stable_hashing_context(|mut hcx| {
+                    let mut hasher = StableHasher::new();
+                    expn_id.expn_data().hash_stable(&mut hcx, &mut hasher);
+                    hasher.finish()
                 });
-                let local_hash: u64 = hasher.finish();
                 debug_assert_eq!(hash.local_hash(), local_hash);
             }
 
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 66f4508f6b4..333dc5aa668 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -132,11 +132,6 @@ impl<'tcx> QueryCtxt<'tcx> {
         self.queries.on_disk_cache.as_ref()
     }
 
-    #[cfg(parallel_compiler)]
-    pub unsafe fn deadlock(self, registry: &rustc_rayon_core::Registry) {
-        rustc_query_system::query::deadlock(self, registry)
-    }
-
     pub(super) fn encode_query_results(
         self,
         encoder: &mut on_disk_cache::CacheEncoder<'_, 'tcx>,
@@ -287,17 +282,21 @@ macro_rules! define_queries {
                 } else {
                     Some(key.default_span(*tcx))
                 };
-                // Use `tcx.hir().opt_def_kind()` to reduce the chance of
-                // accidentally triggering an infinite query loop.
-                let def_kind = key.key_as_def_id()
-                    .and_then(|def_id| def_id.as_local())
-                    .and_then(|def_id| tcx.hir().opt_def_kind(def_id));
+                let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
+                    // Try to avoid infinite recursion.
+                    None
+                } else {
+                    key.key_as_def_id()
+                        .and_then(|def_id| def_id.as_local())
+                        .and_then(|def_id| tcx.opt_def_kind(def_id))
+                };
                 let hash = || {
-                    let mut hcx = tcx.create_stable_hashing_context();
-                    let mut hasher = StableHasher::new();
-                    std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
-                    key.hash_stable(&mut hcx, &mut hasher);
-                    hasher.finish::<u64>()
+                    tcx.with_stable_hashing_context(|mut hcx|{
+                        let mut hasher = StableHasher::new();
+                        std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
+                        key.hash_stable(&mut hcx, &mut hasher);
+                        hasher.finish::<u64>()
+                    })
                 };
 
                 QueryStackFrame::new(name, description, span, def_kind, hash)
@@ -378,6 +377,17 @@ macro_rules! define_queries {
                 }
             }
 
+            // We use this for the forever-red node.
+            pub fn Red() -> DepKindStruct {
+                DepKindStruct {
+                    is_anon: false,
+                    is_eval_always: false,
+                    fingerprint_style: FingerprintStyle::Unit,
+                    force_from_dep_node: Some(|_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node)),
+                    try_load_from_on_disk_cache: None,
+                }
+            }
+
             pub fn TraitSelect() -> DepKindStruct {
                 DepKindStruct {
                     is_anon: true,
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index bb2179a2495..c6210095b60 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -131,12 +131,11 @@ where
 
     #[inline(always)]
     default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
-        let mut hcx = tcx.create_stable_hashing_context();
-        let mut hasher = StableHasher::new();
-
-        self.hash_stable(&mut hcx, &mut hasher);
-
-        hasher.finish()
+        tcx.with_stable_hashing_context(|mut hcx| {
+            let mut hasher = StableHasher::new();
+            self.hash_stable(&mut hcx, &mut hasher);
+            hasher.finish()
+        })
     }
 
     #[inline(always)]
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 341cf8f827b..e7026096e7b 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -43,6 +43,7 @@ rustc_index::newtype_index! {
 impl DepNodeIndex {
     pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
     pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
+    pub const FOREVER_RED_NODE: DepNodeIndex = DepNodeIndex::from_u32(1);
 }
 
 impl std::convert::From<DepNodeIndex> for QueryInvocationId {
@@ -59,6 +60,7 @@ pub enum DepNodeColor {
 }
 
 impl DepNodeColor {
+    #[inline]
     pub fn is_green(self) -> bool {
         match self {
             DepNodeColor::Red => false,
@@ -124,6 +126,8 @@ impl<K: DepKind> DepGraph<K> {
             record_stats,
         );
 
+        let colors = DepNodeColorMap::new(prev_graph_node_count);
+
         // Instantiate a dependy-less node only once for anonymous queries.
         let _green_node_index = current.intern_new_node(
             profiler,
@@ -131,7 +135,19 @@ impl<K: DepKind> DepGraph<K> {
             smallvec![],
             Fingerprint::ZERO,
         );
-        debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+        assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+
+        // Instantiate a dependy-less red node only once for anonymous queries.
+        let (_red_node_index, _prev_and_index) = current.intern_node(
+            profiler,
+            &prev_graph,
+            DepNode { kind: DepKind::RED, hash: Fingerprint::ZERO.into() },
+            smallvec![],
+            None,
+            false,
+        );
+        assert_eq!(_red_node_index, DepNodeIndex::FOREVER_RED_NODE);
+        assert!(matches!(_prev_and_index, None | Some((_, DepNodeColor::Red))));
 
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
@@ -140,7 +156,7 @@ impl<K: DepKind> DepGraph<K> {
                 current,
                 processed_side_effects: Default::default(),
                 previous: prev_graph,
-                colors: DepNodeColorMap::new(prev_graph_node_count),
+                colors,
                 debug_loaded_from_disk: Default::default(),
             })),
             virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
@@ -328,10 +344,8 @@ impl<K: DepKind> DepGraph<K> {
 
         let dcx = cx.dep_context();
         let hashing_timer = dcx.profiler().incr_result_hashing();
-        let current_fingerprint = hash_result.map(|f| {
-            let mut hcx = dcx.create_stable_hashing_context();
-            f(&mut hcx, &result)
-        });
+        let current_fingerprint =
+            hash_result.map(|f| dcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, &result)));
 
         let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks;
 
@@ -886,8 +900,12 @@ impl<K: DepKind> DepGraph<K> {
 #[derive(Clone, Debug, Encodable, Decodable)]
 pub struct WorkProduct {
     pub cgu_name: String,
-    /// Saved file associated with this CGU.
-    pub saved_file: String,
+    /// Saved files associated with this CGU. In each key/value pair, the value is the path to the
+    /// saved file and the key is some identifier for the type of file being saved.
+    ///
+    /// By convention, file extensions are currently used as identifiers, i.e. the key "o" maps to
+    /// the object file's path, and "dwo" to the dwarf object file's path.
+    pub saved_files: FxHashMap<String, String>,
 }
 
 // Index type for `DepNodeData`'s edges.
@@ -967,6 +985,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
         let nanos = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64;
         let mut stable_hasher = StableHasher::new();
         nanos.hash(&mut stable_hasher);
+        let anon_id_seed = stable_hasher.finish();
 
         #[cfg(debug_assertions)]
         let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") {
@@ -1002,7 +1021,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
                 )
             }),
             prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)),
-            anon_id_seed: stable_hasher.finish(),
+            anon_id_seed,
             #[cfg(debug_assertions)]
             forbidden_edge,
             total_read_count: AtomicU64::new(0),
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 5907ae309ca..342d95ca490 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -23,7 +23,7 @@ pub trait DepContext: Copy {
     type DepKind: self::DepKind;
 
     /// Create a hashing context for hashing new results.
-    fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
+    fn with_stable_hashing_context<R>(&self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R;
 
     /// Access the DepGraph.
     fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
@@ -85,8 +85,12 @@ impl FingerprintStyle {
 
 /// Describe the different families of dependency nodes.
 pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static {
+    /// DepKind to use when incr. comp. is turned off.
     const NULL: Self;
 
+    /// DepKind to use to create the initial forever-red node.
+    const RED: Self;
+
     /// Implementation of `std::fmt::Debug` for `DepNode`.
     fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
 
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index 62a1f776fb3..843f6f9d703 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -1,4 +1,5 @@
 use crate::ich;
+
 use rustc_ast as ast;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
@@ -118,13 +119,13 @@ impl<'a> StableHashingContext<'a> {
         &mut self,
         hash_bodies: bool,
         owner: LocalDefId,
-        bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
-        f: impl FnOnce(&mut Self),
+        bodies: &SortedMap<hir::ItemLocalId, &hir::Body<'_>>,
+        f: impl FnOnce(&mut StableHashingContext<'_>),
     ) {
-        let prev = self.body_resolver;
-        self.body_resolver = BodyResolver::Traverse { hash_bodies, owner, bodies };
-        f(self);
-        self.body_resolver = prev;
+        f(&mut StableHashingContext {
+            body_resolver: BodyResolver::Traverse { hash_bodies, owner, bodies },
+            ..self.clone()
+        });
     }
 
     #[inline]
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 2a07d9b7f80..9f5779194af 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -84,6 +84,7 @@ pub struct QueryJob {
 
 impl QueryJob {
     /// Creates a new query job.
+    #[inline]
     pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
         QueryJob {
             id,
@@ -106,6 +107,7 @@ impl QueryJob {
     ///
     /// This does nothing for single threaded rustc,
     /// as there are no concurrent jobs which could be waiting on us
+    #[inline]
     pub fn signal_complete(self) {
         #[cfg(parallel_compiler)]
         {
@@ -492,14 +494,13 @@ fn remove_cycle(
 /// There may be multiple cycles involved in a deadlock, so this searches
 /// all active queries for cycles before finally resuming all the waiters at once.
 #[cfg(parallel_compiler)]
-pub fn deadlock<CTX: QueryContext>(tcx: CTX, registry: &rayon_core::Registry) {
+pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
     let on_panic = OnDrop(|| {
         eprintln!("deadlock handler panicked, aborting process");
         process::abort();
     });
 
     let mut wakelist = Vec::new();
-    let query_map = tcx.try_collect_active_jobs().unwrap();
     let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
 
     let mut found_cycle = false;
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index de64ebb6203..f698a853d1e 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -81,6 +81,7 @@ pub struct QuerySideEffects {
 }
 
 impl QuerySideEffects {
+    #[inline]
     pub fn is_empty(&self) -> bool {
         let QuerySideEffects { diagnostics } = self;
         diagnostics.is_empty()
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 3e4c7ad9f8f..bbcd00be943 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -542,8 +542,7 @@ fn incremental_verify_ich<CTX, K, V: Debug>(
 
     debug!("BEGIN verify_ich({:?})", dep_node);
     let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
-        let mut hcx = tcx.create_stable_hashing_context();
-        f(&mut hcx, result)
+        tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
     });
     let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
     debug!("END verify_ich({:?})", dep_node);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e8b7cee5734..2851b08cd93 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -28,7 +28,7 @@ use rustc_span::{BytePos, Span};
 use tracing::debug;
 
 use crate::imports::{Import, ImportKind, ImportResolver};
-use crate::late::Rib;
+use crate::late::{PatternSource, Rib};
 use crate::path_names_to_string;
 use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
 use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
@@ -896,25 +896,40 @@ impl<'a> Resolver<'a> {
                 err
             }
             ResolutionError::BindingShadowsSomethingUnacceptable {
-                shadowing_binding_descr,
+                shadowing_binding,
                 name,
                 participle,
                 article,
-                shadowed_binding_descr,
+                shadowed_binding,
                 shadowed_binding_span,
             } => {
+                let shadowed_binding_descr = shadowed_binding.descr();
                 let mut err = struct_span_err!(
                     self.session,
                     span,
                     E0530,
                     "{}s cannot shadow {}s",
-                    shadowing_binding_descr,
+                    shadowing_binding.descr(),
                     shadowed_binding_descr,
                 );
                 err.span_label(
                     span,
                     format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
                 );
+                match (shadowing_binding, shadowed_binding) {
+                    (
+                        PatternSource::Match,
+                        Res::Def(DefKind::Ctor(CtorOf::Variant | CtorOf::Struct, CtorKind::Fn), _),
+                    ) => {
+                        err.span_suggestion(
+                            span,
+                            "try specify the pattern arguments",
+                            format!("{}(..)", name),
+                            Applicability::Unspecified,
+                        );
+                    }
+                    _ => (),
+                }
                 let msg =
                     format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
                 err.span_label(shadowed_binding_span, msg);
@@ -928,10 +943,7 @@ impl<'a> Resolver<'a> {
                     "generic parameters with a default cannot use \
                                                 forward declared identifiers"
                 );
-                err.span_label(
-                    span,
-                    "defaulted generic parameters cannot be forward declared".to_string(),
-                );
+                err.span_label(span, "defaulted generic parameters cannot be forward declared");
                 err
             }
             ResolutionError::ParamInTyOfConstParam(name) => {
@@ -1495,6 +1507,21 @@ impl<'a> Resolver<'a> {
             err.help("have you added the `#[macro_use]` on the module/import?");
             return;
         }
+        if ident.name == kw::Default
+            && let ModuleKind::Def(DefKind::Enum, def_id, _) = parent_scope.module.kind
+            && let Some(span) = self.opt_span(def_id)
+        {
+            let source_map = self.session.source_map();
+            let head_span = source_map.guess_head_span(span);
+            if let Ok(head) = source_map.span_to_snippet(head_span) {
+                err.span_suggestion(head_span, "consider adding a derive", format!("#[derive(Default)]\n{head}"), Applicability::MaybeIncorrect);
+            } else {
+                err.span_help(
+                    head_span,
+                    "consider adding `#[derive(Default)]` to this enum",
+                );
+            }
+        }
         for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
             if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
                 ident,
@@ -1620,7 +1647,7 @@ impl<'a> Resolver<'a> {
 
     fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: bool) -> String {
         let res = b.res();
-        if b.span.is_dummy() || self.session.source_map().span_to_snippet(b.span).is_err() {
+        if b.span.is_dummy() || !self.session.source_map().is_span_accessible(b.span) {
             // These already contain the "built-in" prefix or look bad with it.
             let add_built_in =
                 !matches!(b.res(), Res::NonMacroAttr(..) | Res::PrimTy(..) | Res::ToolMod);
@@ -2580,8 +2607,10 @@ fn show_candidates(
             } else {
                 "item".to_string()
             };
+            let plural_descr =
+                if descr.ends_with("s") { format!("{}es", descr) } else { format!("{}s", descr) };
 
-            let mut msg = format!("{}these {}s exist but are inaccessible", prefix, descr);
+            let mut msg = format!("{}these {} exist but are inaccessible", prefix, plural_descr);
             let mut has_colon = false;
 
             let mut spans = Vec::new();
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index c6aa57f039d..e6060ad4665 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1090,31 +1090,31 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         // Since import resolution is finished, globs will not define any more names.
         *module.globs.borrow_mut() = Vec::new();
 
-        let mut reexports = Vec::new();
-
-        module.for_each_child(self.r, |_, ident, _, binding| {
-            // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
-            // into the crate root to actual `NameBindingKind::Import`.
-            if binding.is_import()
-                || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
-            {
-                let res = binding.res().expect_non_local();
-                // Ambiguous imports are treated as errors at this point and are
-                // not exposed to other crates (see #36837 for more details).
-                if res != def::Res::Err && !binding.is_ambiguity() {
-                    reexports.push(ModChild {
-                        ident,
-                        res,
-                        vis: binding.vis,
-                        span: binding.span,
-                        macro_rules: false,
-                    });
+        if let Some(def_id) = module.opt_def_id() {
+            let mut reexports = Vec::new();
+
+            module.for_each_child(self.r, |_, ident, _, binding| {
+                // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
+                // into the crate root to actual `NameBindingKind::Import`.
+                if binding.is_import()
+                    || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
+                {
+                    let res = binding.res().expect_non_local();
+                    // Ambiguous imports are treated as errors at this point and are
+                    // not exposed to other crates (see #36837 for more details).
+                    if res != def::Res::Err && !binding.is_ambiguity() {
+                        reexports.push(ModChild {
+                            ident,
+                            res,
+                            vis: binding.vis,
+                            span: binding.span,
+                            macro_rules: false,
+                        });
+                    }
                 }
-            }
-        });
+            });
 
-        if !reexports.is_empty() {
-            if let Some(def_id) = module.opt_def_id() {
+            if !reexports.is_empty() {
                 // Call to `expect_local` should be fine because current
                 // code is only called for local modules.
                 self.r.reexport_map.insert(def_id.expect_local(), reexports);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ced32904c0a..098b5a0c92e 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -50,7 +50,7 @@ struct BindingInfo {
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum PatternSource {
+pub enum PatternSource {
     Match,
     Let,
     For,
@@ -64,7 +64,7 @@ enum IsRepeatExpr {
 }
 
 impl PatternSource {
-    fn descr(self) -> &'static str {
+    pub fn descr(self) -> &'static str {
         match self {
             PatternSource::Match => "match binding",
             PatternSource::Let => "let binding",
@@ -2869,11 +2869,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.report_error(
                     ident.span,
                     ResolutionError::BindingShadowsSomethingUnacceptable {
-                        shadowing_binding_descr: pat_src.descr(),
+                        shadowing_binding: pat_src,
                         name: ident.name,
                         participle: if binding.is_import() { "imported" } else { "defined" },
                         article: binding.res().article(),
-                        shadowed_binding_descr: binding.res().descr(),
+                        shadowed_binding: binding.res(),
                         shadowed_binding_span: binding.span,
                     },
                 );
@@ -2885,11 +2885,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 self.report_error(
                     ident.span,
                     ResolutionError::BindingShadowsSomethingUnacceptable {
-                        shadowing_binding_descr: pat_src.descr(),
+                        shadowing_binding: pat_src,
                         name: ident.name,
                         participle: "defined",
                         article: res.article(),
-                        shadowed_binding_descr: res.descr(),
+                        shadowed_binding: res,
                         shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
                     }
                 );
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 03cb1cfcfc9..677d7036b2f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -349,10 +349,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
             err.code(rustc_errors::error_code!(E0424));
             err.span_label(span, match source {
-                PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed"
-                                   .to_string(),
-                _ => "`self` value is a keyword only available in methods with a `self` parameter"
-                     .to_string(),
+                PathSource::Pat => "`self` value is a keyword and may not be bound to variables or shadowed",
+                _ => "`self` value is a keyword only available in methods with a `self` parameter",
             });
             if let Some((fn_kind, span)) = &self.diagnostic_metadata.current_function {
                 // The current function has a `self' parameter, but we were unable to resolve
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index ed5d1165c7d..557dbecfabe 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -2539,12 +2539,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
 /// "Constrained" basically means that it appears in any type but
 /// not amongst the inputs to a projection. In other words, `<&'a
 /// T as Trait<''b>>::Foo` does not constrain `'a` or `'b`.
-fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxHashSet<LocalDefId>> {
+fn is_late_bound_map(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<&FxIndexSet<LocalDefId>> {
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let decl = tcx.hir().fn_decl_by_hir_id(hir_id)?;
     let generics = tcx.hir().get_generics(def_id)?;
 
-    let mut late_bound = FxHashSet::default();
+    let mut late_bound = FxIndexSet::default();
 
     let mut constrained_by_input = ConstrainedCollector::default();
     for arg_ty in decl.inputs {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 57384877da5..8968179c92e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -13,7 +13,6 @@
 #![feature(let_chains)]
 #![feature(let_else)]
 #![feature(never_type)]
-#![cfg_attr(bootstrap, feature(nll))]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
 #![allow(rustc::potential_query_instability)]
@@ -62,7 +61,7 @@ use tracing::debug;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportKind, ImportResolver, NameResolution};
-use late::{HasGenericParams, PathSource};
+use late::{HasGenericParams, PathSource, PatternSource};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
 use crate::access_levels::AccessLevelsVisitor;
@@ -231,11 +230,11 @@ enum ResolutionError<'a> {
     ),
     /// Error E0530: `X` bindings cannot shadow `Y`s.
     BindingShadowsSomethingUnacceptable {
-        shadowing_binding_descr: &'static str,
+        shadowing_binding: PatternSource,
         name: Symbol,
         participle: &'static str,
         article: &'static str,
-        shadowed_binding_descr: &'static str,
+        shadowed_binding: Res,
         shadowed_binding_span: Span,
     },
     /// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 99f38b3222d..0a0c674d179 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -623,9 +623,9 @@ impl<'tcx> SaveContext<'tcx> {
                 }
             },
 
-            Node::Binding(&hir::Pat {
-                kind: hir::PatKind::Binding(_, canonical_id, ..), ..
-            }) => Res::Local(canonical_id),
+            Node::Pat(&hir::Pat { kind: hir::PatKind::Binding(_, canonical_id, ..), .. }) => {
+                Res::Local(canonical_id)
+            }
 
             _ => Res::Err,
         }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 14ad1a42a7d..b7da0f22942 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -726,6 +726,7 @@ impl Default for Options {
             prints: Vec::new(),
             cg: Default::default(),
             error_format: ErrorOutputType::default(),
+            diagnostic_width: None,
             externs: Externs(BTreeMap::new()),
             crate_name: None,
             libs: Vec::new(),
@@ -1102,49 +1103,6 @@ impl CrateCheckConfig {
             .extend(atomic_values);
 
         // Target specific values
-        #[cfg(bootstrap)]
-        {
-            for target in TARGETS
-                .iter()
-                .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
-            {
-                self.values_valid
-                    .entry(sym::target_os)
-                    .or_default()
-                    .insert(Symbol::intern(&target.options.os));
-                self.values_valid
-                    .entry(sym::target_family)
-                    .or_default()
-                    .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
-                self.values_valid
-                    .entry(sym::target_arch)
-                    .or_default()
-                    .insert(Symbol::intern(&target.arch));
-                self.values_valid
-                    .entry(sym::target_endian)
-                    .or_default()
-                    .insert(Symbol::intern(&target.options.endian.as_str()));
-                self.values_valid
-                    .entry(sym::target_env)
-                    .or_default()
-                    .insert(Symbol::intern(&target.options.env));
-                self.values_valid
-                    .entry(sym::target_abi)
-                    .or_default()
-                    .insert(Symbol::intern(&target.options.abi));
-                self.values_valid
-                    .entry(sym::target_vendor)
-                    .or_default()
-                    .insert(Symbol::intern(&target.options.vendor));
-                self.values_valid
-                    .entry(sym::target_pointer_width)
-                    .or_default()
-                    .insert(sym::integer(target.pointer_width));
-            }
-        }
-
-        // Target specific values
-        #[cfg(not(bootstrap))]
         {
             const VALUES: [&Symbol; 8] = [
                 &sym::target_os,
@@ -1470,6 +1428,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
                                  never  = never colorize output",
             "auto|always|never",
         ),
+        opt::opt_s(
+            "",
+            "diagnostic-width",
+            "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
+            "WIDTH",
+        ),
         opt::multi_s(
             "",
             "remap-path-prefix",
@@ -2245,6 +2209,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let error_format = parse_error_format(matches, color, json_rendered);
 
+    let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
+        early_error(error_format, "`--diagnostic-width` must be an positive integer");
+    });
+
     let unparsed_crate_types = matches.opt_strs("crate-type");
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
         .unwrap_or_else(|e| early_error(error_format, &e));
@@ -2517,6 +2485,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         prints,
         cg,
         error_format,
+        diagnostic_width,
         externs,
         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
         crate_name,
@@ -2767,8 +2736,8 @@ pub(crate) mod dep_tracking {
     use super::{
         BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
         InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
-        OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
-        SymbolManglingVersion, TrimmedDefPaths,
+        OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
+        SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -2855,6 +2824,7 @@ pub(crate) mod dep_tracking {
         Edition,
         LinkerPluginLto,
         SplitDebuginfo,
+        SplitDwarfKind,
         StackProtector,
         SwitchWithOptPath,
         SymbolManglingVersion,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 35b55981e37..7353c1ca0e2 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -6,7 +6,7 @@
 #![feature(once_cell)]
 #![feature(option_get_or_insert_default)]
 #![feature(rustc_attrs)]
-#![cfg_attr(not(bootstrap), feature(map_many_mut))]
+#![feature(map_many_mut)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 441e1f9f6a2..8f1057b793f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -170,6 +170,7 @@ top_level_options!(
 
         test: bool [TRACKED],
         error_format: ErrorOutputType [UNTRACKED],
+        diagnostic_width: Option<usize> [UNTRACKED],
 
         /// If `Some`, enable incremental compilation, using the given
         /// directory to store intermediate results.
@@ -1245,6 +1246,8 @@ options! {
     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
         (default: no)"),
+    dump_drop_tracking_cfg: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "dump drop-tracking control-flow graph as a `.dot` file (default: no)"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "dump MIR state to file.
         `val` is used to select which passes and functions to dump. For example:
@@ -1269,6 +1272,8 @@ options! {
         computed `block` spans (one span encompassing a block's terminator and \
         all statements). If `-Z instrument-coverage` is also enabled, create \
         an additional `.html` file showing the computed coverage spans."),
+    dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
+        "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
     emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
         "emit a section containing stack size metadata (default: no)"),
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1388,6 +1393,8 @@ options! {
         "panic strategy for out-of-memory handling"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
         "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
+    diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
+        "set the current output width for diagnostic truncation"),
     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
         "support compiling tests with panic=abort (default: no)"),
     panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED],
@@ -1496,7 +1503,7 @@ options! {
         "control if mem::uninitialized and mem::zeroed panic on more UB"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
-    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
+    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED],
         "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
         (default: `split`)
 
@@ -1504,7 +1511,7 @@ options! {
                  file which is ignored by the linker
         `single`: sections which do not require relocation are written into object file but ignored
                   by the linker"),
-    split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
+    split_dwarf_inlining: bool = (true, parse_bool, [TRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
     symbol_mangling_version: Option<SymbolManglingVersion> = (None,
@@ -1514,8 +1521,6 @@ options! {
         "show extended diagnostic help (default: no)"),
     temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
         "the directory the intermediate files are written to"),
-    terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
-        "set the current terminal width"),
     // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
     // alongside query results and changes to translation options can affect diagnostics - so
     // translation options should be tracked.
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index a5ccae047fc..f31d52147b4 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -311,7 +311,7 @@ impl ParseSess {
         self.create_warning(warning).emit()
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -319,7 +319,7 @@ impl ParseSess {
         self.span_diagnostic.struct_err(msg)
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.span_diagnostic.struct_warn(msg)
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index b5058fd699a..1cccef2f64f 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -2,7 +2,7 @@ use crate::cgu_reuse_tracker::CguReuseTracker;
 use crate::code_stats::CodeStats;
 pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo};
 use crate::config::{self, CrateType, OutputType, SwitchWithOptPath};
-use crate::parse::ParseSess;
+use crate::parse::{add_feature_diagnostics, ParseSess};
 use crate::search_paths::{PathKind, SearchPath};
 use crate::{filesearch, lint};
 
@@ -280,7 +280,7 @@ impl Session {
         self.crate_types.set(crate_types).expect("`crate_types` was initialized twice")
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_warn<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -288,7 +288,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -297,7 +297,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -306,11 +306,11 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_warn_with_code(sp, msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn(msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn_with_expectation(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -318,7 +318,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn_with_expectation(msg, id)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_allow<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -326,11 +326,11 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_span_allow(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_allow(msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_expect(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -338,7 +338,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_expect(msg, id)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -346,7 +346,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.diagnostic().struct_span_err(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -356,14 +356,14 @@ impl Session {
         self.diagnostic().struct_span_err_with_code(sp, msg, code)
     }
     // FIXME: This method should be removed (every error should have an associated error code).
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_err(
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.parse_sess.struct_err(msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_err_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -371,7 +371,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         self.diagnostic().struct_err_with_code(msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_warn_with_code(
         &self,
         msg: impl Into<DiagnosticMessage>,
@@ -379,7 +379,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, ()> {
         self.diagnostic().struct_warn_with_code(msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_fatal<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -387,7 +387,7 @@ impl Session {
     ) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_span_fatal(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -396,16 +396,16 @@ impl Session {
     ) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
         self.diagnostic().struct_fatal(msg)
     }
 
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().span_fatal(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -414,11 +414,11 @@ impl Session {
     ) -> ! {
         self.diagnostic().span_fatal_with_code(sp, msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
         self.diagnostic().fatal(msg).raise()
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err_or_warn<S: Into<MultiSpan>>(
         &self,
         is_warning: bool,
@@ -431,7 +431,7 @@ impl Session {
             self.span_err(sp, msg);
         }
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -439,7 +439,7 @@ impl Session {
     ) -> ErrorGuaranteed {
         self.diagnostic().span_err(sp, msg)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn span_err_with_code<S: Into<MultiSpan>>(
         &self,
         sp: S,
@@ -448,7 +448,7 @@ impl Session {
     ) {
         self.diagnostic().span_err_with_code(sp, msg, code)
     }
-    #[cfg_attr(not(bootstrap), rustc_lint_diagnostics)]
+    #[rustc_lint_diagnostics]
     pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
         self.diagnostic().err(msg)
     }
@@ -458,6 +458,15 @@ impl Session {
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         self.parse_sess.create_err(err)
     }
+    pub fn create_feature_err<'a>(
+        &'a self,
+        err: impl SessionDiagnostic<'a>,
+        feature: Symbol,
+    ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut err = self.parse_sess.create_err(err);
+        add_feature_diagnostics(&mut err, &self.parse_sess, feature);
+        err
+    }
     pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed {
         self.parse_sess.emit_err(err)
     }
@@ -1162,7 +1171,7 @@ fn default_emitter(
                         fallback_bundle,
                         short,
                         sopts.debugging_opts.teach,
-                        sopts.debugging_opts.terminal_width,
+                        sopts.diagnostic_width,
                         macro_backtrace,
                     ),
                     Some(dst) => EmitterWriter::new(
@@ -1173,7 +1182,7 @@ fn default_emitter(
                         short,
                         false, // no teach messages when writing to a buffer
                         false, // no colors when writing to a buffer
-                        None,  // no terminal width
+                        None,  // no diagnostic width
                         macro_backtrace,
                     ),
                 };
@@ -1188,7 +1197,7 @@ fn default_emitter(
                 fallback_bundle,
                 pretty,
                 json_rendered,
-                sopts.debugging_opts.terminal_width,
+                sopts.diagnostic_width,
                 macro_backtrace,
             )
             .ui_testing(sopts.debugging_opts.ui_testing),
@@ -1202,7 +1211,7 @@ fn default_emitter(
                 fallback_bundle,
                 pretty,
                 json_rendered,
-                sopts.debugging_opts.terminal_width,
+                sopts.diagnostic_width,
                 macro_backtrace,
             )
             .ui_testing(sopts.debugging_opts.ui_testing),
@@ -1489,6 +1498,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             ))
         }
     }
+
+    if let Some(dwarf_version) = sess.opts.debugging_opts.dwarf_version {
+        if dwarf_version > 5 {
+            sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version));
+        }
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 955db72157c..3df4dfb74b3 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -629,8 +629,7 @@ pub fn debug_hygiene_data(verbose: bool) -> String {
         if verbose {
             format!("{:#?}", data)
         } else {
-            let mut s = String::from("");
-            s.push_str("Expansions:");
+            let mut s = String::from("Expansions:");
             let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
                 s.push_str(&format!(
                     "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index a329fa15320..a1f34287a5f 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1603,6 +1603,7 @@ impl SourceFile {
         self.name.is_real()
     }
 
+    #[inline]
     pub fn is_imported(&self) -> bool {
         self.src.is_none()
     }
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 227127aed50..afbb88e9233 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -597,6 +597,13 @@ impl SourceMap {
         local_begin.sf.src.is_some() && local_end.sf.src.is_some()
     }
 
+    pub fn is_span_accessible(&self, sp: Span) -> bool {
+        self.span_to_source(sp, |src, start_index, end_index| {
+            Ok(src.get(start_index..end_index).is_some())
+        })
+        .map_or(false, |is_accessible| is_accessible)
+    }
+
     /// Returns the source snippet as `String` corresponding to the given `Span`.
     pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
         self.span_to_source(sp, |src, start_index, end_index| {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4e28d2b6001..9b6967621f1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -173,6 +173,7 @@ symbols! {
         DebugTuple,
         Decodable,
         Decoder,
+        DecorateLint,
         Default,
         Deref,
         DiagnosticMessage,
@@ -785,6 +786,7 @@ symbols! {
         impl_lint_pass,
         impl_macros,
         impl_trait_in_bindings,
+        import,
         import_shadowing,
         imported_main,
         in_band_lifetimes,
@@ -1522,6 +1524,7 @@ symbols! {
         use_nested_groups,
         used,
         used_with_arg,
+        using,
         usize,
         v1,
         va_arg,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index f67b87a6a52..e3045c9321d 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -3,7 +3,7 @@ use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
 use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::util::common::record_time;
 
 use tracing::debug;
@@ -96,47 +96,48 @@ fn get_symbol_hash<'tcx>(
     let substs = instance.substs;
     debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
 
-    let mut hasher = StableHasher::new();
-    let mut hcx = tcx.create_stable_hashing_context();
-
-    record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
-        // the main symbol name is not necessarily unique; hash in the
-        // compiler's internal def-path, guaranteeing each symbol has a
-        // truly unique path
-        tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
-
-        // Include the main item-type. Note that, in this case, the
-        // assertions about `needs_subst` may not hold, but this item-type
-        // ought to be the same for every reference anyway.
-        assert!(!item_type.has_erasable_regions());
-        hcx.while_hashing_spans(false, |hcx| {
-            item_type.hash_stable(hcx, &mut hasher);
-
-            // If this is a function, we hash the signature as well.
-            // This is not *strictly* needed, but it may help in some
-            // situations, see the `run-make/a-b-a-linker-guard` test.
-            if let ty::FnDef(..) = item_type.kind() {
-                item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
-            }
+    tcx.with_stable_hashing_context(|mut hcx| {
+        let mut hasher = StableHasher::new();
+
+        record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
+            // the main symbol name is not necessarily unique; hash in the
+            // compiler's internal def-path, guaranteeing each symbol has a
+            // truly unique path
+            tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
+
+            // Include the main item-type. Note that, in this case, the
+            // assertions about `needs_subst` may not hold, but this item-type
+            // ought to be the same for every reference anyway.
+            assert!(!item_type.has_erasable_regions());
+            hcx.while_hashing_spans(false, |hcx| {
+                item_type.hash_stable(hcx, &mut hasher);
+
+                // If this is a function, we hash the signature as well.
+                // This is not *strictly* needed, but it may help in some
+                // situations, see the `run-make/a-b-a-linker-guard` test.
+                if let ty::FnDef(..) = item_type.kind() {
+                    item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
+                }
 
-            // also include any type parameters (for generic items)
-            substs.hash_stable(hcx, &mut hasher);
+                // also include any type parameters (for generic items)
+                substs.hash_stable(hcx, &mut hasher);
 
-            if let Some(instantiating_crate) = instantiating_crate {
-                tcx.def_path_hash(instantiating_crate.as_def_id())
-                    .stable_crate_id()
-                    .hash_stable(hcx, &mut hasher);
-            }
+                if let Some(instantiating_crate) = instantiating_crate {
+                    tcx.def_path_hash(instantiating_crate.as_def_id())
+                        .stable_crate_id()
+                        .hash_stable(hcx, &mut hasher);
+                }
 
-            // We want to avoid accidental collision between different types of instances.
-            // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
-            // instances without this.
-            discriminant(&instance.def).hash_stable(hcx, &mut hasher);
+                // We want to avoid accidental collision between different types of instances.
+                // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+                // instances without this.
+                discriminant(&instance.def).hash_stable(hcx, &mut hasher);
+            });
         });
-    });
 
-    // 64 bits should be enough to avoid collisions.
-    hasher.finish::<u64>()
+        // 64 bits should be enough to avoid collisions.
+        hasher.finish::<u64>()
+    })
 }
 
 // Follow C++ namespace-mangling style, see
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 1036c5d941b..13229a3995c 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::print::{Print, Printer};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{
-    self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy,
+    self, EarlyBinder, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeVisitable, UintTy,
 };
 use rustc_span::symbol::kw;
 use rustc_target::abi::call::FnAbi;
@@ -240,7 +240,7 @@ impl<'tcx> SymbolMangler<'tcx> {
         print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>,
     ) -> Result<&'a mut Self, !>
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         let regions = if value.has_late_bound_regions() {
             self.tcx.collect_referenced_late_bound_regions(value)
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index df8ccc42a77..65d2cd64bf6 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -244,18 +244,8 @@ impl FromStr for InlineAsmArch {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Encodable,
-    Decodable,
-    Debug,
-    Eq,
-    PartialEq,
-    PartialOrd,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum InlineAsmReg {
     X86(X86InlineAsmReg),
     Arm(ArmInlineAsmReg),
@@ -406,18 +396,8 @@ impl InlineAsmReg {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Encodable,
-    Decodable,
-    Debug,
-    Eq,
-    PartialEq,
-    PartialOrd,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum InlineAsmRegClass {
     X86(X86InlineAsmRegClass),
     Arm(ArmInlineAsmRegClass),
@@ -620,18 +600,8 @@ impl InlineAsmRegClass {
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Encodable,
-    Decodable,
-    Debug,
-    Eq,
-    PartialEq,
-    PartialOrd,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum InlineAsmRegOrRegClass {
     Reg(InlineAsmReg),
     RegClass(InlineAsmRegClass),
@@ -808,18 +778,8 @@ pub fn allocatable_registers(
     }
 }
 
-#[derive(
-    Copy,
-    Clone,
-    Encodable,
-    Decodable,
-    Debug,
-    Eq,
-    PartialEq,
-    PartialOrd,
-    Hash,
-    HashStable_Generic
-)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Hash)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub enum InlineAsmClobberAbi {
     X86,
     X86_64Win,
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index c2b9d696776..dc06597db6f 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -3,7 +3,7 @@ use crate::spec::TargetOptions;
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
     base.os = "android".into();
-    base.dwarf_version = Some(2);
+    base.default_dwarf_version = 2;
     base.position_independent_executables = true;
     base.has_thread_local = false;
     // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e8460a509e2..713dc9a1f0e 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -28,7 +28,7 @@ pub fn opts(os: &'static str) -> TargetOptions {
         executables: true,
         families: cvs!["unix"],
         is_like_osx: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         frame_pointer: FramePointer::Always,
         has_rpath: true,
         dll_suffix: ".dylib".into(),
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index b59322d07f5..c1e469746cb 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index a7e0f9f7041..36312d26e37 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -10,7 +10,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index a08603da040..48ccb10f214 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1275,9 +1275,9 @@ pub struct TargetOptions {
     pub is_like_msvc: bool,
     /// Whether a target toolchain is like WASM.
     pub is_like_wasm: bool,
-    /// Version of DWARF to use if not using the default.
+    /// Default supported version of DWARF on this platform.
     /// Useful because some platforms (osx, bsd) only want up to DWARF2.
-    pub dwarf_version: Option<u32>,
+    pub default_dwarf_version: u32,
     /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
@@ -1539,7 +1539,7 @@ impl Default for TargetOptions {
             is_like_windows: false,
             is_like_msvc: false,
             is_like_wasm: false,
-            dwarf_version: None,
+            default_dwarf_version: 4,
             linker_is_gnu: true,
             allows_weak_linkage: true,
             has_rpath: false,
@@ -1778,13 +1778,13 @@ impl Target {
                     base.$key_name = s;
                 }
             } );
-            ($key_name:ident, Option<u32>) => ( {
+            ($key_name:ident, u32) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.remove(&name).and_then(|b| b.as_u64()) {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".into());
                     }
-                    base.$key_name = Some(s as u32);
+                    base.$key_name = s as u32;
                 }
             } );
             ($key_name:ident, Option<u64>) => ( {
@@ -2143,7 +2143,7 @@ impl Target {
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
         key!(is_like_wasm, bool);
-        key!(dwarf_version, Option<u32>);
+        key!(default_dwarf_version, u32);
         key!(linker_is_gnu, bool);
         key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
@@ -2387,7 +2387,7 @@ impl ToJson for Target {
         target_option_val!(is_like_windows);
         target_option_val!(is_like_msvc);
         target_option_val!(is_like_wasm);
-        target_option_val!(dwarf_version);
+        target_option_val!(default_dwarf_version);
         target_option_val!(linker_is_gnu);
         target_option_val!(allows_weak_linkage);
         target_option_val!(has_rpath);
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 69016d77cf9..40ef04ba043 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -11,7 +11,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         use_ctors_section: true,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index bbd322bb6ce..51cecdd47ea 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -11,7 +11,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
         relro_level: RelroLevel::Full,
-        dwarf_version: Some(2),
+        default_dwarf_version: 2,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 5b88cff03d7..8b7e8984a8a 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt};
-use rustc_middle::ty::{ToPredicate, TypeFoldable};
+use rustc_middle::ty::{ToPredicate, TypeVisitable};
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::Span;
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index f135f0c1b13..9d30374f8b8 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -9,7 +9,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, Quer
 use rustc_middle::traits::query::Fallible;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeFoldable, TypeVisitable};
 use rustc_span::{Span, DUMMY_SP};
 
 use std::fmt::Debug;
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 44ff3fd7306..282ee632ce5 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -37,5 +37,4 @@ extern crate smallvec;
 
 pub mod autoderef;
 pub mod infer;
-pub mod opaque_types;
 pub mod traits;
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
deleted file mode 100644
index 9dd8588cece..00000000000
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ /dev/null
@@ -1,544 +0,0 @@
-use crate::traits;
-use crate::traits::error_reporting::InferCtxtExt as _;
-use crate::traits::TraitEngineExt as _;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefId;
-use rustc_hir::OpaqueTyOrigin;
-use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt as _};
-use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
-use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, ToPredicate, Ty, TyCtxt};
-use rustc_span::Span;
-
-pub trait InferCtxtExt<'tcx> {
-    fn infer_opaque_definition_from_instantiation(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        instantiated_ty: OpaqueHiddenType<'tcx>,
-        origin: OpaqueTyOrigin,
-    ) -> Ty<'tcx>;
-}
-
-impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
-    /// Given the fully resolved, instantiated type for an opaque
-    /// type, i.e., the value of an inference variable like C1 or C2
-    /// (*), computes the "definition type" for an opaque type
-    /// definition -- that is, the inferred value of `Foo1<'x>` or
-    /// `Foo2<'x>` that we would conceptually use in its definition:
-    /// ```ignore (illustrative)
-    /// type Foo1<'x> = impl Bar<'x> = AAA;  // <-- this type AAA
-    /// type Foo2<'x> = impl Bar<'x> = BBB;  // <-- or this type BBB
-    /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
-    /// ```
-    /// Note that these values are defined in terms of a distinct set of
-    /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main
-    /// purpose of this function is to do that translation.
-    ///
-    /// (*) C1 and C2 were introduced in the comments on
-    /// `register_member_constraints`. Read that comment for more context.
-    ///
-    /// # Parameters
-    ///
-    /// - `def_id`, the `impl Trait` type
-    /// - `substs`, the substs  used to instantiate this opaque type
-    /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
-    ///   `opaque_defn.concrete_ty`
-    #[instrument(level = "debug", skip(self))]
-    fn infer_opaque_definition_from_instantiation(
-        &self,
-        opaque_type_key: OpaqueTypeKey<'tcx>,
-        instantiated_ty: OpaqueHiddenType<'tcx>,
-        origin: OpaqueTyOrigin,
-    ) -> Ty<'tcx> {
-        if self.is_tainted_by_errors() {
-            return self.tcx.ty_error();
-        }
-
-        let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
-        // Use substs to build up a reverse map from regions to their
-        // identity mappings. This is necessary because of `impl
-        // Trait` lifetimes are computed by replacing existing
-        // lifetimes with 'static and remapping only those used in the
-        // `impl Trait` return type, resulting in the parameters
-        // shifting.
-        let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
-        debug!(?id_substs);
-        let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
-            substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect();
-        debug!("map = {:#?}", map);
-
-        // Convert the type from the function into a type valid outside
-        // the function, by replacing invalid regions with 'static,
-        // after producing an error for each of them.
-        let definition_ty = instantiated_ty.ty.fold_with(&mut ReverseMapper::new(
-            self.tcx,
-            def_id,
-            map,
-            instantiated_ty.ty,
-            instantiated_ty.span,
-        ));
-        debug!(?definition_ty);
-
-        if !check_opaque_type_parameter_valid(
-            self.tcx,
-            opaque_type_key,
-            origin,
-            instantiated_ty.span,
-        ) {
-            return self.tcx.ty_error();
-        }
-
-        // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
-        // on stable and we'd break that.
-        if let OpaqueTyOrigin::TyAlias = origin {
-            // This logic duplicates most of `check_opaque_meets_bounds`.
-            // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely.
-            let param_env = self.tcx.param_env(def_id);
-            let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap());
-            self.tcx.infer_ctxt().enter(move |infcx| {
-                // Require the hidden type to be well-formed with only the generics of the opaque type.
-                // Defining use functions may have more bounds than the opaque type, which is ok, as long as the
-                // hidden type is well formed even without those bounds.
-                let predicate =
-                    ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
-                        .to_predicate(infcx.tcx);
-                let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
-
-                // Require that the hidden type actually fulfills all the bounds of the opaque type, even without
-                // the bounds that the function supplies.
-                match infcx.register_hidden_type(
-                    OpaqueTypeKey { def_id, substs: id_substs },
-                    ObligationCause::misc(instantiated_ty.span, body_id),
-                    param_env,
-                    definition_ty,
-                    origin,
-                ) {
-                    Ok(infer_ok) => {
-                        for obligation in infer_ok.obligations {
-                            fulfillment_cx.register_predicate_obligation(&infcx, obligation);
-                        }
-                    }
-                    Err(err) => {
-                        infcx
-                            .report_mismatched_types(
-                                &ObligationCause::misc(instantiated_ty.span, body_id),
-                                self.tcx.mk_opaque(def_id, id_substs),
-                                definition_ty,
-                                err,
-                            )
-                            .emit();
-                    }
-                }
-
-                fulfillment_cx.register_predicate_obligation(
-                    &infcx,
-                    Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
-                );
-
-                // Check that all obligations are satisfied by the implementation's
-                // version.
-                let errors = fulfillment_cx.select_all_or_error(&infcx);
-
-                let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
-
-                if errors.is_empty() {
-                    definition_ty
-                } else {
-                    infcx.report_fulfillment_errors(&errors, None, false);
-                    self.tcx.ty_error()
-                }
-            })
-        } else {
-            definition_ty
-        }
-    }
-}
-
-fn check_opaque_type_parameter_valid(
-    tcx: TyCtxt<'_>,
-    opaque_type_key: OpaqueTypeKey<'_>,
-    origin: OpaqueTyOrigin,
-    span: Span,
-) -> bool {
-    match origin {
-        // No need to check return position impl trait (RPIT)
-        // because for type and const parameters they are correct
-        // by construction: we convert
-        //
-        // fn foo<P0..Pn>() -> impl Trait
-        //
-        // into
-        //
-        // type Foo<P0...Pn>
-        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
-        //
-        // For lifetime parameters we convert
-        //
-        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-        //
-        // into
-        //
-        // type foo::<'p0..'pn>::Foo<'q0..'qm>
-        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-        //
-        // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
-        // Check these
-        OpaqueTyOrigin::TyAlias => {}
-    }
-    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
-    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
-    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
-        let arg_is_param = match arg.unpack() {
-            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if lt.is_static() => {
-                tcx.sess
-                    .struct_span_err(span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
-                        "cannot use static lifetime; use a bound lifetime \
-                                    instead or remove the lifetime parameter from the \
-                                    opaque type",
-                    )
-                    .emit();
-                return false;
-            }
-            GenericArgKind::Lifetime(lt) => {
-                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
-            }
-            GenericArgKind::Const(ct) => matches!(ct.kind(), ty::ConstKind::Param(_)),
-        };
-
-        if arg_is_param {
-            seen_params.entry(arg).or_default().push(i);
-        } else {
-            // Prevent `fn foo() -> Foo<u32>` from being defining.
-            let opaque_param = opaque_generics.param_at(i, tcx);
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(
-                    tcx.def_span(opaque_param.def_id),
-                    &format!(
-                        "used non-generic {} `{}` for generic parameter",
-                        opaque_param.kind.descr(),
-                        arg,
-                    ),
-                )
-                .emit();
-            return false;
-        }
-    }
-
-    for (_, indices) in seen_params {
-        if indices.len() > 1 {
-            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
-            let spans: Vec<_> = indices
-                .into_iter()
-                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
-                .collect();
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(spans, &format!("{} used multiple times", descr))
-                .emit();
-            return false;
-        }
-    }
-    true
-}
-
-struct ReverseMapper<'tcx> {
-    tcx: TyCtxt<'tcx>,
-
-    opaque_type_def_id: DefId,
-    map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
-    map_missing_regions_to_empty: bool,
-
-    /// initially `Some`, set to `None` once error has been reported
-    hidden_ty: Option<Ty<'tcx>>,
-
-    /// Span of function being checked.
-    span: Span,
-}
-
-impl<'tcx> ReverseMapper<'tcx> {
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        opaque_type_def_id: DefId,
-        map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>,
-        hidden_ty: Ty<'tcx>,
-        span: Span,
-    ) -> Self {
-        Self {
-            tcx,
-            opaque_type_def_id,
-            map,
-            map_missing_regions_to_empty: false,
-            hidden_ty: Some(hidden_ty),
-            span,
-        }
-    }
-
-    fn fold_kind_mapping_missing_regions_to_empty(
-        &mut self,
-        kind: GenericArg<'tcx>,
-    ) -> GenericArg<'tcx> {
-        assert!(!self.map_missing_regions_to_empty);
-        self.map_missing_regions_to_empty = true;
-        let kind = kind.fold_with(self);
-        self.map_missing_regions_to_empty = false;
-        kind
-    }
-
-    fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> {
-        assert!(!self.map_missing_regions_to_empty);
-        kind.fold_with(self)
-    }
-}
-
-impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            // Ignore bound regions and `'static` regions that appear in the
-            // type, we only need to remap regions that reference lifetimes
-            // from the function declaration.
-            // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
-            ty::ReLateBound(..) | ty::ReStatic => return r,
-
-            // If regions have been erased (by writeback), don't try to unerase
-            // them.
-            ty::ReErased => return r,
-
-            // The regions that we expect from borrow checking.
-            ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
-
-            ty::ReEmpty(_) | ty::RePlaceholder(_) | ty::ReVar(_) => {
-                // All of the regions in the type should either have been
-                // erased by writeback, or mapped back to named regions by
-                // borrow checking.
-                bug!("unexpected region kind in opaque type: {:?}", r);
-            }
-        }
-
-        let generics = self.tcx().generics_of(self.opaque_type_def_id);
-        match self.map.get(&r.into()).map(|k| k.unpack()) {
-            Some(GenericArgKind::Lifetime(r1)) => r1,
-            Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
-            None if self.map_missing_regions_to_empty => self.tcx.lifetimes.re_root_empty,
-            None if generics.parent.is_some() => {
-                if let Some(hidden_ty) = self.hidden_ty.take() {
-                    unexpected_hidden_region_diagnostic(
-                        self.tcx,
-                        self.tcx.def_span(self.opaque_type_def_id),
-                        hidden_ty,
-                        r,
-                    )
-                    .emit();
-                }
-                self.tcx.lifetimes.re_root_empty
-            }
-            None => {
-                self.tcx
-                    .sess
-                    .struct_span_err(self.span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        self.span,
-                        format!(
-                            "lifetime `{}` is part of concrete type but not used in \
-                                 parameter list of the `impl Trait` type alias",
-                            r
-                        ),
-                    )
-                    .emit();
-
-                self.tcx().lifetimes.re_static
-            }
-        }
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        match *ty.kind() {
-            ty::Closure(def_id, substs) => {
-                // I am a horrible monster and I pray for death. When
-                // we encounter a closure here, it is always a closure
-                // from within the function that we are currently
-                // type-checking -- one that is now being encapsulated
-                // in an opaque type. Ideally, we would
-                // go through the types/lifetimes that it references
-                // and treat them just like we would any other type,
-                // which means we would error out if we find any
-                // reference to a type/region that is not in the
-                // "reverse map".
-                //
-                // **However,** in the case of closures, there is a
-                // somewhat subtle (read: hacky) consideration. The
-                // problem is that our closure types currently include
-                // all the lifetime parameters declared on the
-                // enclosing function, even if they are unused by the
-                // closure itself. We can't readily filter them out,
-                // so here we replace those values with `'empty`. This
-                // can't really make a difference to the rest of the
-                // compiler; those regions are ignored for the
-                // outlives relation, and hence don't affect trait
-                // selection or auto traits, and they are erased
-                // during codegen.
-
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_mapping_missing_regions_to_empty(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
-                self.tcx.mk_closure(def_id, substs)
-            }
-
-            ty::Generator(def_id, substs, movability) => {
-                let generics = self.tcx.generics_of(def_id);
-                let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, kind)| {
-                    if index < generics.parent_count {
-                        // Accommodate missing regions in the parent kinds...
-                        self.fold_kind_mapping_missing_regions_to_empty(kind)
-                    } else {
-                        // ...but not elsewhere.
-                        self.fold_kind_normally(kind)
-                    }
-                }));
-
-                self.tcx.mk_generator(def_id, substs, movability)
-            }
-
-            ty::Param(param) => {
-                // Look it up in the substitution list.
-                match self.map.get(&ty.into()).map(|k| k.unpack()) {
-                    // Found it in the substitution list; replace with the parameter from the
-                    // opaque type.
-                    Some(GenericArgKind::Type(t1)) => t1,
-                    Some(u) => panic!("type mapped to unexpected kind: {:?}", u),
-                    None => {
-                        debug!(?param, ?self.map);
-                        self.tcx
-                            .sess
-                            .struct_span_err(
-                                self.span,
-                                &format!(
-                                    "type parameter `{}` is part of concrete type but not \
-                                          used in parameter list for the `impl Trait` type alias",
-                                    ty
-                                ),
-                            )
-                            .emit();
-
-                        self.tcx().ty_error()
-                    }
-                }
-            }
-
-            _ => ty.super_fold_with(self),
-        }
-    }
-
-    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        trace!("checking const {:?}", ct);
-        // Find a const parameter
-        match ct.kind() {
-            ty::ConstKind::Param(..) => {
-                // Look it up in the substitution list.
-                match self.map.get(&ct.into()).map(|k| k.unpack()) {
-                    // Found it in the substitution list, replace with the parameter from the
-                    // opaque type.
-                    Some(GenericArgKind::Const(c1)) => c1,
-                    Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
-                    None => {
-                        self.tcx
-                            .sess
-                            .struct_span_err(
-                                self.span,
-                                &format!(
-                                    "const parameter `{}` is part of concrete type but not \
-                                          used in parameter list for the `impl Trait` type alias",
-                                    ct
-                                ),
-                            )
-                            .emit();
-
-                        self.tcx().const_error(ct.ty())
-                    }
-                }
-            }
-
-            _ => ct,
-        }
-    }
-}
-
-/// Given a set of predicates that apply to an object type, returns
-/// the region bounds that the (erased) `Self` type must
-/// outlive. Precisely *because* the `Self` type is erased, the
-/// parameter `erased_self_ty` must be supplied to indicate what type
-/// has been used to represent `Self` in the predicates
-/// themselves. This should really be a unique type; `FreshTy(0)` is a
-/// popular choice.
-///
-/// N.B., in some cases, particularly around higher-ranked bounds,
-/// this function returns a kind of conservative approximation.
-/// That is, all regions returned by this function are definitely
-/// required, but there may be other region bounds that are not
-/// returned, as well as requirements like `for<'a> T: 'a`.
-///
-/// Requires that trait definitions have been processed so that we can
-/// elaborate predicates and walk supertraits.
-#[instrument(skip(tcx, predicates), level = "debug")]
-pub(crate) fn required_region_bounds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    erased_self_ty: Ty<'tcx>,
-    predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
-) -> Vec<ty::Region<'tcx>> {
-    assert!(!erased_self_ty.has_escaping_bound_vars());
-
-    traits::elaborate_predicates(tcx, predicates)
-        .filter_map(|obligation| {
-            debug!(?obligation);
-            match obligation.predicate.kind().skip_binder() {
-                ty::PredicateKind::Projection(..)
-                | ty::PredicateKind::Trait(..)
-                | ty::PredicateKind::Subtype(..)
-                | ty::PredicateKind::Coerce(..)
-                | ty::PredicateKind::WellFormed(..)
-                | ty::PredicateKind::ObjectSafe(..)
-                | ty::PredicateKind::ClosureKind(..)
-                | ty::PredicateKind::RegionOutlives(..)
-                | ty::PredicateKind::ConstEvaluatable(..)
-                | ty::PredicateKind::ConstEquate(..)
-                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
-                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
-                    // Search for a bound of the form `erased_self_ty
-                    // : 'a`, but be wary of something like `for<'a>
-                    // erased_self_ty : 'a` (we interpret a
-                    // higher-ranked bound like that as 'static,
-                    // though at present the code in `fulfill.rs`
-                    // considers such bounds to be unsatisfiable, so
-                    // it's kind of a moot point since you could never
-                    // construct such an object, but this seems
-                    // correct even if that code changes).
-                    if t == &erased_self_ty && !r.has_escaping_bound_vars() {
-                        Some(*r)
-                    } else {
-                        None
-                    }
-                }
-            }
-        })
-        .collect()
-}
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 90ff07cba02..65ff9ceb67e 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -8,6 +8,7 @@ use crate::infer::InferCtxt;
 use crate::traits::project::ProjectAndUnifyResult;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{Region, RegionVid, Term};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -212,15 +213,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                 panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
             }
 
-            let body_id_map: FxHashMap<_, _> = infcx
-                .inner
-                .borrow()
-                .region_obligations()
-                .iter()
-                .map(|&(id, _)| (id, vec![]))
-                .collect();
-
-            infcx.process_registered_region_obligations(&body_id_map, full_env);
+            infcx.process_registered_region_obligations(&Default::default(), full_env);
 
             let region_data = infcx
                 .inner
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index 592b0ab477a..9ef7ac9a8e0 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -8,7 +8,7 @@ use crate::traits::{
     PredicateObligation, SelectionError, TraitEngine,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 2b26b916d32..52ca23c4b30 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -13,16 +13,15 @@ use crate::traits::{
     self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
     PredicateObligations, SelectionContext,
 };
-//use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_hir::CRATE_HIR_ID;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, TraitEngine};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
@@ -45,7 +44,7 @@ pub enum Conflict {
 
 pub struct OverlapResult<'tcx> {
     pub impl_header: ty::ImplHeader<'tcx>,
-    pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+    pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
 
     /// `true` if the overlap might've been permitted before the shift
     /// to universes.
@@ -317,14 +316,13 @@ fn negative_impl<'cx, 'tcx>(
         let (subject2, obligations) =
             impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
 
-        !equate(&infcx, impl_env, impl1_def_id, subject1, subject2, obligations)
+        !equate(&infcx, impl_env, subject1, subject2, obligations)
     })
 }
 
 fn equate<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     impl_env: ty::ParamEnv<'tcx>,
-    impl1_def_id: DefId,
     subject1: ImplSubject<'tcx>,
     subject2: ImplSubject<'tcx>,
     obligations: impl Iterator<Item = PredicateObligation<'tcx>>,
@@ -341,7 +339,7 @@ fn equate<'cx, 'tcx>(
     let opt_failing_obligation = obligations
         .into_iter()
         .chain(more_obligations)
-        .find(|o| negative_impl_exists(selcx, impl_env, impl1_def_id, o));
+        .find(|o| negative_impl_exists(selcx, impl_env, o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
         debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -356,18 +354,17 @@ fn equate<'cx, 'tcx>(
 fn negative_impl_exists<'cx, 'tcx>(
     selcx: &SelectionContext<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    region_context: DefId,
     o: &PredicateObligation<'tcx>,
 ) -> bool {
     let infcx = &selcx.infcx().fork();
 
-    if resolve_negative_obligation(infcx, param_env, region_context, o) {
+    if resolve_negative_obligation(infcx, param_env, o) {
         return true;
     }
 
     // Try to prove a negative obligation exists for super predicates
     for o in util::elaborate_predicates(infcx.tcx, iter::once(o.predicate)) {
-        if resolve_negative_obligation(infcx, param_env, region_context, &o) {
+        if resolve_negative_obligation(infcx, param_env, &o) {
             return true;
         }
     }
@@ -379,7 +376,6 @@ fn negative_impl_exists<'cx, 'tcx>(
 fn resolve_negative_obligation<'cx, 'tcx>(
     infcx: &InferCtxt<'cx, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    region_context: DefId,
     o: &PredicateObligation<'tcx>,
 ) -> bool {
     let tcx = infcx.tcx;
@@ -397,19 +393,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
         return false;
     }
 
-    let mut outlives_env = OutlivesEnvironment::new(param_env);
-    // FIXME -- add "assumed to be well formed" types into the `outlives_env`
-
-    // "Save" the accumulated implied bounds into the outlives environment
-    // (due to the FIXME above, there aren't any, but this step is still needed).
-    // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used
-    // by the "dummy" causes elsewhere (body-id is only relevant when checking
-    // function bodies with closures).
-    outlives_env.save_implied_bounds(CRATE_HIR_ID);
-
-    infcx.process_registered_region_obligations(outlives_env.region_bound_pairs_map(), param_env);
+    // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
+    let outlives_env = OutlivesEnvironment::new(param_env);
+    infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
 
-    let errors = infcx.resolve_regions(region_context, &outlives_env);
+    let errors = infcx.resolve_regions(&outlives_env);
 
     if !errors.is_empty() {
         return false;
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 424eff2f621..3a152eff485 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -17,7 +17,7 @@ use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInpu
 use rustc_middle::thir;
 use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DelaySpanBugEmitted, EarlyBinder, TyCtxt, TypeVisitable};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
@@ -451,6 +451,10 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 let val = ty::ValTree::from_scalar_int(lit);
                 self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
             }
+            &ExprKind::ZstLiteral { user_ty: _ } => {
+                let val = ty::ValTree::zst();
+                self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
+            }
             &ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
                 let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index fa56219b409..34f4a9f7902 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -23,13 +23,14 @@ use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
 use rustc_infer::infer::error_reporting::same_type_modulo_infer;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::{AmbiguousSelection, TraitEngine};
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{
     self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
+    TypeVisitable,
 };
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{ExpnKind, Span, DUMMY_SP};
@@ -672,6 +673,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             if !self.report_similar_impl_candidates(
                                 impl_candidates,
                                 trait_ref,
+                                obligation.cause.body_id,
                                 &mut err,
                             ) {
                                 // This is *almost* equivalent to
@@ -706,6 +708,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                     self.report_similar_impl_candidates(
                                         impl_candidates,
                                         trait_ref,
+                                        obligation.cause.body_id,
                                         &mut err,
                                     );
                                 }
@@ -1111,18 +1114,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     })
                     .collect::<Option<Vec<ArgKind>>>()?,
             ),
-            Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. })
-            | Node::ImplItem(&hir::ImplItem {
-                span,
-                kind: hir::ImplItemKind::Fn(ref sig, _),
-                ..
-            })
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref sig, ..), .. })
+            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, _), .. })
             | Node::TraitItem(&hir::TraitItem {
-                span,
-                kind: hir::TraitItemKind::Fn(ref sig, _),
-                ..
+                kind: hir::TraitItemKind::Fn(ref sig, _), ..
             }) => (
-                sm.guess_head_span(span),
+                sig.span,
                 sig.decl
                     .inputs
                     .iter()
@@ -1137,7 +1134,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ),
             Node::Ctor(ref variant_data) => {
                 let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
-                let span = sm.guess_head_span(span);
                 (span, vec![ArgKind::empty(); variant_data.fields().len()])
             }
             _ => panic!("non-FnLike node found: {:?}", node),
@@ -1359,6 +1355,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
         &self,
         impl_candidates: Vec<ImplCandidate<'tcx>>,
         trait_ref: ty::PolyTraitRef<'tcx>,
+        body_id: hir::HirId,
         err: &mut Diagnostic,
     ) -> bool;
 
@@ -1410,7 +1407,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
     fn annotate_source_of_ambiguity(
         &self,
         err: &mut Diagnostic,
-        impls: &[DefId],
+        impls: &[AmbiguousSelection],
         predicate: ty::Predicate<'tcx>,
     );
 
@@ -1741,6 +1738,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         impl_candidates: Vec<ImplCandidate<'tcx>>,
         trait_ref: ty::PolyTraitRef<'tcx>,
+        body_id: hir::HirId,
         err: &mut Diagnostic,
     ) -> bool {
         let report = |mut candidates: Vec<TraitRef<'tcx>>, err: &mut Diagnostic| {
@@ -1811,8 +1809,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         || self.tcx.is_builtin_derive(def_id)
                 })
                 .filter_map(|def_id| self.tcx.impl_trait_ref(def_id))
-                // Avoid mentioning type parameters.
-                .filter(|trait_ref| !matches!(trait_ref.self_ty().kind(), ty::Param(_)))
+                .filter(|trait_ref| {
+                    let self_ty = trait_ref.self_ty();
+                    // Avoid mentioning type parameters.
+                    if let ty::Param(_) = self_ty.kind() {
+                        false
+                    }
+                    // Avoid mentioning types that are private to another crate
+                    else if let ty::Adt(def, _) = self_ty.peel_refs().kind() {
+                        // FIXME(compiler-errors): This could be generalized, both to
+                        // be more granular, and probably look past other `#[fundamental]`
+                        // types, too.
+                        self.tcx
+                            .visibility(def.did())
+                            .is_accessible_from(body_id.owner.to_def_id(), self.tcx)
+                    } else {
+                        true
+                    }
+                })
                 .collect();
             return report(normalized_impl_candidates, err);
         }
@@ -1980,7 +1994,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                             body_id,
                             span,
                             trait_ref.self_ty().skip_binder().into(),
-                            vec![],
                             ErrorCode::E0282,
                             false,
                         )
@@ -2005,19 +2018,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 let subst = data.trait_ref.substs.iter().find(|s| s.has_infer_types_or_consts());
 
                 let mut err = if let Some(subst) = subst {
-                    let impl_candidates = self
-                        .find_similar_impl_candidates(trait_ref)
-                        .into_iter()
-                        .map(|candidate| candidate.trait_ref)
-                        .collect();
-                    self.emit_inference_failure_err(
-                        body_id,
-                        span,
-                        subst,
-                        impl_candidates,
-                        ErrorCode::E0283,
-                        true,
-                    )
+                    self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283, true)
                 } else {
                     struct_span_err!(
                         self.tcx.sess,
@@ -2039,6 +2040,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 );
                 match selcx.select_from_obligation(&obligation) {
                     Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+                        if self.is_tainted_by_errors() && subst.is_none() {
+                            // If `subst.is_none()`, then this is probably two param-env
+                            // candidates or impl candidates that are equal modulo lifetimes.
+                            // Therefore, if we've already emitted an error, just skip this
+                            // one, since it's not particularly actionable.
+                            err.cancel();
+                            return;
+                        }
                         self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
                     }
                     _ => {
@@ -2117,7 +2126,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                     return;
                 }
 
-                self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282, false)
+                self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282, false)
             }
 
             ty::PredicateKind::Subtype(data) => {
@@ -2131,14 +2140,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                 let SubtypePredicate { a_is_expected: _, a, b } = data;
                 // both must be type variables, or the other would've been instantiated
                 assert!(a.is_ty_var() && b.is_ty_var());
-                self.emit_inference_failure_err(
-                    body_id,
-                    span,
-                    a.into(),
-                    vec![],
-                    ErrorCode::E0282,
-                    true,
-                )
+                self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282, true)
             }
             ty::PredicateKind::Projection(data) => {
                 if predicate.references_error() || self.is_tainted_by_errors() {
@@ -2155,7 +2157,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                         body_id,
                         span,
                         subst,
-                        vec![],
                         ErrorCode::E0284,
                         true,
                     );
@@ -2197,24 +2198,35 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
     fn annotate_source_of_ambiguity(
         &self,
         err: &mut Diagnostic,
-        impls: &[DefId],
+        impls: &[AmbiguousSelection],
         predicate: ty::Predicate<'tcx>,
     ) {
         let mut spans = vec![];
         let mut crates = vec![];
         let mut post = vec![];
-        for def_id in impls {
-            match self.tcx.span_of_impl(*def_id) {
-                Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
-                Err(name) => {
-                    crates.push(name);
-                    if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
-                        post.push(header);
+        let mut or_where_clause = false;
+        for ambig in impls {
+            match ambig {
+                AmbiguousSelection::Impl(def_id) => match self.tcx.span_of_impl(*def_id) {
+                    Ok(span) => spans.push(span),
+                    Err(name) => {
+                        crates.push(name);
+                        if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+                            post.push(header);
+                        }
                     }
+                },
+                AmbiguousSelection::ParamEnv(span) => {
+                    or_where_clause = true;
+                    spans.push(*span);
                 }
             }
         }
-        let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+        let msg = format!(
+            "multiple `impl`s{} satisfying `{}` found",
+            if or_where_clause { " or `where` clauses" } else { "" },
+            predicate
+        );
         let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
         crate_names.sort();
         crate_names.dedup();
@@ -2552,8 +2564,7 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(
     spans: Vec<(Span, Option<hir::HirId>)>,
 ) {
     assert!(type_def_id.is_local());
-    let span = tcx.hir().span_if_local(type_def_id).unwrap();
-    let span = tcx.sess.source_map().guess_head_span(span);
+    let span = tcx.def_span(type_def_id);
     let path = tcx.def_path_str(type_def_id);
     let mut err =
         struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
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 a8be6f74c99..33585de6001 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -24,7 +24,7 @@ use rustc_middle::hir::map;
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable,
-    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_session::Limit;
@@ -777,6 +777,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             Ok(
                 EvaluationResult::EvaluatedToOk
                 | EvaluationResult::EvaluatedToOkModuloRegions
+                | EvaluationResult::EvaluatedToOkModuloOpaqueTypes
                 | EvaluationResult::EvaluatedToAmbig,
             ) => {}
             _ => return false,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index d61166437d7..78600652254 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -10,7 +10,7 @@ use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
-use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable};
 use std::marker::PhantomData;
 
 use super::const_evaluatable;
@@ -131,8 +131,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
         let _enter = span.enter();
 
-        let mut errors = Vec::new();
-
         // Process pending obligations.
         let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor {
             selcx,
@@ -142,7 +140,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         // FIXME: if we kept the original cache key, we could mark projection
         // obligations as complete for the projection cache here.
 
-        errors.extend(outcome.errors.into_iter().map(to_fulfillment_error));
+        let errors: Vec<FulfillmentError<'tcx>> =
+            outcome.errors.into_iter().map(to_fulfillment_error).collect();
 
         debug!(
             "select({} predicates remaining, {} errors) done",
@@ -728,7 +727,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 }
                 return ProcessResult::Changed(vec![]);
             } else {
-                tracing::debug!("Does NOT hold: {:?}", obligation);
+                debug!("Does NOT hold: {:?}", obligation);
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index f04f527ccb7..dd2769c7186 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -5,7 +5,7 @@ use crate::traits::{self, ObligationCause};
 
 use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 
 use crate::traits::error_reporting::InferCtxtExt;
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 34b0f431b8e..74d2eb17b6b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -32,6 +32,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
 use rustc_span::{sym, Span};
 use smallvec::SmallVec;
@@ -198,17 +199,13 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
     }
 }
 
+#[instrument(level = "debug", skip(tcx, elaborated_env))]
 fn do_normalize_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
-    region_context: DefId,
     cause: ObligationCause<'tcx>,
     elaborated_env: ty::ParamEnv<'tcx>,
     predicates: Vec<ty::Predicate<'tcx>>,
 ) -> Result<Vec<ty::Predicate<'tcx>>, ErrorGuaranteed> {
-    debug!(
-        "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})",
-        predicates, region_context, cause,
-    );
     let span = cause.span;
     tcx.infer_ctxt().enter(|infcx| {
         // FIXME. We should really... do something with these region
@@ -240,7 +237,7 @@ fn do_normalize_predicates<'tcx>(
         // cares about declarations like `'a: 'b`.
         let outlives_env = OutlivesEnvironment::new(elaborated_env);
 
-        infcx.resolve_regions_and_report_errors(region_context, &outlives_env);
+        infcx.resolve_regions_and_report_errors(&outlives_env);
 
         let predicates = match infcx.fully_resolve(predicates) {
             Ok(predicates) => predicates,
@@ -269,9 +266,9 @@ fn do_normalize_predicates<'tcx>(
 
 // FIXME: this is gonna need to be removed ...
 /// Normalizes the parameter environment, reporting errors if they occur.
+#[instrument(level = "debug", skip(tcx))]
 pub fn normalize_param_env_or_error<'tcx>(
     tcx: TyCtxt<'tcx>,
-    region_context: DefId,
     unnormalized_env: ty::ParamEnv<'tcx>,
     cause: ObligationCause<'tcx>,
 ) -> ty::ParamEnv<'tcx> {
@@ -289,12 +286,6 @@ pub fn normalize_param_env_or_error<'tcx>(
     // parameter environments once for every fn as it goes,
     // and errors will get reported then; so outside of type inference we
     // can be sure that no errors should occur.
-
-    debug!(
-        "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})",
-        region_context, unnormalized_env, cause
-    );
-
     let mut predicates: Vec<_> =
         util::elaborate_predicates(tcx, unnormalized_env.caller_bounds().into_iter())
             .map(|obligation| obligation.predicate)
@@ -338,7 +329,6 @@ pub fn normalize_param_env_or_error<'tcx>(
     );
     let Ok(non_outlives_predicates) = do_normalize_predicates(
         tcx,
-        region_context,
         cause.clone(),
         elaborated_env,
         predicates,
@@ -362,7 +352,6 @@ pub fn normalize_param_env_or_error<'tcx>(
     );
     let Ok(outlives_predicates) = do_normalize_predicates(
         tcx,
-        region_context,
         cause,
         outlives_env,
         outlives_predicates,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 8d344591915..ac1811244ca 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -19,7 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_middle::ty::{Predicate, ToPredicate};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
@@ -731,7 +731,7 @@ fn receiver_is_dispatchable<'tcx>(
     })
 }
 
-fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
+fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<'tcx>>(
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
     value: T,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index aba4f144d4b..b3e7fbb3578 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -29,8 +29,9 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::traits::select::OverflowError;
-use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
 use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -359,7 +360,7 @@ where
     result
 }
 
-pub(crate) fn needs_normalization<'tcx, T: TypeFoldable<'tcx>>(value: &T, reveal: Reveal) -> bool {
+pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<'tcx>>(value: &T, reveal: Reveal) -> bool {
     match reveal {
         Reveal::UserFacing => value
             .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 25cc6e9f9f2..aad3c37f84e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -1,73 +1,7 @@
-use crate::infer::at::At;
-use crate::infer::canonical::OriginalQueryValues;
-use crate::infer::InferOk;
-
-use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 
-pub trait AtExt<'tcx> {
-    fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>>;
-}
-
-impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
-    /// Given a type `ty` of some value being dropped, computes a set
-    /// of "kinds" (types, regions) that must be outlive the execution
-    /// of the destructor. These basically correspond to data that the
-    /// destructor might access. This is used during regionck to
-    /// impose "outlives" constraints on any lifetimes referenced
-    /// within.
-    ///
-    /// The rules here are given by the "dropck" RFCs, notably [#1238]
-    /// and [#1327]. This is a fixed-point computation, where we
-    /// explore all the data that will be dropped (transitively) when
-    /// a value of type `ty` is dropped. For each type T that will be
-    /// dropped and which has a destructor, we must assume that all
-    /// the types/regions of T are live during the destructor, unless
-    /// they are marked with a special attribute (`#[may_dangle]`).
-    ///
-    /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
-    /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
-    fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> {
-        debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,);
-
-        // Quick check: there are a number of cases that we know do not require
-        // any destructor.
-        let tcx = self.infcx.tcx;
-        if trivial_dropck_outlives(tcx, ty) {
-            return InferOk { value: vec![], obligations: vec![] };
-        }
-
-        let mut orig_values = OriginalQueryValues::default();
-        let c_ty = self.infcx.canonicalize_query(self.param_env.and(ty), &mut orig_values);
-        let span = self.cause.span;
-        debug!("c_ty = {:?}", c_ty);
-        if let Ok(result) = tcx.dropck_outlives(c_ty)
-            && result.is_proven()
-            && let Ok(InferOk { value, obligations }) =
-                self.infcx.instantiate_query_response_and_region_obligations(
-                    self.cause,
-                    self.param_env,
-                    &orig_values,
-                    result,
-                )
-        {
-            let ty = self.infcx.resolve_vars_if_possible(ty);
-            let kinds = value.into_kinds_reporting_overflows(tcx, span, ty);
-            return InferOk { value: kinds, obligations };
-        }
-
-        // Errors and ambiguity in dropck occur in two cases:
-        // - unresolved inference variables at the end of typeck
-        // - non well-formed types where projections cannot be resolved
-        // Either of these should have created an error before.
-        tcx.sess.delay_span_bug(span, "dtorck encountered internal error");
-
-        InferOk { value: vec![], obligations: vec![] }
-    }
-}
-
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
 /// outlive. This is similar but not *quite* the same as the
@@ -79,6 +13,8 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
 ///
 /// Note also that `needs_drop` requires a "global" type (i.e., one
 /// with erased regions), but this function does not.
+///
+// FIXME(@lcnr): remove this module and move this function somewhere else.
 pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
         // None of these types have a destructor and hence they do not
@@ -105,7 +41,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
 
         // (T1..Tn) and closures have same properties as T1..Tn --
-        // check if *any* of those are trivial.
+        // check if *all* of them are trivial.
         ty::Tuple(tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t)),
         ty::Closure(_, ref substs) => {
             trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 7f15b683fda..eccfb3477b9 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -14,6 +14,7 @@ use rustc_infer::traits::Normalized;
 use rustc_middle::mir;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
 
 use std::ops::ControlFlow;
@@ -108,7 +109,7 @@ struct MaxEscapingBoundVarVisitor {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
-    fn visit_binder<T: TypeFoldable<'tcx>>(
+    fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 605c9ace5ed..c9d46b2810d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -95,7 +95,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
         infcx.tcx,
         region_obligations
             .iter()
-            .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
+            .map(|r_o| (r_o.sup_type, r_o.sub_region))
             .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)),
         &region_constraint_data,
     );
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 46d6e973d4c..2a3319f0f26 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -3,7 +3,7 @@ use crate::traits::query::Fallible;
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct ImpliedOutlivesBounds<'tcx> {
     pub ty: Ty<'tcx>,
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 82f147f8143..b63382429d0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -3,7 +3,7 @@ use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutli
 use crate::traits::query::Fallible;
 use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
 pub struct DropckOutlives<'tcx> {
     dropped_ty: Ty<'tcx>,
 }
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 cfd50c1afb9..96d83deeeb7 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -6,13 +6,15 @@
 //!
 //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
 use hir::LangItem;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::util::elaborate_predicates_with_span;
+use rustc_infer::traits::{AmbiguousSelection, TraitEngine};
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
 use rustc_target::spec::abi::Abi;
 
 use crate::traits;
@@ -108,7 +110,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
                         };
                         debug!(?cause, "evaluate_stack: pushing cause");
-                        self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                        self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
                     }
                 }
             }
@@ -199,11 +201,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     // and report ambiguity.
                     if i > 1 {
                         debug!("multiple matches, ambig");
+
+                        // Collect a list of (probable) spans that point to a param-env candidate
+                        let tcx = self.infcx.tcx;
+                        let owner = stack.obligation.cause.body_id.owner.to_def_id();
+                        let predicates = tcx.predicates_of(owner).instantiate_identity(tcx);
+                        let param_env_spans: FxHashMap<_, _> = elaborate_predicates_with_span(
+                            tcx,
+                            std::iter::zip(predicates.predicates, predicates.spans),
+                        )
+                        .filter_map(|obligation| {
+                            let kind = obligation.predicate.kind();
+                            if let ty::PredicateKind::Trait(trait_pred) = kind.skip_binder() {
+                                if trait_pred.trait_ref
+                                    == ty::TraitRef::identity(tcx, trait_pred.def_id())
+                                        .skip_binder()
+                                {
+                                    // HACK: Remap the `Self: Trait` predicate that every trait has to a more useful span
+                                    Some((
+                                        kind.rebind(trait_pred),
+                                        tcx.def_span(trait_pred.def_id()),
+                                    ))
+                                } else {
+                                    Some((kind.rebind(trait_pred), obligation.cause.span))
+                                }
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
+
                         return Err(Ambiguous(
                             candidates
                                 .into_iter()
                                 .filter_map(|c| match c.candidate {
-                                    SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+                                    SelectionCandidate::ImplCandidate(def_id) => {
+                                        Some(AmbiguousSelection::Impl(def_id))
+                                    }
+                                    SelectionCandidate::ParamCandidate(predicate) => {
+                                        Some(AmbiguousSelection::ParamEnv(
+                                            *param_env_spans.get(&predicate)?,
+                                        ))
+                                    }
                                     _ => None,
                                 })
                                 .collect(),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4223cdb5dbb..2bb53a466ca 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -24,7 +24,7 @@ use crate::traits::error_reporting::InferCtxtExt;
 use crate::traits::project::ProjectAndUnifyResult;
 use crate::traits::project::ProjectionCacheKeyExt;
 use crate::traits::ProjectionCacheKey;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
@@ -39,7 +39,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
-use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
 use rustc_span::symbol::sym;
 
 use std::cell::{Cell, RefCell};
@@ -52,7 +52,7 @@ pub use rustc_middle::traits::select::*;
 mod candidate_assembly;
 mod confirmation;
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
 pub enum IntercrateAmbiguityCause {
     DownstreamCrate { trait_desc: String, self_desc: Option<String> },
     UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> },
@@ -128,7 +128,7 @@ pub struct SelectionContext<'cx, 'tcx> {
     /// We don't do his until we detect a coherence error because it can
     /// lead to false overflow results (#47139) and because always
     /// computing it may negatively impact performance.
-    intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
+    intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>,
 
     /// The mode that trait queries run in, which informs our error handling
     /// policy. In essence, canonicalized queries need their errors propagated
@@ -254,14 +254,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
         assert!(self.intercrate);
         assert!(self.intercrate_ambiguity_causes.is_none());
-        self.intercrate_ambiguity_causes = Some(vec![]);
+        self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
     }
 
     /// Gets the intercrate ambiguity causes collected since tracking
     /// was enabled and disables tracking at the same time. If
     /// tracking is not enabled, just returns an empty vector.
-    pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+    pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> {
         assert!(self.intercrate);
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
@@ -394,6 +394,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Err(_) => return Ok(EvaluatedToErr),
             }
 
+            if self.infcx.opaque_types_added_in_snapshot(snapshot) {
+                return Ok(result.max(EvaluatedToOkModuloOpaqueTypes));
+            }
+
             match self.infcx.region_constraints_added_in_snapshot(snapshot) {
                 None => Ok(result),
                 Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)),
@@ -956,7 +960,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             });
 
                             debug!(?cause, "evaluate_stack: pushing cause");
-                            self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+                            self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause);
                         }
                     }
                 }
@@ -1248,7 +1252,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                  reservation impl ambiguity on {:?}",
                             def_id
                         );
-                        intercrate_ambiguity_clauses.push(
+                        intercrate_ambiguity_clauses.insert(
                             IntercrateAmbiguityCause::ReservationImpl {
                                 message: value.to_string(),
                             },
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index a1861529b59..2c4a453aefc 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -15,10 +15,9 @@ use specialization_graph::GraphExt;
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, EmissionGuarantee};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
+use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::{self, ImplSubject, TyCtxt};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
@@ -34,7 +33,7 @@ pub struct OverlapError {
     pub with_impl: DefId,
     pub trait_desc: String,
     pub self_desc: Option<String>,
-    pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+    pub intercrate_ambiguity_causes: FxIndexSet<IntercrateAmbiguityCause>,
     pub involves_placeholder: bool,
 }
 
@@ -341,10 +340,7 @@ fn report_negative_positive_conflict(
     positive_impl_def_id: DefId,
     sg: &mut specialization_graph::Graph,
 ) {
-    let impl_span = tcx
-        .sess
-        .source_map()
-        .guess_head_span(tcx.span_of_impl(local_impl_def_id.to_def_id()).unwrap());
+    let impl_span = tcx.def_span(local_impl_def_id);
 
     let mut err = struct_span_err!(
         tcx.sess,
@@ -357,10 +353,7 @@ fn report_negative_positive_conflict(
 
     match tcx.span_of_impl(negative_impl_def_id) {
         Ok(span) => {
-            err.span_label(
-                tcx.sess.source_map().guess_head_span(span),
-                "negative implementation here".to_string(),
-            );
+            err.span_label(span, "negative implementation here");
         }
         Err(cname) => {
             err.note(&format!("negative implementation in crate `{}`", cname));
@@ -369,10 +362,7 @@ fn report_negative_positive_conflict(
 
     match tcx.span_of_impl(positive_impl_def_id) {
         Ok(span) => {
-            err.span_label(
-                tcx.sess.source_map().guess_head_span(span),
-                "positive implementation here".to_string(),
-            );
+            err.span_label(span, "positive implementation here");
         }
         Err(cname) => {
             err.note(&format!("positive implementation in crate `{}`", cname));
@@ -389,8 +379,7 @@ fn report_conflicting_impls(
     used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
     sg: &mut specialization_graph::Graph,
 ) {
-    let impl_span =
-        tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap());
+    let impl_span = tcx.def_span(impl_def_id);
 
     // Work to be done after we've built the DiagnosticBuilder. We have to define it
     // now because the struct_lint methods don't return back the DiagnosticBuilder
@@ -417,10 +406,7 @@ fn report_conflicting_impls(
         let mut err = err.build(&msg);
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
-                err.span_label(
-                    tcx.sess.source_map().guess_head_span(span),
-                    "first implementation here".to_string(),
-                );
+                err.span_label(span, "first implementation here");
 
                 err.span_label(
                     impl_span,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index 930c80e0abb..fcb73b43fa8 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -4,7 +4,7 @@ use crate::traits;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 
 pub use rustc_middle::traits::specialization_graph::*;
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index bc2ce31df6d..6c0b83fbd03 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::Span;
 use std::ops::ControlFlow;
 
@@ -26,6 +26,7 @@ pub enum NonStructuralMatchTyKind<'tcx> {
     Closure,
     Generator,
     Projection,
+    Float,
 }
 
 /// This method traverses the structure of `ty`, trying to find an
@@ -53,15 +54,16 @@ pub enum NonStructuralMatchTyKind<'tcx> {
 /// For more background on why Rust has this requirement, and issues
 /// that arose when the requirement was not enforced completely, see
 /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
+///
+/// The floats_allowed flag is used to deny constants in floating point
 pub fn search_for_structural_match_violation<'tcx>(
     span: Span,
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
+    floats_allowed: bool,
 ) -> Option<NonStructuralMatchTy<'tcx>> {
-    // FIXME: we should instead pass in an `infcx` from the outside.
-    tcx.infer_ctxt().enter(|infcx| {
-        ty.visit_with(&mut Search { infcx, span, seen: FxHashSet::default() }).break_value()
-    })
+    ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default(), floats_allowed })
+        .break_value()
 }
 
 /// This method returns true if and only if `adt_ty` itself has been marked as
@@ -114,27 +116,25 @@ fn type_marked_structural<'tcx>(
 /// This implements the traversal over the structure of a given type to try to
 /// find instances of ADTs (specifically structs or enums) that do not implement
 /// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
-struct Search<'a, 'tcx> {
+struct Search<'tcx> {
     span: Span,
 
-    infcx: InferCtxt<'a, 'tcx>,
+    tcx: TyCtxt<'tcx>,
 
     /// Tracks ADTs previously encountered during search, so that
     /// we will not recur on them again.
     seen: FxHashSet<hir::def_id::DefId>,
-}
 
-impl<'a, 'tcx> Search<'a, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
+    floats_allowed: bool,
+}
 
+impl<'tcx> Search<'tcx> {
     fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
-        adt_ty.is_structural_eq_shallow(self.tcx())
+        adt_ty.is_structural_eq_shallow(self.tcx)
     }
 }
 
-impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
+impl<'tcx> TypeVisitor<'tcx> for Search<'tcx> {
     type BreakTy = NonStructuralMatchTy<'tcx>;
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -193,19 +193,30 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 return ControlFlow::CONTINUE;
             }
             ty::Array(_, n)
-                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
+                if { n.try_eval_usize(self.tcx, ty::ParamEnv::reveal_all()) == Some(0) } =>
             {
                 // rust-lang/rust#62336: ignore type of contents
                 // for empty array.
                 return ControlFlow::CONTINUE;
             }
-            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
+            ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Str | ty::Never => {
                 // These primitive types are always structural match.
                 //
                 // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                 return ControlFlow::CONTINUE;
             }
 
+            ty::Float(_) => {
+                if self.floats_allowed {
+                    return ControlFlow::CONTINUE;
+                } else {
+                    return ControlFlow::Break(NonStructuralMatchTy {
+                        ty,
+                        kind: NonStructuralMatchTyKind::Float,
+                    });
+                }
+            }
+
             ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
                 // First check all contained types and then tell the caller to continue searching.
                 return ty.super_visit_with(self);
@@ -214,7 +225,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
             ty::Error(_) => {
-                self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check");
+                self.tcx.sess.delay_span_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
                 return ControlFlow::CONTINUE;
@@ -244,9 +255,9 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
 
         // even though we skip super_visit_with, we must recur on
         // fields of ADT.
-        let tcx = self.tcx();
+        let tcx = self.tcx;
         adt_def.all_fields().map(|field| field.ty(tcx, substs)).try_for_each(|field_ty| {
-            let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
+            let ty = self.tcx.normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
             debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
             ty.visit_with(self)
         })
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 3a00c41d90a..3170b29ee69 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -6,7 +6,7 @@ use smallvec::SmallVec;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
 pub use rustc_infer::traits::{self, util::*};
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 8d666046ad9..7b5e1498f26 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -1,11 +1,10 @@
 use crate::infer::InferCtxt;
-use crate::opaque_types::required_region_bounds;
 use crate::traits;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeVisitable};
 use rustc_span::Span;
 
 use std::iter;
@@ -271,7 +270,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
     }
 
     fn normalize(mut self) -> Vec<traits::PredicateObligation<'tcx>> {
-        let cause = self.cause(traits::MiscObligation);
+        let cause = self.cause(traits::WellFormed(None));
         let infcx = &mut self.infcx;
         let param_env = self.param_env;
         let mut obligations = Vec::with_capacity(self.out.len());
@@ -385,7 +384,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         self.out.extend(obligations);
 
         let tcx = self.tcx();
-        let cause = self.cause(traits::MiscObligation);
+        let cause = self.cause(traits::WellFormed(None));
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
@@ -445,7 +444,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                             let predicate =
                                 ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
                                     .to_predicate(self.tcx());
-                            let cause = self.cause(traits::MiscObligation);
+                            let cause = self.cause(traits::WellFormed(None));
                             self.out.push(traits::Obligation::with_depth(
                                 cause,
                                 self.recursion_depth,
@@ -457,7 +456,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                             let resolved = self.infcx.shallow_resolve(infer);
                             // the `InferConst` changed, meaning that we made progress.
                             if resolved != infer {
-                                let cause = self.cause(traits::MiscObligation);
+                                let cause = self.cause(traits::WellFormed(None));
 
                                 let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS {
                                     kind: ty::ConstKind::Infer(resolved),
@@ -648,7 +647,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     let defer_to_coercion = self.tcx().features().object_safe_for_dispatch;
 
                     if !defer_to_coercion {
-                        let cause = self.cause(traits::MiscObligation);
+                        let cause = self.cause(traits::WellFormed(None));
                         let component_traits = data.auto_traits().chain(data.principal_def_id());
                         let tcx = self.tcx();
                         self.out.extend(component_traits.map(|did| {
@@ -679,7 +678,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     let ty = self.infcx.shallow_resolve(ty);
                     if let ty::Infer(ty::TyVar(_)) = ty.kind() {
                         // Not yet resolved, but we've made progress.
-                        let cause = self.cause(traits::MiscObligation);
+                        let cause = self.cause(traits::WellFormed(None));
                         self.out.push(traits::Obligation::with_depth(
                             cause,
                             self.recursion_depth,
@@ -810,3 +809,63 @@ pub fn object_region_bounds<'tcx>(
 
     required_region_bounds(tcx, open_ty, predicates)
 }
+
+/// Given a set of predicates that apply to an object type, returns
+/// the region bounds that the (erased) `Self` type must
+/// outlive. Precisely *because* the `Self` type is erased, the
+/// parameter `erased_self_ty` must be supplied to indicate what type
+/// has been used to represent `Self` in the predicates
+/// themselves. This should really be a unique type; `FreshTy(0)` is a
+/// popular choice.
+///
+/// N.B., in some cases, particularly around higher-ranked bounds,
+/// this function returns a kind of conservative approximation.
+/// That is, all regions returned by this function are definitely
+/// required, but there may be other region bounds that are not
+/// returned, as well as requirements like `for<'a> T: 'a`.
+///
+/// Requires that trait definitions have been processed so that we can
+/// elaborate predicates and walk supertraits.
+#[instrument(skip(tcx, predicates), level = "debug")]
+pub(crate) fn required_region_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    erased_self_ty: Ty<'tcx>,
+    predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
+) -> Vec<ty::Region<'tcx>> {
+    assert!(!erased_self_ty.has_escaping_bound_vars());
+
+    traits::elaborate_predicates(tcx, predicates)
+        .filter_map(|obligation| {
+            debug!(?obligation);
+            match obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Projection(..)
+                | ty::PredicateKind::Trait(..)
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::RegionOutlives(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+                ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
+                    // Search for a bound of the form `erased_self_ty
+                    // : 'a`, but be wary of something like `for<'a>
+                    // erased_self_ty : 'a` (we interpret a
+                    // higher-ranked bound like that as 'static,
+                    // though at present the code in `fulfill.rs`
+                    // considers such bounds to be unsatisfiable, so
+                    // it's kind of a moot point since you could never
+                    // construct such an object, but this seems
+                    // correct even if that code changes).
+                    if t == &erased_self_ty && !r.has_escaping_bound_vars() {
+                        Some(*r)
+                    } else {
+                        None
+                    }
+                }
+            }
+        })
+        .collect()
+}
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 2453d3a692a..c7c604e14e3 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -35,7 +35,8 @@ use rustc_ast::ast;
 use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
-    self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+    self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_span::def_id::DefId;
 
@@ -896,7 +897,7 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    fn visit_binder<T: TypeFoldable<'tcx>>(
+    fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index 59cf37fee9c..db7ea4253e3 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -14,7 +14,7 @@ use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
 use rustc_middle::traits::ChalkRustInterner;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::GenericArg;
-use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable, TypeVisitable};
 
 use rustc_infer::infer::canonical::{
     Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse,
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index ae48211d52d..c7cac8fca89 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::query::OutlivesBound;
 use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 use rustc_span::source_map::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 552db5406df..5e58f237982 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -4,7 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::CodegenObligationError;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{
-    self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+    self, Binder, Instance, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
@@ -56,7 +56,7 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
     type BreakTy = ();
 
-    fn visit_binder<T: TypeFoldable<'tcx>>(
+    fn visit_binder<T: TypeVisitable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
     ) -> ControlFlow<Self::BreakTy> {
@@ -332,12 +332,12 @@ fn resolve_associated_item<'tcx>(
         }),
         traits::ImplSource::Closure(closure_data) => {
             let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap();
-            Some(Instance::resolve_closure(
+            Instance::resolve_closure(
                 tcx,
                 closure_data.closure_def_id,
                 closure_data.substs,
                 trait_closure_kind,
-            ))
+            )
         }
         traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
             ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 38ae6a25b18..1d345caf699 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -211,7 +211,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
     });
     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
-    traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
+    traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
 }
 
 /// Elaborate the environment.
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index f9708d6d919..fd6376ef6ee 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -204,14 +204,6 @@ bitflags! {
                                           | TypeFlags::HAS_CT_INFER.bits
                                           | TypeFlags::HAS_TY_PLACEHOLDER.bits
                                           | TypeFlags::HAS_CT_PLACEHOLDER.bits
-                                          // The `evaluate_obligation` query does not return further
-                                          // obligations. If it evaluates an obligation with an opaque
-                                          // type, that opaque type may get compared to another type,
-                                          // constraining it. We would lose this information.
-                                          // FIXME: differentiate between crate-local opaque types
-                                          // and opaque types from other crates, as only opaque types
-                                          // from the local crate can possibly be a local name
-                                          | TypeFlags::HAS_TY_OPAQUE.bits
                                           // We consider 'freshened' types and constants
                                           // to depend on a particular fn.
                                           // The freshening process throws away information,
@@ -599,6 +591,7 @@ impl UnifyKey for FloatVid {
 }
 
 #[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash)]
+#[rustc_pass_by_value]
 pub enum Variance {
     Covariant,     // T<A> <: T<B> iff A <: B -- e.g., function return type
     Invariant,     // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index d111008e82c..c873cf27e42 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -164,10 +164,62 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 suggested_name,
                 Applicability::MaybeIncorrect,
             );
-        } else {
-            err.span_label(span, format!("associated type `{}` not found", assoc_name));
+            return err.emit();
         }
 
+        // If we didn't find a good item in the supertraits (or couldn't get
+        // the supertraits), like in ItemCtxt, then look more generally from
+        // all visible traits. If there's one clear winner, just suggest that.
+
+        let visible_traits: Vec<_> = self
+            .tcx()
+            .all_traits()
+            .filter(|trait_def_id| {
+                let viz = self.tcx().visibility(*trait_def_id);
+                if let Some(def_id) = self.item_def_id() {
+                    viz.is_accessible_from(def_id, self.tcx())
+                } else {
+                    viz.is_visible_locally()
+                }
+            })
+            .collect();
+
+        let wider_candidate_names: Vec<_> = visible_traits
+            .iter()
+            .flat_map(|trait_def_id| {
+                self.tcx().associated_items(*trait_def_id).in_definition_order()
+            })
+            .filter_map(
+                |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
+            )
+            .collect();
+
+        if let (Some(suggested_name), true) = (
+            find_best_match_for_name(&wider_candidate_names, assoc_name.name, None),
+            assoc_name.span != DUMMY_SP,
+        ) {
+            if let [best_trait] = visible_traits
+                .iter()
+                .filter(|trait_def_id| {
+                    self.tcx()
+                        .associated_items(*trait_def_id)
+                        .filter_by_name_unhygienic(suggested_name)
+                        .any(|item| item.kind == ty::AssocKind::Type)
+                })
+                .collect::<Vec<_>>()[..]
+            {
+                err.span_label(
+                    assoc_name.span,
+                    format!(
+                        "there is a similarly named associated type `{suggested_name}` in the trait `{}`",
+                        self.tcx().def_path_str(*best_trait)
+                    ),
+                );
+                return err.emit();
+            }
+        }
+
+        err.span_label(span, format!("associated type `{}` not found", assoc_name));
         err.emit()
     }
 
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 37958cc0f40..0a2b54eec47 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -28,7 +28,7 @@ use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{
-    self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable,
+    self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edition::Edition;
@@ -1958,9 +1958,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         );
                     }
 
-                    if let Some(sp) = tcx.hir().span_if_local(adt_def.did()) {
-                        let sp = tcx.sess.source_map().guess_head_span(sp);
-                        err.span_label(sp, format!("variant `{}` not found here", assoc_ident));
+                    if adt_def.did().is_local() {
+                        err.span_label(
+                            tcx.def_span(adt_def.did()),
+                            format!("variant `{assoc_ident}` not found for this enum"),
+                        );
                     }
 
                     err.emit()
@@ -2450,7 +2452,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
                     let msg = format!("`Self` is of type `{ty}`");
                     if let (Ok(i_sp), Some(t_sp)) = (span_of_impl, span_of_ty) {
-                        let i_sp = tcx.sess.source_map().guess_head_span(i_sp);
                         let mut span: MultiSpan = vec![t_sp].into();
                         span.push_span_label(
                             i_sp,
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 035571c881c..79e402b542a 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -4,7 +4,7 @@ use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
@@ -263,7 +263,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else if let ExprKind::Block(block, _) = &then_expr.kind
                     && let Some(expr) = &block.expr
                 {
-                    err.span_label(expr.span, "found here".to_string());
+                    err.span_label(expr.span, "found here");
                 }
                 err.note("`if` expressions without `else` evaluate to `()`");
                 err.help("consider adding an `else` block that evaluates to the expected type");
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 83a8c5ea021..3af73abe5ce 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
@@ -117,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // we must check that return type of called functions is WF:
-        self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation);
+        self.register_wf_obligation(output.into(), call_expr.span, traits::WellFormed(None));
 
         output
     }
@@ -280,15 +280,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         callee_node: &hir::ExprKind<'_>,
         callee_span: Span,
     ) {
-        let hir_id = self.tcx.hir().get_parent_node(hir_id);
-        let parent_node = self.tcx.hir().get(hir_id);
+        let hir = self.tcx.hir();
+        let parent_hir_id = hir.get_parent_node(hir_id);
+        let parent_node = hir.get(parent_hir_id);
         if let (
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure { fn_decl_span, .. }, ..
+                kind: hir::ExprKind::Closure { fn_decl_span, body, .. },
+                ..
             }),
             hir::ExprKind::Block(..),
         ) = (parent_node, callee_node)
         {
+            let fn_decl_span = if hir.body(*body).generator_kind
+                == Some(hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure))
+            {
+                // Actually need to unwrap a few more layers of HIR to get to
+                // the _real_ closure...
+                let async_closure = hir.get_parent_node(hir.get_parent_node(parent_hir_id));
+                if let hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Closure { fn_decl_span, .. },
+                    ..
+                }) = hir.get(async_closure)
+                {
+                    *fn_decl_span
+                } else {
+                    return;
+                }
+            } else {
+                *fn_decl_span
+            };
+
             let start = fn_decl_span.shrink_to_lo();
             let end = callee_span.shrink_to_hi();
             err.multipart_suggestion(
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 7d5d6849b3b..66dd5582490 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -40,7 +40,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 6222dbb4074..e9709b64d93 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -13,6 +13,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ItemKind, Node, PathSegment};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
@@ -20,7 +21,9 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, ParamEnv, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+};
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
 use rustc_span::{self, Span};
@@ -285,11 +288,9 @@ fn check_panic_info_fn(
         tcx.sess.span_err(decl.output.span(), "return type should be `!`");
     }
 
-    let span = tcx.def_span(fn_id);
     let inputs = fn_sig.inputs();
     if inputs.len() != 1 {
-        let span = tcx.sess.source_map().guess_head_span(span);
-        tcx.sess.span_err(span, "function should have one argument");
+        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
         return;
     }
 
@@ -342,9 +343,7 @@ fn check_alloc_error_fn(
 
     let inputs = fn_sig.inputs();
     if inputs.len() != 1 {
-        let span = tcx.def_span(fn_id);
-        let span = tcx.sess.source_map().guess_head_span(span);
-        tcx.sess.span_err(span, "function should have one argument");
+        tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
         return;
     }
 
@@ -521,7 +520,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
 
     struct FoundParentLifetime;
     struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
-    impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
+    impl<'tcx> ty::visit::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
         type BreakTy = FoundParentLifetime;
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -555,7 +554,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
         selftys: Vec<(Span, Option<String>)>,
     }
 
-    impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+    impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         type BreakTy = Ty<'tcx>;
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
@@ -736,10 +735,8 @@ fn check_opaque_meets_bounds<'tcx>(
             hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
             // Can have different predicates to their defining use
             hir::OpaqueTyOrigin::TyAlias => {
-                // Finally, resolve all regions. This catches wily misuses of
-                // lifetime parameters.
-                let fcx = FnCtxt::new(&inh, param_env, hir_id);
-                fcx.regionck_item(hir_id, span, FxHashSet::default());
+                let outlives_environment = OutlivesEnvironment::new(param_env);
+                infcx.check_region_obligations_and_report_errors(&outlives_environment);
             }
         }
 
@@ -1033,7 +1030,6 @@ fn check_impl_items_against_trait<'tcx>(
                 compare_impl_method(
                     tcx,
                     &ty_impl_item,
-                    impl_item.span,
                     &ty_trait_item,
                     impl_trait_ref,
                     opt_trait_span,
@@ -1093,17 +1089,20 @@ fn check_impl_items_against_trait<'tcx>(
         }
 
         if !missing_items.is_empty() {
-            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-            missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
+            missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span);
         }
 
         if let Some(missing_items) = must_implement_one_of {
-            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
             let attr_span = tcx
                 .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
                 .map(|attr| attr.span);
 
-            missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
+            missing_items_must_implement_one_of_err(
+                tcx,
+                tcx.def_span(impl_id),
+                missing_items,
+                attr_span,
+            );
         }
     }
 }
@@ -1596,7 +1595,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
                 .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
             {
                 struct OpaqueTypeCollector(Vec<DefId>);
-                impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector {
+                impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
                             ty::Opaque(def, _) => {
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 131e594ed94..1681e6af812 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -10,8 +10,8 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_infer::infer::{InferOk, InferResult};
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::InternalSubsts;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Span;
 use rustc_target::spec::abi::Abi;
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 43fc49c6801..acd7e4a92dc 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -50,9 +50,9 @@ use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
 };
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 95c82a7d2c3..2bfb9343877 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -1,3 +1,4 @@
+use crate::check::regionck::OutlivesEnvironmentExt;
 use crate::errors::LifetimesOrBoundsMismatchOnTrait;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
@@ -5,6 +6,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
 use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -31,14 +33,13 @@ use super::{potentially_plural_count, FnCtxt, Inherited};
 pub(crate) fn compare_impl_method<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_m: &ty::AssocItem,
-    impl_m_span: Span,
     trait_m: &ty::AssocItem,
     impl_trait_ref: ty::TraitRef<'tcx>,
     trait_item_span: Option<Span>,
 ) {
     debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref);
 
-    let impl_m_span = tcx.sess.source_map().guess_head_span(impl_m_span);
+    let impl_m_span = tcx.def_span(impl_m.def_id);
 
     if let Err(_) = compare_self_type(tcx, impl_m, impl_m_span, trait_m, impl_trait_ref) {
         return;
@@ -78,10 +79,11 @@ fn compare_predicate_entailment<'tcx>(
     let trait_to_impl_substs = impl_trait_ref.substs;
 
     // This node-id should be used for the `body_id` field on each
-    // `ObligationCause` (and the `FnCtxt`). This is what
-    // `regionck_item` expects.
+    // `ObligationCause` (and the `FnCtxt`).
+    //
+    // FIXME(@lcnr): remove that after removing `cause.body_id` from
+    // obligations.
     let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
-
     // We sometimes modify the span further down.
     let mut cause = ObligationCause::new(
         impl_m_span,
@@ -208,8 +210,7 @@ fn compare_predicate_entailment<'tcx>(
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
-    let param_env =
-        traits::normalize_param_env_or_error(tcx, impl_m.def_id, param_env, normalize_cause);
+    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
 
     tcx.infer_ctxt().enter(|infcx| {
         let inh = Inherited::new(infcx, impl_m.def_id.expect_local());
@@ -399,8 +400,9 @@ fn compare_predicate_entailment<'tcx>(
 
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
-        let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
-        fcx.regionck_item(impl_m_hir_id, impl_m_span, wf_tys);
+        let mut outlives_environment = OutlivesEnvironment::new(param_env);
+        outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id);
+        infcx.check_region_obligations_and_report_errors(&outlives_environment);
 
         Ok(())
     })
@@ -441,13 +443,9 @@ fn check_region_bounds_on_impl_item<'tcx>(
             .as_local()
             .and_then(|did| tcx.hir().get_generics(did))
             .map_or(def_span, |g| g.span);
-        let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
-            let def_sp = tcx.sess.source_map().guess_head_span(sp);
-            trait_m
-                .def_id
-                .as_local()
-                .and_then(|did| tcx.hir().get_generics(did))
-                .map_or(def_sp, |g| g.span)
+        let generics_span = trait_m.def_id.as_local().map(|did| {
+            let def_sp = tcx.def_span(did);
+            tcx.hir().get_generics(did).map_or(def_sp, |g| g.span)
         });
 
         let reported = tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
@@ -1041,8 +1039,7 @@ fn compare_generic_param_kinds<'tcx>(
             err.span_label(trait_header_span, "");
             err.span_label(param_trait_span, make_param_message("expected", param_trait));
 
-            let impl_header_span =
-                tcx.sess.source_map().guess_head_span(tcx.def_span(tcx.parent(impl_item.def_id)));
+            let impl_header_span = tcx.def_span(tcx.parent(impl_item.def_id));
             err.span_label(impl_header_span, "");
             err.span_label(param_impl_span, make_param_message("found", param_impl));
 
@@ -1155,8 +1152,8 @@ pub(crate) fn compare_const_impl<'tcx>(
             return;
         }
 
-        let fcx = FnCtxt::new(&inh, param_env, impl_c_hir_id);
-        fcx.regionck_item(impl_c_hir_id, impl_c_span, FxHashSet::default());
+        let outlives_environment = OutlivesEnvironment::new(param_env);
+        infcx.resolve_regions_and_report_errors(&outlives_environment);
     });
 }
 
@@ -1247,12 +1244,7 @@ fn compare_type_predicate_entailment<'tcx>(
         Reveal::UserFacing,
         hir::Constness::NotConst,
     );
-    let param_env = traits::normalize_param_env_or_error(
-        tcx,
-        impl_ty.def_id,
-        param_env,
-        normalize_cause.clone(),
-    );
+    let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone());
     tcx.infer_ctxt().enter(|infcx| {
         let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
         let infcx = &inh.infcx;
@@ -1279,8 +1271,8 @@ fn compare_type_predicate_entailment<'tcx>(
 
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
-        let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
-        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, FxHashSet::default());
+        let outlives_environment = OutlivesEnvironment::new(param_env);
+        infcx.check_region_obligations_and_report_errors(&outlives_environment);
 
         Ok(())
     })
@@ -1504,12 +1496,16 @@ pub fn check_type_bounds<'tcx>(
 
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
+        //
+        // FIXME: Remove that `FnCtxt`.
         let fcx = FnCtxt::new(&inh, param_env, impl_ty_hir_id);
         let implied_bounds = match impl_ty.container {
             ty::TraitContainer(_) => FxHashSet::default(),
             ty::ImplContainer(def_id) => fcx.impl_implied_bounds(def_id, impl_ty_span),
         };
-        fcx.regionck_item(impl_ty_hir_id, impl_ty_span, implied_bounds);
+        let mut outlives_environment = OutlivesEnvironment::new(param_env);
+        outlives_environment.add_implied_bounds(infcx, implied_bounds, impl_ty_hir_id);
+        infcx.check_region_obligations_and_report_errors(&outlives_environment);
 
         Ok(())
     })
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 961bbc42661..dc553d1441e 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None,
                         hir::Path { res: hir::def::Res::Local(hir_id), .. },
                     )) => {
-                        if let Some(hir::Node::Binding(pat)) = self.tcx.hir().find(*hir_id) {
+                        if let Some(hir::Node::Pat(pat)) = self.tcx.hir().find(*hir_id) {
                             let parent = self.tcx.hir().get_parent_node(pat.hir_id);
                             primary_span = pat.span;
                             secondary_span = pat.span;
@@ -317,9 +317,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 .tcx
                                 .is_diagnostic_item(sym::Result, expected_adt.did())
                             {
-                                vec!["Ok(())".to_string()]
+                                vec!["Ok(())"]
                             } else if self.tcx.is_diagnostic_item(sym::Option, expected_adt.did()) {
-                                vec!["None".to_string(), "Some(())".to_string()]
+                                vec!["None", "Some(())"]
                             } else {
                                 return;
                             };
@@ -760,7 +760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     if let Some(call_span) =
                         iter::successors(Some(expr.span), |s| s.parent_callsite())
                             .find(|&s| sp.contains(s))
-                        && sm.span_to_snippet(call_span).is_ok()
+                        && sm.is_span_accessible(call_span)
                     {
                         return Some((
                             sp.with_hi(call_span.lo()),
@@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return None;
                 }
                 if sp.contains(expr.span)
-                    && sm.span_to_snippet(expr.span).is_ok()
+                    && sm.is_span_accessible(expr.span)
                 {
                     return Some((
                         sp.with_hi(expr.span.lo()),
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index ed3b9f2db1f..72095c40807 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -1,5 +1,6 @@
-use crate::check::regionck::RegionCtxt;
-use crate::hir;
+// FIXME(@lcnr): Move this module out of `rustc_typeck`.
+//
+// We don't do any drop checking during hir typeck.
 use crate::hir::def_id::{DefId, LocalDefId};
 use rustc_errors::{struct_span_err, ErrorGuaranteed};
 use rustc_middle::ty::error::TypeError;
@@ -7,9 +8,6 @@ use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
-use rustc_span::Span;
-use rustc_trait_selection::traits::query::dropck_outlives::AtExt;
-use rustc_trait_selection::traits::ObligationCause;
 
 /// This function confirms that the `Drop` implementation identified by
 /// `drop_impl_did` is not any more specialized than the type it is
@@ -231,23 +229,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     result
 }
 
-/// This function is not only checking that the dropck obligations are met for
-/// the given type, but it's also currently preventing non-regular recursion in
-/// types from causing stack overflows (dropck_no_diverge_on_nonregular_*.rs).
-pub(crate) fn check_drop_obligations<'a, 'tcx>(
-    rcx: &mut RegionCtxt<'a, 'tcx>,
-    ty: Ty<'tcx>,
-    span: Span,
-    body_id: hir::HirId,
-) {
-    debug!("check_drop_obligations typ: {:?}", ty);
-
-    let cause = &ObligationCause::misc(span, body_id);
-    let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
-    debug!("dropck_outlives = {:#?}", infer_ok);
-    rcx.fcx.register_infer_ok_obligations(infer_ok);
-}
-
 // This is an implementation of the TypeRelation trait with the
 // aim of simply comparing for equality (without side-effects).
 // It is not intended to be used anywhere else other than here.
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index b4476d5c59b..58c01a34cad 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -44,7 +44,7 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
 use rustc_middle::ty::error::TypeError::FieldMisMatch;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeVisitable};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     #[instrument(skip(self, expr), level = "debug")]
-    pub(super) fn check_expr_kind(
+    fn check_expr_kind(
         &self,
         expr: &'tcx hir::Expr<'tcx>,
         expected: Expectation<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index bce2e85de84..cf7de1dc016 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -23,6 +23,7 @@ use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{
     self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
 };
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{
     self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
     ToPredicate, Ty, UserType,
@@ -495,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
         let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
-        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
+        self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
         t
     }
 
@@ -525,7 +526,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.register_wf_obligation(
             c.into(),
             self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
+            ObligationCauseCode::WellFormed(None),
         );
         c
     }
@@ -543,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.register_wf_obligation(
             c.into(),
             self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
+            ObligationCauseCode::WellFormed(None),
         );
         c
     }
@@ -557,7 +558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     // sufficiently enforced with erased regions. =)
     fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
     where
-        T: TypeFoldable<'tcx>,
+        T: TypeVisitable<'tcx>,
     {
         t.has_free_regions() || t.has_projections() || t.has_infer_types()
     }
@@ -606,7 +607,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for arg in substs.iter().filter(|arg| {
             matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
         }) {
-            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
+            self.register_wf_obligation(arg, expr.span, traits::WellFormed(None));
         }
     }
 
@@ -1538,15 +1539,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ty
         } else {
             if !self.is_tainted_by_errors() {
-                self.emit_inference_failure_err(
-                    (**self).body_id,
-                    sp,
-                    ty.into(),
-                    vec![],
-                    E0282,
-                    true,
-                )
-                .emit();
+                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282, true)
+                    .emit();
             }
             let err = self.tcx.ty_error();
             self.demand_suptype(sp, err, ty);
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index d2e16021827..a7c7089234a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -24,7 +24,7 @@ use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
 use rustc_infer::infer::InferOk;
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
-use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
@@ -483,6 +483,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.set_tainted_by_errors();
         let tcx = self.tcx;
 
+        // Precompute the provided types and spans, since that's all we typically need for below
+        let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
+            .iter()
+            .map(|expr| {
+                let ty = self
+                    .typeck_results
+                    .borrow()
+                    .expr_ty_adjusted_opt(*expr)
+                    .unwrap_or_else(|| tcx.ty_error());
+                (self.resolve_vars_if_possible(ty), expr.span)
+            })
+            .collect();
+
         // A "softer" version of the `demand_compatible`, which checks types without persisting them,
         // and treats error types differently
         // This will allow us to "probe" for other argument orders that would likely have been correct
@@ -499,31 +512,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return Compatibility::Incompatible(None);
             }
 
-            let provided_arg: &hir::Expr<'tcx> = &provided_args[provided_idx];
-            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
-            // FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure.
-            //
-            //   I had another method of "soft" type checking before,
-            //   but it was failing to find the type of some expressions (like "")
-            //   so I prodded this method and made it pub(super) so I could call it, and it seems to work well.
-            let checked_ty = self.check_expr_kind(provided_arg, expectation);
+            let (arg_ty, arg_span) = provided_arg_tys[provided_idx];
 
+            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
             let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
-            let can_coerce = self.can_coerce(checked_ty, coerced_ty);
+            let can_coerce = self.can_coerce(arg_ty, coerced_ty);
             if !can_coerce {
                 return Compatibility::Incompatible(None);
             }
 
             // Using probe here, since we don't want this subtyping to affect inference.
             let subtyping_error = self.probe(|_| {
-                self.at(&self.misc(provided_arg.span), self.param_env)
-                    .sup(formal_input_ty, coerced_ty)
-                    .err()
+                self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err()
             });
 
             // Same as above: if either the coerce type or the checked type is an error type,
             // consider them *not* compatible.
-            let references_error = (coerced_ty, checked_ty).references_error();
+            let references_error = (coerced_ty, arg_ty).references_error();
             match (references_error, subtyping_error) {
                 (false, None) => Compatibility::Compatible,
                 (_, subtyping_error) => Compatibility::Incompatible(subtyping_error),
@@ -542,19 +547,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible)
                 .find_errors();
 
-        // Precompute the provided types and spans, since that's all we typically need for below
-        let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args
-            .iter()
-            .map(|expr| {
-                let ty = self
-                    .typeck_results
-                    .borrow()
-                    .expr_ty_adjusted_opt(*expr)
-                    .unwrap_or_else(|| tcx.ty_error());
-                (self.resolve_vars_if_possible(ty), expr.span)
-            })
-            .collect();
-
         // First, check if we just need to wrap some arguments in a tuple.
         if let Some((mismatch_idx, terr)) =
             compatibility_diagonal.iter().enumerate().find_map(|(i, c)| {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 8b680a3d042..05bcc710e16 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -15,8 +15,8 @@ use rustc_hir::def_id::DefId;
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 7195da863db..863a981134f 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -13,7 +13,6 @@ use rustc_hir::{
 use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_infer::traits;
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Binder, IsSuggestable, Subst, ToPredicate, Ty};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -184,9 +183,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if let (ty::FnDef(def_id, ..), true) =
             (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
         {
-            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
-                let sp = self.sess().source_map().guess_head_span(sp);
-                err.span_label(sp, &format!("{} defined here", found));
+            if def_id.is_local() {
+                err.span_label(self.tcx.def_span(def_id), &format!("{} defined here", found));
             }
         } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
             let is_struct_pat_shorthand_field =
@@ -239,25 +237,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
                 }
-            } else if found.to_string().starts_with("Option<")
-                && expected.to_string() == "Option<&str>"
+            } else if let ty::Adt(found_adt, found_substs) = found.kind()
+                && self.tcx.is_diagnostic_item(sym::Option, found_adt.did())
+                && let ty::Adt(expected_adt, expected_substs) = expected.kind()
+                && self.tcx.is_diagnostic_item(sym::Option, expected_adt.did())
+                && let ty::Ref(_, inner_ty, _) = expected_substs.type_at(0).kind()
+                && inner_ty.is_str()
             {
-                if let ty::Adt(_def, subst) = found.kind() {
-                    if subst.len() != 0 {
-                        if let GenericArgKind::Type(ty) = subst[0].unpack() {
-                            let peeled = ty.peel_refs().to_string();
-                            if peeled == "String" {
-                                let ref_cnt = ty.to_string().len() - peeled.len();
-                                let result = format!(".map(|x| &*{}x)", "*".repeat(ref_cnt));
-                                err.span_suggestion_verbose(
-                                    expr.span.shrink_to_hi(),
-                                    "try converting the passed type into a `&str`",
-                                    result,
-                                    Applicability::MaybeIncorrect,
-                                );
-                            }
-                        }
-                    }
+                let ty = found_substs.type_at(0);
+                let mut peeled = ty;
+                let mut ref_cnt = 0;
+                while let ty::Ref(_, inner, _) = peeled.kind() {
+                    peeled = *inner;
+                    ref_cnt += 1;
+                }
+                if let ty::Adt(adt, _) = peeled.kind()
+                    && self.tcx.is_diagnostic_item(sym::String, adt.did())
+                {
+                    err.span_suggestion_verbose(
+                        expr.span.shrink_to_hi(),
+                        "try converting the passed type into a `&str`",
+                        format!(".map(|x| &*{}x)", "*".repeat(ref_cnt)),
+                        Applicability::MaybeIncorrect,
+                    );
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
index c2b4c478ba3..887c791af76 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
@@ -109,7 +109,7 @@ rustc_index::newtype_index! {
 }
 
 /// Identifies a value whose drop state we need to track.
-#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
+#[derive(PartialEq, Eq, Hash, Clone, Copy)]
 enum TrackedValue {
     /// Represents a named variable, such as a let binding, parameter, or upvar.
     ///
@@ -121,6 +121,21 @@ enum TrackedValue {
     Temporary(HirId),
 }
 
+impl Debug for TrackedValue {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ty::tls::with_opt(|opt_tcx| {
+            if let Some(tcx) = opt_tcx {
+                write!(f, "{}", tcx.hir().node_to_string(self.hir_id()))
+            } else {
+                match self {
+                    Self::Variable(hir_id) => write!(f, "Variable({:?})", hir_id),
+                    Self::Temporary(hir_id) => write!(f, "Temporary({:?})", hir_id),
+                }
+            }
+        })
+    }
+}
+
 impl TrackedValue {
     fn hir_id(&self) -> HirId {
         match self {
@@ -148,7 +163,7 @@ enum TrackedValueConversionError {
     /// Place projects are not currently supported.
     ///
     /// The reasoning around these is kind of subtle, so we choose to be more
-    /// conservative around these for now. There is not reason in theory we
+    /// conservative around these for now. There is no reason in theory we
     /// cannot support these, we just have not implemented it yet.
     PlaceProjectionsNotSupported,
 }
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
index dbc309b29ff..111d534abf8 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
@@ -33,6 +33,9 @@ pub(super) fn build_control_flow_graph<'tcx>(
     intravisit::walk_body(&mut drop_range_visitor, body);
 
     drop_range_visitor.drop_ranges.process_deferred_edges();
+    if let Some(filename) = &tcx.sess.opts.debugging_opts.dump_drop_tracking_cfg {
+        super::cfg_visualize::write_graph_to_file(&drop_range_visitor.drop_ranges, filename, tcx);
+    }
 
     (drop_range_visitor.drop_ranges, drop_range_visitor.places.borrowed_temporaries)
 }
@@ -126,13 +129,14 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
     /// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
     /// expressions. This method consumes a little deeper into the expression when needed.
     fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
-        debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
+        debug!("consuming expr {:?}, count={:?}", expr.kind, self.expr_index);
         let places = self
             .places
             .consumed
             .get(&expr.hir_id)
             .map_or(vec![], |places| places.iter().cloned().collect());
         for place in places {
+            trace!(?place, "consuming place");
             for_each_consumable(self.hir, place, |value| self.record_drop(value));
         }
     }
@@ -251,7 +255,6 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
                 | hir::Node::Ty(..)
                 | hir::Node::TypeBinding(..)
                 | hir::Node::TraitRef(..)
-                | hir::Node::Binding(..)
                 | hir::Node::Pat(..)
                 | hir::Node::Arm(..)
                 | hir::Node::Local(..)
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
index 20aad7aedf7..c0a0bfe8e1c 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_visualize.rs
@@ -2,6 +2,7 @@
 //! flow graph when needed for debugging.
 
 use rustc_graphviz as dot;
+use rustc_middle::ty::TyCtxt;
 
 use super::{DropRangesBuilder, PostOrderId};
 
@@ -9,22 +10,35 @@ use super::{DropRangesBuilder, PostOrderId};
 ///
 /// It is not normally called, but is kept around to easily add debugging
 /// code when needed.
-#[allow(dead_code)]
-pub(super) fn write_graph_to_file(drop_ranges: &DropRangesBuilder, filename: &str) {
-    dot::render(drop_ranges, &mut std::fs::File::create(filename).unwrap()).unwrap();
+pub(super) fn write_graph_to_file(
+    drop_ranges: &DropRangesBuilder,
+    filename: &str,
+    tcx: TyCtxt<'_>,
+) {
+    dot::render(
+        &DropRangesGraph { drop_ranges, tcx },
+        &mut std::fs::File::create(filename).unwrap(),
+    )
+    .unwrap();
 }
 
-impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
+struct DropRangesGraph<'a, 'tcx> {
+    drop_ranges: &'a DropRangesBuilder,
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'a> dot::GraphWalk<'a> for DropRangesGraph<'_, '_> {
     type Node = PostOrderId;
 
     type Edge = (PostOrderId, PostOrderId);
 
     fn nodes(&'a self) -> dot::Nodes<'a, Self::Node> {
-        self.nodes.iter_enumerated().map(|(i, _)| i).collect()
+        self.drop_ranges.nodes.iter_enumerated().map(|(i, _)| i).collect()
     }
 
     fn edges(&'a self) -> dot::Edges<'a, Self::Edge> {
-        self.nodes
+        self.drop_ranges
+            .nodes
             .iter_enumerated()
             .flat_map(|(i, node)| {
                 if node.successors.len() == 0 {
@@ -45,7 +59,7 @@ impl<'a> dot::GraphWalk<'a> for DropRangesBuilder {
     }
 }
 
-impl<'a> dot::Labeller<'a> for DropRangesBuilder {
+impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
     type Node = PostOrderId;
 
     type Edge = (PostOrderId, PostOrderId);
@@ -61,15 +75,15 @@ impl<'a> dot::Labeller<'a> for DropRangesBuilder {
     fn node_label(&'a self, n: &Self::Node) -> dot::LabelText<'a> {
         dot::LabelText::LabelStr(
             format!(
-                "{:?}, local_id: {}",
-                n,
-                self.post_order_map
+                "{n:?}: {}",
+                self.drop_ranges
+                    .post_order_map
                     .iter()
                     .find(|(_hir_id, &post_order_id)| post_order_id == *n)
-                    .map_or("<unknown>".into(), |(hir_id, _)| format!(
-                        "{}",
-                        hir_id.local_id.index()
-                    ))
+                    .map_or("<unknown>".into(), |(hir_id, _)| self
+                        .tcx
+                        .hir()
+                        .node_to_string(*hir_id))
             )
             .into(),
         )
diff --git a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
index b22b791f629..67cc46f21f0 100644
--- a/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -75,6 +75,7 @@ impl<'tcx> ExprUseDelegate<'tcx> {
         if !self.places.consumed.contains_key(&consumer) {
             self.places.consumed.insert(consumer, <_>::default());
         }
+        debug!(?consumer, ?target, "mark_consumed");
         self.places.consumed.get_mut(&consumer).map(|places| places.insert(target));
     }
 
@@ -136,13 +137,16 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
         place_with_id: &expr_use_visitor::PlaceWithHirId<'tcx>,
         diag_expr_id: HirId,
     ) {
-        let parent = match self.tcx.hir().find_parent_node(place_with_id.hir_id) {
+        let hir = self.tcx.hir();
+        let parent = match hir.find_parent_node(place_with_id.hir_id) {
             Some(parent) => parent,
             None => place_with_id.hir_id,
         };
         debug!(
-            "consume {:?}; diag_expr_id={:?}, using parent {:?}",
-            place_with_id, diag_expr_id, parent
+            "consume {:?}; diag_expr_id={}, using parent {}",
+            place_with_id,
+            hir.node_to_string(diag_expr_id),
+            hir.node_to_string(parent)
         );
         place_with_id
             .try_into()
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 08a64d8e673..2ce258cf69c 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -8,6 +8,7 @@ use rustc_hir::HirIdMap;
 use rustc_infer::infer;
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::{self, Span};
 use rustc_trait_selection::infer::InferCtxtExt as _;
diff --git a/compiler/rustc_typeck/src/check/intrinsicck.rs b/compiler/rustc_typeck/src/check/intrinsicck.rs
index 469e6118575..cc91f2431e0 100644
--- a/compiler/rustc_typeck/src/check/intrinsicck.rs
+++ b/compiler/rustc_typeck/src/check/intrinsicck.rs
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
-use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeVisitable, UintTy};
 use rustc_session::lint;
 use rustc_span::{Span, Symbol, DUMMY_SP};
 use rustc_target::abi::{Pointer, VariantIdx};
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 4061b7cae7c..d8cdc9275f4 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -501,7 +501,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // the function type must also be well-formed (this is not
         // implied by the substs being well-formed because of inherent
         // impls and late-bound regions - see issue #28609).
-        self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation);
+        self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None));
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 5ca82218355..e29f0275bf4 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -21,7 +21,7 @@ use rustc_infer::infer::{self, InferOk};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 87254b211d6..e9b91414a07 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -21,7 +21,9 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{
+    self, EarlyBinder, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitable,
+};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index fa5f0eff223..7bf167426f7 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -17,7 +17,7 @@ use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::with_crate_prefix;
 use rustc_middle::ty::ToPolyTraitRef;
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
 use rustc_trait_selection::traits::error_reporting::on_unimplemented::InferCtxtExt as _;
@@ -121,11 +121,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }) else {
                             continue;
                         };
-                        let note_span = self
-                            .tcx
-                            .hir()
-                            .span_if_local(item.def_id)
-                            .or_else(|| self.tcx.hir().span_if_local(impl_did));
+
+                        let note_span = if item.def_id.is_local() {
+                            Some(self.tcx.def_span(item.def_id))
+                        } else if impl_did.is_local() {
+                            Some(self.tcx.def_span(impl_did))
+                        } else {
+                            None
+                        };
 
                         let impl_ty = self.tcx.at(span).type_of(impl_did);
 
@@ -158,10 +161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         };
                         if let Some(note_span) = note_span {
                             // We have a span pointing to the method. Show note with snippet.
-                            err.span_note(
-                                self.tcx.sess.source_map().guess_head_span(note_span),
-                                &note_str,
-                            );
+                            err.span_note(note_span, &note_str);
                         } else {
                             err.note(&note_str);
                         }
@@ -197,11 +197,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     CandidateSource::Trait(trait_did) => {
                         let Some(item) = self.associated_value(trait_did, item_name) else { continue };
-                        let item_span = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .guess_head_span(self.tcx.def_span(item.def_id));
+                        let item_span = self.tcx.def_span(item.def_id);
                         let idx = if sources.len() > 1 {
                             let msg = &format!(
                                 "candidate #{} is defined in the trait `{}`",
@@ -352,9 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let type_param = generics.type_param(param_type, self.tcx);
                         Some(self.tcx.def_span(type_param.def_id))
                     }
-                    ty::Adt(def, _) if def.did().is_local() => {
-                        tcx.def_ident_span(def.did()).map(|span| span)
-                    }
+                    ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
                     _ => None,
                 };
 
@@ -471,9 +465,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         err.note(&format!("`count` is defined on `{iterator_trait}`, which `{actual}` does not implement"));
                     }
                 } else if !unsatisfied_predicates.is_empty() {
-                    let def_span = |def_id| {
-                        self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id))
-                    };
                     let mut type_params = FxHashMap::default();
 
                     // Pick out the list of unimplemented traits on the receiver.
@@ -564,22 +555,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                         match &self_ty.kind() {
                             // Point at the type that couldn't satisfy the bound.
-                            ty::Adt(def, _) => bound_spans.push((def_span(def.did()), msg)),
+                            ty::Adt(def, _) => {
+                                bound_spans.push((self.tcx.def_span(def.did()), msg))
+                            }
                             // Point at the trait object that couldn't satisfy the bound.
                             ty::Dynamic(preds, _) => {
                                 for pred in preds.iter() {
                                     match pred.skip_binder() {
-                                        ty::ExistentialPredicate::Trait(tr) => {
-                                            bound_spans.push((def_span(tr.def_id), msg.clone()))
-                                        }
+                                        ty::ExistentialPredicate::Trait(tr) => bound_spans
+                                            .push((self.tcx.def_span(tr.def_id), msg.clone())),
                                         ty::ExistentialPredicate::Projection(_)
                                         | ty::ExistentialPredicate::AutoTrait(_) => {}
                                     }
                                 }
                             }
                             // Point at the closure that couldn't satisfy the bound.
-                            ty::Closure(def_id, _) => bound_spans
-                                .push((def_span(*def_id), format!("doesn't satisfy `{}`", quiet))),
+                            ty::Closure(def_id, _) => bound_spans.push((
+                                tcx.def_span(*def_id),
+                                format!("doesn't satisfy `{}`", quiet),
+                            )),
                             _ => {}
                         }
                     };
@@ -625,12 +619,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Find all the requirements that come from a local `impl` block.
                     let mut skip_list: FxHashSet<_> = Default::default();
                     let mut spanned_predicates: FxHashMap<MultiSpan, _> = Default::default();
-                    for (data, p, parent_p, impl_def_id, cause_span) in unsatisfied_predicates
+                    for (data, p, parent_p, impl_def_id, cause) in unsatisfied_predicates
                         .iter()
                         .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
                         .filter_map(|(p, parent, c)| match c.code() {
                             ObligationCauseCode::ImplDerivedObligation(ref data) => {
-                                Some((&data.derived, p, parent, data.impl_def_id, data.span))
+                                Some((&data.derived, p, parent, data.impl_def_id, data))
                             }
                             _ => None,
                         })
@@ -699,9 +693,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     let _ = format_pred(*pred);
                                 }
                                 skip_list.insert(p);
-                                let mut spans = if cause_span != *item_span {
-                                    let mut spans: MultiSpan = cause_span.into();
-                                    spans.push_span_label(cause_span, unsatisfied_msg);
+                                let mut spans = if cause.span != *item_span {
+                                    let mut spans: MultiSpan = cause.span.into();
+                                    spans.push_span_label(cause.span, unsatisfied_msg);
                                     spans
                                 } else {
                                     ident.span.into()
@@ -713,7 +707,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                             // Unmet obligation coming from an `impl`.
                             Some(Node::Item(hir::Item {
-                                kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
+                                kind:
+                                    hir::ItemKind::Impl(hir::Impl {
+                                        of_trait, self_ty, generics, ..
+                                    }),
                                 span: item_span,
                                 ..
                             })) if !matches!(
@@ -729,14 +726,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 Some(ExpnKind::Macro(MacroKind::Derive, _))
                             ) =>
                             {
+                                let sized_pred =
+                                    unsatisfied_predicates.iter().any(|(pred, _, _)| {
+                                        match pred.kind().skip_binder() {
+                                            ty::PredicateKind::Trait(pred) => {
+                                                Some(pred.def_id())
+                                                    == self.tcx.lang_items().sized_trait()
+                                                    && pred.polarity == ty::ImplPolarity::Positive
+                                            }
+                                            _ => false,
+                                        }
+                                    });
+                                for param in generics.params {
+                                    if param.span == cause.span && sized_pred {
+                                        let (sp, sugg) = match param.colon_span {
+                                            Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
+                                            None => (param.span.shrink_to_hi(), ": ?Sized"),
+                                        };
+                                        err.span_suggestion_verbose(
+                                            sp,
+                                            "consider relaxing the type parameter's implicit \
+                                             `Sized` bound",
+                                            sugg,
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                }
                                 if let Some(pred) = parent_p {
                                     // Done to add the "doesn't satisfy" `span_label`.
                                     let _ = format_pred(*pred);
                                 }
                                 skip_list.insert(p);
-                                let mut spans = if cause_span != *item_span {
-                                    let mut spans: MultiSpan = cause_span.into();
-                                    spans.push_span_label(cause_span, unsatisfied_msg);
+                                let mut spans = if cause.span != *item_span {
+                                    let mut spans: MultiSpan = cause.span.into();
+                                    spans.push_span_label(cause.span, unsatisfied_msg);
                                     spans
                                 } else {
                                     let mut spans = Vec::with_capacity(2);
@@ -1469,21 +1492,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 _ => None,
             })
             .collect::<FxHashSet<_>>();
-        let sm = self.tcx.sess.source_map();
         let mut spans: MultiSpan = def_ids
             .iter()
             .filter_map(|def_id| {
                 let span = self.tcx.def_span(*def_id);
-                if span.is_dummy() { None } else { Some(sm.guess_head_span(span)) }
+                if span.is_dummy() { None } else { Some(span) }
             })
             .collect::<Vec<_>>()
             .into();
 
         for pred in &preds {
             match pred.self_ty().kind() {
-                ty::Adt(def, _) => {
+                ty::Adt(def, _) if def.did().is_local() => {
                     spans.push_span_label(
-                        sm.guess_head_span(self.tcx.def_span(def.did())),
+                        self.tcx.def_span(def.did()),
                         format!("must implement `{}`", pred.trait_ref.print_only_trait_path()),
                     );
                 }
@@ -2090,9 +2112,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             match &potential_candidates[..] {
                 [] => {}
                 [trait_info] if trait_info.def_id.is_local() => {
-                    let span = self.tcx.hir().span_if_local(trait_info.def_id).unwrap();
                     err.span_note(
-                        self.tcx.sess.source_map().guess_head_span(span),
+                        self.tcx.def_span(trait_info.def_id),
                         &format!(
                             "`{}` defines an item `{}`, perhaps you need to {} it",
                             self.tcx.def_path_str(trait_info.def_id),
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 0ede9ef7756..dee58791cec 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -368,7 +368,7 @@ fn typeck_with_fallback<'tcx>(
 
     let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
         let param_env = tcx.param_env(def_id);
-        let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
+        let fcx = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
             let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
                 let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
                 <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
@@ -378,13 +378,7 @@ fn typeck_with_fallback<'tcx>(
 
             check_abi(tcx, id, span, fn_sig.abi());
 
-            // When normalizing the function signature, we assume all types are
-            // well-formed. So, we don't need to worry about the obligations
-            // from normalization. We could just discard these, but to align with
-            // compare_method and elsewhere, we just add implied bounds for
-            // these types.
-            let mut wf_tys = FxHashSet::default();
-            // Compute the fty from point of view of inside the fn.
+            // Compute the function signature from point of view of inside the fn.
             let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
             let fn_sig = inh.normalize_associated_types_in(
                 body.value.span,
@@ -392,10 +386,7 @@ fn typeck_with_fallback<'tcx>(
                 param_env,
                 fn_sig,
             );
-            wf_tys.extend(fn_sig.inputs_and_output.iter());
-
-            let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
-            (fcx, wf_tys)
+            check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
         } else {
             let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
             let expected_type = body_ty
@@ -458,7 +449,7 @@ fn typeck_with_fallback<'tcx>(
 
             fcx.write_ty(id, expected_type);
 
-            (fcx, FxHashSet::default())
+            fcx
         };
 
         let fallback_has_occurred = fcx.type_inference_fallback();
@@ -490,11 +481,7 @@ fn typeck_with_fallback<'tcx>(
 
         fcx.check_asms();
 
-        if fn_sig.is_some() {
-            fcx.regionck_fn(id, body, span, wf_tys);
-        } else {
-            fcx.regionck_expr(body);
-        }
+        fcx.infcx.skip_region_resolution();
 
         fcx.resolve_type_vars_in_body(body)
     });
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index c2f97a5051c..0887c27ea36 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitor,
+    self, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
@@ -565,9 +565,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .is_ok()
             {
                 let (variable_snippet, applicability) = if !fn_sig.inputs().is_empty() {
-                    ("( /* arguments */ )".to_string(), Applicability::HasPlaceholders)
+                    ("( /* arguments */ )", Applicability::HasPlaceholders)
                 } else {
-                    ("()".to_string(), Applicability::MaybeIncorrect)
+                    ("()", Applicability::MaybeIncorrect)
                 };
 
                 err.span_suggestion_verbose(
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index e1ec9f13cd1..fbfbfba5c2a 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -13,7 +13,7 @@ use rustc_hir::{HirId, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::middle::stability::EvalResult;
-use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitable};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 0ce63922098..1c3c5f999bc 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -1,106 +1,9 @@
-//! The region check is a final pass that runs over the AST after we have
-//! inferred the type constraints but before we have actually finalized
-//! the types. Its purpose is to embed a variety of region constraints.
-//! Inserting these constraints as a separate pass is good because (1) it
-//! localizes the code that has to do with region inference and (2) often
-//! we cannot know what constraints are needed until the basic types have
-//! been inferred.
-//!
-//! ### Interaction with the borrow checker
-//!
-//! In general, the job of the borrowck module (which runs later) is to
-//! check that all soundness criteria are met, given a particular set of
-//! regions. The job of *this* module is to anticipate the needs of the
-//! borrow checker and infer regions that will satisfy its requirements.
-//! It is generally true that the inference doesn't need to be sound,
-//! meaning that if there is a bug and we inferred bad regions, the borrow
-//! checker should catch it. This is not entirely true though; for
-//! example, the borrow checker doesn't check subtyping, and it doesn't
-//! check that region pointers are always live when they are used. It
-//! might be worthwhile to fix this so that borrowck serves as a kind of
-//! verification step -- that would add confidence in the overall
-//! correctness of the compiler, at the cost of duplicating some type
-//! checks and effort.
-//!
-//! ### Inferring the duration of borrows, automatic and otherwise
-//!
-//! Whenever we introduce a borrowed pointer, for example as the result of
-//! a borrow expression `let x = &data`, the lifetime of the pointer `x`
-//! is always specified as a region inference variable. `regionck` has the
-//! job of adding constraints such that this inference variable is as
-//! narrow as possible while still accommodating all uses (that is, every
-//! dereference of the resulting pointer must be within the lifetime).
-//!
-//! #### Reborrows
-//!
-//! Generally speaking, `regionck` does NOT try to ensure that the data
-//! `data` will outlive the pointer `x`. That is the job of borrowck. The
-//! one exception is when "re-borrowing" the contents of another borrowed
-//! pointer. For example, imagine you have a borrowed pointer `b` with
-//! lifetime `L1` and you have an expression `&*b`. The result of this
-//! expression will be another borrowed pointer with lifetime `L2` (which is
-//! an inference variable). The borrow checker is going to enforce the
-//! constraint that `L2 < L1`, because otherwise you are re-borrowing data
-//! for a lifetime larger than the original loan. However, without the
-//! routines in this module, the region inferencer would not know of this
-//! dependency and thus it might infer the lifetime of `L2` to be greater
-//! than `L1` (issue #3148).
-//!
-//! There are a number of troublesome scenarios in the tests
-//! `region-dependent-*.rs`, but here is one example:
-//!
-//!     struct Foo { i: i32 }
-//!     struct Bar { foo: Foo  }
-//!     fn get_i<'a>(x: &'a Bar) -> &'a i32 {
-//!        let foo = &x.foo; // Lifetime L1
-//!        &foo.i            // Lifetime L2
-//!     }
-//!
-//! Note that this comes up either with `&` expressions, `ref`
-//! bindings, and `autorefs`, which are the three ways to introduce
-//! a borrow.
-//!
-//! The key point here is that when you are borrowing a value that
-//! is "guaranteed" by a borrowed pointer, you must link the
-//! lifetime of that borrowed pointer (`L1`, here) to the lifetime of
-//! the borrow itself (`L2`). What do I mean by "guaranteed" by a
-//! borrowed pointer? I mean any data that is reached by first
-//! dereferencing a borrowed pointer and then either traversing
-//! interior offsets or boxes. We say that the guarantor
-//! of such data is the region of the borrowed pointer that was
-//! traversed. This is essentially the same as the ownership
-//! relation, except that a borrowed pointer never owns its
-//! contents.
-
-use crate::check::dropck;
-use crate::check::FnCtxt;
-use crate::mem_categorization as mc;
 use crate::outlives::outlives_bounds::InferCtxtExt as _;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::PatKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{self, InferCtxt, RegionObligation};
-use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
-use rustc_middle::ty::adjustment;
-use rustc_middle::ty::{self, Ty};
-use rustc_span::Span;
-use std::ops::Deref;
-
-// a variation on try that just returns unit
-macro_rules! ignore_err {
-    ($e:expr) => {
-        match $e {
-            Ok(e) => e,
-            Err(_) => {
-                debug!("ignoring mem-categorization error!");
-                return ();
-            }
-        }
-    };
-}
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::Ty;
 
 pub(crate) trait OutlivesEnvironmentExt<'tcx> {
     fn add_implied_bounds(
@@ -108,7 +11,6 @@ pub(crate) trait OutlivesEnvironmentExt<'tcx> {
         infcx: &InferCtxt<'_, 'tcx>,
         fn_sig_tys: FxHashSet<Ty<'tcx>>,
         body_id: hir::HirId,
-        span: Span,
     );
 }
 
@@ -135,750 +37,11 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
         infcx: &InferCtxt<'a, 'tcx>,
         fn_sig_tys: FxHashSet<Ty<'tcx>>,
         body_id: hir::HirId,
-        span: Span,
     ) {
         for ty in fn_sig_tys {
             let ty = infcx.resolve_vars_if_possible(ty);
-            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
+            let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty);
             self.add_outlives_bounds(Some(infcx), implied_bounds)
         }
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// PUBLIC ENTRY POINTS
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn regionck_expr(&self, body: &'tcx hir::Body<'tcx>) {
-        let subject = self.tcx.hir().body_owner_def_id(body.id());
-        let id = body.value.hir_id;
-        let mut rcx = RegionCtxt::new(self, id, Subject(subject), self.param_env);
-
-        // There are no add'l implied bounds when checking a
-        // standalone expr (e.g., the `E` in a type like `[u32; E]`).
-        rcx.outlives_environment.save_implied_bounds(id);
-
-        if !self.errors_reported_since_creation() {
-            // regionck assumes typeck succeeded
-            rcx.visit_body(body);
-            rcx.visit_region_obligations(id);
-        }
-        // Checked by NLL
-        rcx.fcx.skip_region_resolution();
-    }
-
-    /// Region checking during the WF phase for items. `wf_tys` are the
-    /// types from which we should derive implied bounds, if any.
-    #[instrument(level = "debug", skip(self))]
-    pub fn regionck_item(&self, item_id: hir::HirId, span: Span, wf_tys: FxHashSet<Ty<'tcx>>) {
-        let subject = self.tcx.hir().local_def_id(item_id);
-        let mut rcx = RegionCtxt::new(self, item_id, Subject(subject), self.param_env);
-        rcx.outlives_environment.add_implied_bounds(self, wf_tys, item_id, span);
-        rcx.outlives_environment.save_implied_bounds(item_id);
-        rcx.visit_region_obligations(item_id);
-        rcx.resolve_regions_and_report_errors();
-    }
-
-    /// Region check a function body. Not invoked on closures, but
-    /// only on the "root" fn item (in which closures may be
-    /// embedded). Walks the function body and adds various add'l
-    /// constraints that are needed for region inference. This is
-    /// separated both to isolate "pure" region constraints from the
-    /// rest of type check and because sometimes we need type
-    /// inference to have completed before we can determine which
-    /// constraints to add.
-    pub(crate) fn regionck_fn(
-        &self,
-        fn_id: hir::HirId,
-        body: &'tcx hir::Body<'tcx>,
-        span: Span,
-        wf_tys: FxHashSet<Ty<'tcx>>,
-    ) {
-        debug!("regionck_fn(id={})", fn_id);
-        let subject = self.tcx.hir().body_owner_def_id(body.id());
-        let hir_id = body.value.hir_id;
-        let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env);
-        // We need to add the implied bounds from the function signature
-        rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span);
-        rcx.outlives_environment.save_implied_bounds(fn_id);
-
-        if !self.errors_reported_since_creation() {
-            // regionck assumes typeck succeeded
-            rcx.visit_fn_body(fn_id, body, self.tcx.hir().span(fn_id));
-        }
-
-        // Checked by NLL
-        rcx.fcx.skip_region_resolution();
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// INTERNALS
-
-pub struct RegionCtxt<'a, 'tcx> {
-    pub fcx: &'a FnCtxt<'a, 'tcx>,
-
-    outlives_environment: OutlivesEnvironment<'tcx>,
-
-    // id of innermost fn body id
-    body_id: hir::HirId,
-    body_owner: LocalDefId,
-
-    // id of AST node being analyzed (the subject of the analysis).
-    subject_def_id: LocalDefId,
-}
-
-impl<'a, 'tcx> Deref for RegionCtxt<'a, 'tcx> {
-    type Target = FnCtxt<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        self.fcx
-    }
-}
-
-pub struct Subject(LocalDefId);
-
-impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
-    pub fn new(
-        fcx: &'a FnCtxt<'a, 'tcx>,
-        initial_body_id: hir::HirId,
-        Subject(subject): Subject,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> RegionCtxt<'a, 'tcx> {
-        let outlives_environment = OutlivesEnvironment::new(param_env);
-        RegionCtxt {
-            fcx,
-            body_id: initial_body_id,
-            body_owner: subject,
-            subject_def_id: subject,
-            outlives_environment,
-        }
-    }
-
-    /// Try to resolve the type for the given node, returning `t_err` if an error results. Note that
-    /// we never care about the details of the error, the same error will be detected and reported
-    /// in the writeback phase.
-    ///
-    /// Note one important point: we do not attempt to resolve *region variables* here. This is
-    /// because regionck is essentially adding constraints to those region variables and so may yet
-    /// influence how they are resolved.
-    ///
-    /// Consider this silly example:
-    ///
-    /// ```ignore UNSOLVED (does replacing @i32 with Box<i32> preserve the desired semantics for the example?)
-    /// fn borrow(x: &i32) -> &i32 {x}
-    /// fn foo(x: @i32) -> i32 {  // block: B
-    ///     let b = borrow(x);    // region: <R0>
-    ///     *b
-    /// }
-    /// ```
-    ///
-    /// Here, the region of `b` will be `<R0>`. `<R0>` is constrained to be some subregion of the
-    /// block B and some superregion of the call. If we forced it now, we'd choose the smaller
-    /// region (the call). But that would make the *b illegal. Since we don't resolve, the type
-    /// of b will be `&<R0>.i32` and then `*b` will require that `<R0>` be bigger than the let and
-    /// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
-    pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.resolve_vars_if_possible(unresolved_ty)
-    }
-
-    /// Try to resolve the type for the given node.
-    fn resolve_node_type(&self, id: hir::HirId) -> Ty<'tcx> {
-        let t = self.node_ty(id);
-        self.resolve_type(t)
-    }
-
-    /// This is the "main" function when region-checking a function item or a
-    /// closure within a function item. It begins by updating various fields
-    /// (e.g., `outlives_environment`) to be appropriate to the function and
-    /// then adds constraints derived from the function body.
-    ///
-    /// Note that it does **not** restore the state of the fields that
-    /// it updates! This is intentional, since -- for the main
-    /// function -- we wish to be able to read the final
-    /// `outlives_environment` and other fields from the caller. For
-    /// closures, however, we save and restore any "scoped state"
-    /// before we invoke this function. (See `visit_fn` in the
-    /// `intravisit::Visitor` impl below.)
-    fn visit_fn_body(
-        &mut self,
-        id: hir::HirId, // the id of the fn itself
-        body: &'tcx hir::Body<'tcx>,
-        span: Span,
-    ) {
-        // When we enter a function, we can derive
-        debug!("visit_fn_body(id={:?})", id);
-
-        let body_id = body.id();
-        self.body_id = body_id.hir_id;
-        self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
-
-        let Some(fn_sig) = self.typeck_results.borrow().liberated_fn_sigs().get(id) else {
-            bug!("No fn-sig entry for id={:?}", id);
-        };
-
-        // Collect the types from which we create inferred bounds.
-        // For the return type, if diverging, substitute `bool` just
-        // because it will have no effect.
-        //
-        // FIXME(#27579) return types should not be implied bounds
-        let fn_sig_tys: FxHashSet<_> =
-            fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
-
-        self.outlives_environment.add_implied_bounds(self.fcx, fn_sig_tys, body_id.hir_id, span);
-        self.outlives_environment.save_implied_bounds(body_id.hir_id);
-        self.link_fn_params(body.params);
-        self.visit_body(body);
-        self.visit_region_obligations(body_id.hir_id);
-    }
-
-    fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
-        debug!("visit_inline_const(id={:?})", id);
-
-        // Save state of current function. We will restore afterwards.
-        let old_body_id = self.body_id;
-        let old_body_owner = self.body_owner;
-        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
-
-        let body_id = body.id();
-        self.body_id = body_id.hir_id;
-        self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
-
-        self.outlives_environment.save_implied_bounds(body_id.hir_id);
-
-        self.visit_body(body);
-        self.visit_region_obligations(body_id.hir_id);
-
-        // Restore state from previous function.
-        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
-        self.body_id = old_body_id;
-        self.body_owner = old_body_owner;
-    }
-
-    fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
-        debug!("visit_region_obligations: hir_id={:?}", hir_id);
-
-        // region checking can introduce new pending obligations
-        // which, when processed, might generate new region
-        // obligations. So make sure we process those.
-        self.select_all_obligations_or_error();
-    }
-
-    fn resolve_regions_and_report_errors(&self) {
-        self.infcx.process_registered_region_obligations(
-            self.outlives_environment.region_bound_pairs_map(),
-            self.param_env,
-        );
-
-        self.fcx.resolve_regions_and_report_errors(
-            self.subject_def_id.to_def_id(),
-            &self.outlives_environment,
-        );
-    }
-
-    fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat<'_>) {
-        debug!("regionck::visit_pat(pat={:?})", pat);
-        pat.each_binding(|_, hir_id, span, _| {
-            let typ = self.resolve_node_type(hir_id);
-            let body_id = self.body_id;
-            dropck::check_drop_obligations(self, typ, span, body_id);
-        })
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
-    // (..) FIXME(#3238) should use visit_pat, not visit_arm/visit_local,
-    // However, right now we run into an issue whereby some free
-    // regions are not properly related if they appear within the
-    // types of arguments that must be inferred. This could be
-    // addressed by deferring the construction of the region
-    // hierarchy, and in particular the relationships between free
-    // regions, until regionck, as described in #3238.
-
-    fn visit_fn(
-        &mut self,
-        fk: intravisit::FnKind<'tcx>,
-        _: &'tcx hir::FnDecl<'tcx>,
-        body_id: hir::BodyId,
-        span: Span,
-        hir_id: hir::HirId,
-    ) {
-        assert!(
-            matches!(fk, intravisit::FnKind::Closure),
-            "visit_fn invoked for something other than a closure"
-        );
-
-        // Save state of current function before invoking
-        // `visit_fn_body`.  We will restore afterwards.
-        let old_body_id = self.body_id;
-        let old_body_owner = self.body_owner;
-        let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
-
-        let body = self.tcx.hir().body(body_id);
-        self.visit_fn_body(hir_id, body, span);
-
-        // Restore state from previous function.
-        self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
-        self.body_id = old_body_id;
-        self.body_owner = old_body_owner;
-    }
-
-    //visit_pat: visit_pat, // (..) see above
-
-    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
-        // see above
-        self.constrain_bindings_in_pat(arm.pat);
-        intravisit::walk_arm(self, arm);
-    }
-
-    fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) {
-        // see above
-        self.constrain_bindings_in_pat(l.pat);
-        self.link_local(l);
-        intravisit::walk_local(self, l);
-    }
-
-    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
-        // Check any autoderefs or autorefs that appear.
-        let cmt_result = self.constrain_adjustments(expr);
-
-        // If necessary, constrain destructors in this expression. This will be
-        // the adjusted form if there is an adjustment.
-        match cmt_result {
-            Ok(head_cmt) => {
-                self.check_safety_of_rvalue_destructor_if_necessary(&head_cmt, expr.span);
-            }
-            Err(..) => {
-                self.tcx.sess.delay_span_bug(expr.span, "cat_expr Errd");
-            }
-        }
-
-        match expr.kind {
-            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => {
-                self.link_addr_of(expr, m, base);
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::Match(ref discr, arms, _) => {
-                self.link_match(discr, arms);
-
-                intravisit::walk_expr(self, expr);
-            }
-
-            hir::ExprKind::ConstBlock(anon_const) => {
-                let body = self.tcx.hir().body(anon_const.body);
-                self.visit_inline_const(anon_const.hir_id, body);
-            }
-
-            _ => intravisit::walk_expr(self, expr),
-        }
-    }
-}
-
-impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
-    /// Creates a temporary `MemCategorizationContext` and pass it to the closure.
-    fn with_mc<F, R>(&self, f: F) -> R
-    where
-        F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'tcx>) -> R,
-    {
-        f(mc::MemCategorizationContext::new(
-            &self.infcx,
-            self.outlives_environment.param_env,
-            self.body_owner,
-            &self.typeck_results.borrow(),
-        ))
-    }
-
-    /// Invoked on any adjustments that occur. Checks that if this is a region pointer being
-    /// dereferenced, the lifetime of the pointer includes the deref expr.
-    fn constrain_adjustments(
-        &mut self,
-        expr: &hir::Expr<'_>,
-    ) -> mc::McResult<PlaceWithHirId<'tcx>> {
-        debug!("constrain_adjustments(expr={:?})", expr);
-
-        let mut place = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?;
-
-        let typeck_results = self.typeck_results.borrow();
-        let adjustments = typeck_results.expr_adjustments(expr);
-        if adjustments.is_empty() {
-            return Ok(place);
-        }
-
-        debug!("constrain_adjustments: adjustments={:?}", adjustments);
-
-        // If necessary, constrain destructors in the unadjusted form of this
-        // expression.
-        self.check_safety_of_rvalue_destructor_if_necessary(&place, expr.span);
-
-        for adjustment in adjustments {
-            debug!("constrain_adjustments: adjustment={:?}, place={:?}", adjustment, place);
-
-            if let adjustment::Adjust::Deref(Some(deref)) = adjustment.kind {
-                self.link_region(
-                    expr.span,
-                    deref.region,
-                    ty::BorrowKind::from_mutbl(deref.mutbl),
-                    &place,
-                );
-            }
-
-            if let adjustment::Adjust::Borrow(ref autoref) = adjustment.kind {
-                self.link_autoref(expr, &place, autoref);
-            }
-
-            place = self.with_mc(|mc| mc.cat_expr_adjusted(expr, place, adjustment))?;
-        }
-
-        Ok(place)
-    }
-
-    fn check_safety_of_rvalue_destructor_if_necessary(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        span: Span,
-    ) {
-        if let PlaceBase::Rvalue = place_with_id.place.base {
-            if place_with_id.place.projections.is_empty() {
-                let typ = self.resolve_type(place_with_id.place.ty());
-                let body_id = self.body_id;
-                dropck::check_drop_obligations(self, typ, span, body_id);
-            }
-        }
-    }
-    /// Adds constraints to inference such that `T: 'a` holds (or
-    /// reports an error if it cannot).
-    ///
-    /// # Parameters
-    ///
-    /// - `origin`, the reason we need this constraint
-    /// - `ty`, the type `T`
-    /// - `region`, the region `'a`
-    pub fn type_must_outlive(
-        &self,
-        origin: infer::SubregionOrigin<'tcx>,
-        ty: Ty<'tcx>,
-        region: ty::Region<'tcx>,
-    ) {
-        self.infcx.register_region_obligation(
-            self.body_id,
-            RegionObligation { sub_region: region, sup_type: ty, origin },
-        );
-    }
-
-    /// Computes the guarantor for an expression `&base` and then ensures that the lifetime of the
-    /// resulting pointer is linked to the lifetime of its guarantor (if any).
-    fn link_addr_of(
-        &mut self,
-        expr: &hir::Expr<'_>,
-        mutability: hir::Mutability,
-        base: &hir::Expr<'_>,
-    ) {
-        debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
-
-        let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base)));
-
-        debug!("link_addr_of: cmt={:?}", cmt);
-
-        self.link_region_from_node_type(expr.span, expr.hir_id, mutability, &cmt);
-    }
-
-    /// Computes the guarantors for any ref bindings in a `let` and
-    /// then ensures that the lifetime of the resulting pointer is
-    /// linked to the lifetime of the initialization expression.
-    fn link_local(&self, local: &hir::Local<'_>) {
-        debug!("regionck::for_local()");
-        let init_expr = match local.init {
-            None => {
-                return;
-            }
-            Some(expr) => &*expr,
-        };
-        let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr)));
-        self.link_pattern(discr_cmt, local.pat);
-    }
-
-    /// Computes the guarantors for any ref bindings in a match and
-    /// then ensures that the lifetime of the resulting pointer is
-    /// linked to the lifetime of its guarantor (if any).
-    fn link_match(&self, discr: &hir::Expr<'_>, arms: &[hir::Arm<'_>]) {
-        debug!("regionck::for_match()");
-        let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr)));
-        debug!("discr_cmt={:?}", discr_cmt);
-        for arm in arms {
-            self.link_pattern(discr_cmt.clone(), arm.pat);
-        }
-    }
-
-    /// Computes the guarantors for any ref bindings in a match and
-    /// then ensures that the lifetime of the resulting pointer is
-    /// linked to the lifetime of its guarantor (if any).
-    fn link_fn_params(&self, params: &[hir::Param<'_>]) {
-        for param in params {
-            let param_ty = self.node_ty(param.hir_id);
-            let param_cmt =
-                self.with_mc(|mc| mc.cat_rvalue(param.hir_id, param.pat.span, param_ty));
-            debug!("param_ty={:?} param_cmt={:?} param={:?}", param_ty, param_cmt, param);
-            self.link_pattern(param_cmt, param.pat);
-        }
-    }
-
-    /// Link lifetimes of any ref bindings in `root_pat` to the pointers found
-    /// in the discriminant, if needed.
-    fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
-        debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
-        ignore_err!(self.with_mc(|mc| {
-            mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| {
-                // `ref x` pattern
-                if let PatKind::Binding(..) = kind
-                    && let Some(ty::BindByReference(mutbl)) = mc.typeck_results.extract_binding_mode(self.tcx.sess, *hir_id, *span) {
-                    self.link_region_from_node_type(*span, *hir_id, mutbl, sub_cmt);
-                }
-            })
-        }));
-    }
-
-    /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being
-    /// autoref'd.
-    fn link_autoref(
-        &self,
-        expr: &hir::Expr<'_>,
-        expr_cmt: &PlaceWithHirId<'tcx>,
-        autoref: &adjustment::AutoBorrow<'tcx>,
-    ) {
-        debug!("link_autoref(autoref={:?}, expr_cmt={:?})", autoref, expr_cmt);
-
-        match *autoref {
-            adjustment::AutoBorrow::Ref(r, m) => {
-                self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m.into()), expr_cmt);
-            }
-
-            adjustment::AutoBorrow::RawPtr(_) => {}
-        }
-    }
-
-    /// Like `link_region()`, except that the region is extracted from the type of `id`,
-    /// which must be some reference (`&T`, `&str`, etc).
-    fn link_region_from_node_type(
-        &self,
-        span: Span,
-        id: hir::HirId,
-        mutbl: hir::Mutability,
-        cmt_borrowed: &PlaceWithHirId<'tcx>,
-    ) {
-        debug!(
-            "link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
-            id, mutbl, cmt_borrowed
-        );
-
-        let rptr_ty = self.resolve_node_type(id);
-        if let ty::Ref(r, _, _) = rptr_ty.kind() {
-            debug!("rptr_ty={}", rptr_ty);
-            self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
-        }
-    }
-
-    /// Informs the inference engine that `borrow_cmt` is being borrowed with
-    /// kind `borrow_kind` and lifetime `borrow_region`.
-    /// In order to ensure borrowck is satisfied, this may create constraints
-    /// between regions, as explained in `link_reborrowed_region()`.
-    fn link_region(
-        &self,
-        span: Span,
-        borrow_region: ty::Region<'tcx>,
-        borrow_kind: ty::BorrowKind,
-        borrow_place: &PlaceWithHirId<'tcx>,
-    ) {
-        let origin = infer::DataBorrowed(borrow_place.place.ty(), span);
-        self.type_must_outlive(origin, borrow_place.place.ty(), borrow_region);
-
-        for pointer_ty in borrow_place.place.deref_tys() {
-            debug!(
-                "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})",
-                borrow_region, borrow_kind, borrow_place
-            );
-            match *pointer_ty.kind() {
-                ty::RawPtr(_) => return,
-                ty::Ref(ref_region, _, ref_mutability) => {
-                    if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability)
-                    {
-                        return;
-                    }
-                }
-                _ => assert!(pointer_ty.is_box(), "unexpected built-in deref type {}", pointer_ty),
-            }
-        }
-        if let PlaceBase::Upvar(upvar_id) = borrow_place.place.base {
-            self.link_upvar_region(span, borrow_region, upvar_id);
-        }
-    }
-
-    /// This is the most complicated case: the path being borrowed is
-    /// itself the referent of a borrowed pointer. Let me give an
-    /// example fragment of code to make clear(er) the situation:
-    ///
-    /// ```ignore (incomplete Rust code)
-    /// let r: &'a mut T = ...;  // the original reference "r" has lifetime 'a
-    /// ...
-    /// &'z *r                   // the reborrow has lifetime 'z
-    /// ```
-    ///
-    /// Now, in this case, our primary job is to add the inference
-    /// constraint that `'z <= 'a`. Given this setup, let's clarify the
-    /// parameters in (roughly) terms of the example:
-    ///
-    /// ```plain,ignore (pseudo-Rust)
-    /// A borrow of: `& 'z bk * r` where `r` has type `& 'a bk T`
-    /// borrow_region   ^~                 ref_region    ^~
-    /// borrow_kind        ^~               ref_kind        ^~
-    /// ref_cmt                 ^
-    /// ```
-    ///
-    /// Here `bk` stands for some borrow-kind (e.g., `mut`, `uniq`, etc).
-    ///
-    /// There is a complication beyond the simple scenario I just painted: there
-    /// may in fact be more levels of reborrowing. In the example, I said the
-    /// borrow was like `&'z *r`, but it might in fact be a borrow like
-    /// `&'z **q` where `q` has type `&'a &'b mut T`. In that case, we want to
-    /// ensure that `'z <= 'a` and `'z <= 'b`.
-    ///
-    /// The return value of this function indicates whether we *don't* need to
-    /// the recurse to the next reference up.
-    ///
-    /// This is explained more below.
-    fn link_reborrowed_region(
-        &self,
-        span: Span,
-        borrow_region: ty::Region<'tcx>,
-        ref_region: ty::Region<'tcx>,
-        ref_mutability: hir::Mutability,
-    ) -> bool {
-        debug!("link_reborrowed_region: {:?} <= {:?}", borrow_region, ref_region);
-        self.sub_regions(infer::Reborrow(span), borrow_region, ref_region);
-
-        // Decide whether we need to recurse and link any regions within
-        // the `ref_cmt`. This is concerned for the case where the value
-        // being reborrowed is in fact a borrowed pointer found within
-        // another borrowed pointer. For example:
-        //
-        //    let p: &'b &'a mut T = ...;
-        //    ...
-        //    &'z **p
-        //
-        // What makes this case particularly tricky is that, if the data
-        // being borrowed is a `&mut` or `&uniq` borrow, borrowck requires
-        // not only that `'z <= 'a`, (as before) but also `'z <= 'b`
-        // (otherwise the user might mutate through the `&mut T` reference
-        // after `'b` expires and invalidate the borrow we are looking at
-        // now).
-        //
-        // So let's re-examine our parameters in light of this more
-        // complicated (possible) scenario:
-        //
-        //     A borrow of: `& 'z bk * * p` where `p` has type `&'b bk & 'a bk T`
-        //     borrow_region   ^~                 ref_region             ^~
-        //     borrow_kind        ^~               ref_kind                 ^~
-        //     ref_cmt                 ^~~
-        //
-        // (Note that since we have not examined `ref_cmt.cat`, we don't
-        // know whether this scenario has occurred; but I wanted to show
-        // how all the types get adjusted.)
-        match ref_mutability {
-            hir::Mutability::Not => {
-                // The reference being reborrowed is a shareable ref of
-                // type `&'a T`. In this case, it doesn't matter where we
-                // *found* the `&T` pointer, the memory it references will
-                // be valid and immutable for `'a`. So we can stop here.
-                true
-            }
-
-            hir::Mutability::Mut => {
-                // The reference being reborrowed is either an `&mut T`. This is
-                // the case where recursion is needed.
-                false
-            }
-        }
-    }
-
-    /// An upvar may be behind up to 2 references:
-    ///
-    /// * One can come from the reference to a "by-reference" upvar.
-    /// * Another one can come from the reference to the closure itself if it's
-    ///   a `FnMut` or `Fn` closure.
-    ///
-    /// This function links the lifetimes of those references to the lifetime
-    /// of the borrow that's provided. See [RegionCtxt::link_reborrowed_region] for some
-    /// more explanation of this in the general case.
-    ///
-    /// We also supply a *cause*, and in this case we set the cause to
-    /// indicate that the reference being "reborrowed" is itself an upvar. This
-    /// provides a nicer error message should something go wrong.
-    fn link_upvar_region(
-        &self,
-        span: Span,
-        borrow_region: ty::Region<'tcx>,
-        upvar_id: ty::UpvarId,
-    ) {
-        debug!("link_upvar_region(borrorw_region={:?}, upvar_id={:?}", borrow_region, upvar_id);
-        // A by-reference upvar can't be borrowed for longer than the
-        // upvar is borrowed from the environment.
-        let closure_local_def_id = upvar_id.closure_expr_id;
-        let mut all_captures_are_imm_borrow = true;
-        for captured_place in self
-            .typeck_results
-            .borrow()
-            .closure_min_captures
-            .get(&closure_local_def_id.to_def_id())
-            .and_then(|root_var_min_cap| root_var_min_cap.get(&upvar_id.var_path.hir_id))
-            .into_iter()
-            .flatten()
-        {
-            match captured_place.info.capture_kind {
-                ty::UpvarCapture::ByRef(upvar_borrow) => {
-                    self.sub_regions(
-                        infer::ReborrowUpvar(span, upvar_id),
-                        borrow_region,
-                        captured_place.region.unwrap(),
-                    );
-                    if let ty::ImmBorrow = upvar_borrow {
-                        debug!("link_upvar_region: capture by shared ref");
-                    } else {
-                        all_captures_are_imm_borrow = false;
-                    }
-                }
-                ty::UpvarCapture::ByValue => {
-                    all_captures_are_imm_borrow = false;
-                }
-            }
-        }
-        if all_captures_are_imm_borrow {
-            return;
-        }
-        let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_local_def_id);
-        let ty = self.resolve_node_type(fn_hir_id);
-        debug!("link_upvar_region: ty={:?}", ty);
-
-        // A closure capture can't be borrowed for longer than the
-        // reference to the closure.
-        if let ty::Closure(_, substs) = ty.kind() {
-            match self.infcx.closure_kind(substs) {
-                Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => {
-                    // Region of environment pointer
-                    let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                        scope: upvar_id.closure_expr_id.to_def_id(),
-                        bound_region: ty::BrEnv,
-                    }));
-                    self.sub_regions(
-                        infer::ReborrowUpvar(span, upvar_id),
-                        borrow_region,
-                        env_region,
-                    );
-                }
-                Some(ty::ClosureKind::FnOnce) => {}
-                None => {
-                    span_bug!(span, "Have not inferred closure kind before regionck");
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 87f85a9842f..74546ed9080 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -747,14 +747,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let (migration_string, migrated_variables_concat) =
                 migration_suggestion_for_2229(self.tcx, &need_migrations);
 
-            let local_def_id = closure_def_id.expect_local();
-            let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
-            let closure_span = self.tcx.hir().span(closure_hir_id);
-            let closure_head_span = self.tcx.sess.source_map().guess_head_span(closure_span);
+            let closure_hir_id =
+                self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+            let closure_head_span = self.tcx.def_span(closure_def_id);
             self.tcx.struct_span_lint_hir(
                 lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
                 closure_hir_id,
-                 closure_head_span,
+                closure_head_span,
                 |lint| {
                     let mut diagnostics_builder = lint.build(
                         &reasons.migration_message(),
@@ -827,12 +826,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         migrated_variables_concat
                     );
 
+                    let closure_span = self.tcx.hir().span_with_body(closure_hir_id);
                     let mut closure_body_span = {
                         // If the body was entirely expanded from a macro
                         // invocation, i.e. the body is not contained inside the
                         // closure span, then we walk up the expansion until we
                         // find the span before the expansion.
-                        let s = self.tcx.hir().span(body_id.hir_id);
+                        let s = self.tcx.hir().span_with_body(body_id.hir_id);
                         s.find_ancestor_inside(closure_span).unwrap_or(s)
                     };
 
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 7fe36781cf4..5621cf2e1a4 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -18,7 +18,7 @@ use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt,
-    TypeFoldable, TypeSuperFoldable, TypeVisitor,
+    TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -62,7 +62,10 @@ impl<'tcx> CheckWfFcxBuilder<'tcx> {
             }
             let wf_tys = f(&fcx);
             fcx.select_all_obligations_or_error();
-            fcx.regionck_item(id, span, wf_tys);
+
+            let mut outlives_environment = OutlivesEnvironment::new(param_env);
+            outlives_environment.add_implied_bounds(&fcx.infcx, wf_tys, id);
+            fcx.infcx.check_region_obligations_and_report_errors(&outlives_environment);
         });
     }
 }
@@ -655,13 +658,12 @@ fn resolve_regions_with_wf_tys<'tcx>(
     // call individually.
     tcx.infer_ctxt().enter(|infcx| {
         let mut outlives_environment = OutlivesEnvironment::new(param_env);
-        outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
-        outlives_environment.save_implied_bounds(id);
-        let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
+        outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id);
+        let region_bound_pairs = outlives_environment.region_bound_pairs();
 
         add_constraints(&infcx, region_bound_pairs);
 
-        let errors = infcx.resolve_regions(id.expect_owner().to_def_id(), &outlives_environment);
+        let errors = infcx.resolve_regions(&outlives_environment);
 
         debug!(?errors, "errors");
 
@@ -822,50 +824,62 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                 }
 
                 if let Some(non_structural_match_ty) =
-                    traits::search_for_structural_match_violation(param.span, tcx, ty)
+                    traits::search_for_structural_match_violation(param.span, tcx, ty, false)
                 {
                     // We use the same error code in both branches, because this is really the same
                     // issue: we just special-case the message for type parameters to make it
                     // clearer.
-                    if let ty::Param(_) = ty.peel_refs().kind() {
-                        // Const parameters may not have type parameters as their types,
-                        // because we cannot be sure that the type parameter derives `PartialEq`
-                        // and `Eq` (just implementing them is not enough for `structural_match`).
-                        struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
-                            used as the type of a const parameter",
-                            ty,
-                        )
-                        .span_label(
-                            hir_ty.span,
-                            format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
-                        )
-                        .note(
-                            "it is not currently possible to use a type parameter as the type of a \
-                            const parameter",
-                        )
-                        .emit();
-                    } else {
-                        let mut diag = struct_span_err!(
-                            tcx.sess,
-                            hir_ty.span,
-                            E0741,
-                            "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
-                            the type of a const parameter",
-                            non_structural_match_ty.ty,
-                        );
-
-                        if ty == non_structural_match_ty.ty {
-                            diag.span_label(
+                    match ty.peel_refs().kind() {
+                        ty::Param(_) => {
+                            // Const parameters may not have type parameters as their types,
+                            // because we cannot be sure that the type parameter derives `PartialEq`
+                            // and `Eq` (just implementing them is not enough for `structural_match`).
+                            struct_span_err!(
+                                tcx.sess,
                                 hir_ty.span,
-                                format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
-                            );
+                                E0741,
+                                "`{ty}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
+                                used as the type of a const parameter",
+                            )
+                            .span_label(
+                                hir_ty.span,
+                                format!("`{ty}` may not derive both `PartialEq` and `Eq`"),
+                            )
+                            .note(
+                                "it is not currently possible to use a type parameter as the type of a \
+                                const parameter",
+                            )
+                            .emit();
                         }
+                        ty::Float(_) => {
+                            struct_span_err!(
+                                tcx.sess,
+                                hir_ty.span,
+                                E0741,
+                                "`{ty}` is forbidden as the type of a const generic parameter",
+                            )
+                            .note("floats do not derive `Eq` or `Ord`, which are required for const parameters")
+                            .emit();
+                        }
+                        _ => {
+                            let mut diag = struct_span_err!(
+                                tcx.sess,
+                                hir_ty.span,
+                                E0741,
+                                "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
+                                the type of a const parameter",
+                                non_structural_match_ty.ty,
+                            );
 
-                        diag.emit();
+                            if ty == non_structural_match_ty.ty {
+                                diag.span_label(
+                                    hir_ty.span,
+                                    format!("`{ty}` doesn't derive both `PartialEq` and `Eq`"),
+                                );
+                            }
+
+                            diag.emit();
+                        }
                     }
                 }
             } else {
@@ -1178,7 +1192,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: LocalDefId, ty_span: Span, allow_fo
             fcx.register_bound(
                 item_ty,
                 tcx.require_lang_item(LangItem::Sized, None),
-                traits::ObligationCause::new(ty_span, fcx.body_id, traits::MiscObligation),
+                traits::ObligationCause::new(ty_span, fcx.body_id, traits::WellFormed(None)),
             );
         }
 
@@ -1367,7 +1381,7 @@ fn check_where_clauses<'tcx, 'fcx>(
             struct CountParams {
                 params: FxHashSet<u32>,
             }
-            impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+            impl<'tcx> ty::visit::TypeVisitor<'tcx> for CountParams {
                 type BreakTy = ();
 
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 67160b98b9d..41d241f84ac 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -15,6 +15,7 @@ use rustc_middle::hir::place::Place as HirPlace;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable};
 use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -692,7 +693,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
                     t.into(),
-                    vec![],
                     E0282,
                     false,
                 )
@@ -707,7 +707,6 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
                     Some(self.body.id()),
                     self.span.to_span(self.tcx),
                     c.into(),
-                    vec![],
                     E0282,
                     false,
                 )
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index c647c2a4c1b..d532050d050 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -11,7 +11,7 @@ use rustc_infer::infer;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
-use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitable};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
@@ -349,7 +349,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
 
                     // Finally, resolve all regions.
                     let outlives_env = OutlivesEnvironment::new(param_env);
-                    infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env);
+                    infcx.resolve_regions_and_report_errors(&outlives_env);
                 }
             }
             _ => {
@@ -606,7 +606,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
 
         // Finally, resolve all regions.
         let outlives_env = OutlivesEnvironment::new(param_env);
-        infcx.resolve_regions_and_report_errors(impl_did.to_def_id(), &outlives_env);
+        infcx.resolve_regions_and_report_errors(&outlives_env);
 
         CoerceUnsizedInfo { custom_kind: kind }
     })
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 447ec87f302..ae9ebe59091 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -8,8 +8,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
-use rustc_span::Span;
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_trait_selection::traits;
 
 mod builtin;
@@ -18,11 +17,6 @@ mod inherent_impls_overlap;
 mod orphan;
 mod unsafety;
 
-/// Obtains the span of just the impl header of `impl_def_id`.
-fn impl_header_span(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) -> Span {
-    tcx.sess.source_map().guess_head_span(tcx.span_of_impl(impl_def_id.to_def_id()).unwrap())
-}
-
 fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<'_>) {
     debug!(
         "(checking implementation) adding impl for trait '{:?}', item '{}'",
@@ -47,56 +41,53 @@ fn enforce_trait_manually_implementable(
 ) {
     let did = Some(trait_def_id);
     let li = tcx.lang_items();
+    let impl_header_span = tcx.def_span(impl_def_id);
 
     // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
     if did == li.pointee_trait() {
-        let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
             tcx.sess,
-            span,
+            impl_header_span,
             E0322,
             "explicit impls for the `Pointee` trait are not permitted"
         )
-        .span_label(span, "impl of `Pointee` not allowed")
+        .span_label(impl_header_span, "impl of `Pointee` not allowed")
         .emit();
         return;
     }
 
     if did == li.discriminant_kind_trait() {
-        let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
             tcx.sess,
-            span,
+            impl_header_span,
             E0322,
             "explicit impls for the `DiscriminantKind` trait are not permitted"
         )
-        .span_label(span, "impl of `DiscriminantKind` not allowed")
+        .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed")
         .emit();
         return;
     }
 
     if did == li.sized_trait() {
-        let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
             tcx.sess,
-            span,
+            impl_header_span,
             E0322,
             "explicit impls for the `Sized` trait are not permitted"
         )
-        .span_label(span, "impl of `Sized` not allowed")
+        .span_label(impl_header_span, "impl of `Sized` not allowed")
         .emit();
         return;
     }
 
     if did == li.unsize_trait() {
-        let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
             tcx.sess,
-            span,
+            impl_header_span,
             E0328,
             "explicit impls for the `Unsize` trait are not permitted"
         )
-        .span_label(span, "impl of `Unsize` not allowed")
+        .span_label(impl_header_span, "impl of `Unsize` not allowed")
         .emit();
         return;
     }
@@ -110,10 +101,9 @@ fn enforce_trait_manually_implementable(
         tcx.trait_def(trait_def_id).specialization_kind
     {
         if !tcx.features().specialization && !tcx.features().min_specialization {
-            let span = impl_header_span(tcx, impl_def_id);
             tcx.sess
                 .struct_span_err(
-                    span,
+                    impl_header_span,
                     "implementing `rustc_specialization_trait` traits is unstable",
                 )
                 .help("add `#![feature(min_specialization)]` to the crate attributes to enable")
@@ -138,8 +128,13 @@ fn enforce_empty_impls_for_marker_traits(
         return;
     }
 
-    let span = impl_header_span(tcx, impl_def_id);
-    struct_span_err!(tcx.sess, span, E0715, "impls for marker traits cannot contain items").emit();
+    struct_span_err!(
+        tcx.sess,
+        tcx.def_span(impl_def_id),
+        E0715,
+        "impls for marker traits cannot contain items"
+    )
+    .emit();
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -217,7 +212,7 @@ fn check_object_overlap<'tcx>(
             } else {
                 let mut supertrait_def_ids = traits::supertrait_def_ids(tcx, component_def_id);
                 if supertrait_def_ids.any(|d| d == trait_def_id) {
-                    let span = impl_header_span(tcx, impl_def_id);
+                    let span = tcx.def_span(impl_def_id);
                     struct_span_err!(
                         tcx.sess,
                         span,
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index f3a043a08a3..697ef7bc022 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IgnoreRegions;
 use rustc_middle::ty::{
-    self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor,
+    self, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::lint;
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -47,7 +47,7 @@ fn do_orphan_check_impl<'tcx>(
     let hir::ItemKind::Impl(ref impl_) = item.kind else {
         bug!("{:?} is not an impl: {:?}", def_id, item);
     };
-    let sp = tcx.sess.source_map().guess_head_span(item.span);
+    let sp = tcx.def_span(def_id);
     let tr = impl_.of_trait.as_ref().unwrap();
 
     // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index a0cbb7c2c5a..44b9c8392f8 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -59,7 +59,7 @@ struct OnlySelfBounds(bool);
 // Main entry point
 
 fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
+    tcx.hir().visit_item_likes_in_module(module_def_id, &mut CollectItemTypesVisitor { tcx });
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 6ee2b544916..f942a4fb53a 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -8,7 +8,7 @@ use rustc_hir::{HirId, Node};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitable};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 858cf63390a..8428e466406 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -1,5 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::fold::{TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::source_map::Span;
 use std::ops::ControlFlow;
@@ -43,7 +43,7 @@ pub fn parameters_for_impl<'tcx>(
 /// of parameters whose values are needed in order to constrain `ty` - these
 /// differ, with the latter being a superset, in the presence of projections.
 pub fn parameters_for<'tcx>(
-    t: &impl TypeFoldable<'tcx>,
+    t: &impl TypeVisitable<'tcx>,
     include_nonconstraining: bool,
 ) -> Vec<Parameter> {
     let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index 4392b9aada9..3dc728271b0 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -72,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>(
                 let cause = traits::ObligationCause::new(
                     ty.span,
                     self.hir_id,
-                    traits::ObligationCauseCode::MiscObligation,
+                    traits::ObligationCauseCode::WellFormed(None),
                 );
                 fulfill.register_predicate_obligation(
                     &infcx,
@@ -86,7 +86,7 @@ fn diagnostic_hir_wf_check<'tcx>(
 
                 let errors = fulfill.select_all_or_error(&infcx);
                 if !errors.is_empty() {
-                    tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
+                    debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
                     for error in errors {
                         if error.obligation.predicate == self.predicate {
                             // Save the cause from the greatest depth - this corresponds
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 981c35e184b..e7ca70de4ba 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -16,7 +16,7 @@ use rustc_errors::struct_span_err;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_span::Span;
 
 use std::collections::hash_map::Entry::{Occupied, Vacant};
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index f07396ce74f..c46b825f457 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -75,7 +75,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
 use rustc_span::Span;
 use rustc_trait_selection::traits::{self, translate_substs, wf};
 
@@ -150,7 +150,7 @@ fn get_impl_substs<'tcx>(
 
     // Conservatively use an empty `ParamEnv`.
     let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
-    infcx.resolve_regions_and_report_errors(impl1_def_id.to_def_id(), &outlives_env);
+    infcx.resolve_regions_and_report_errors(&outlives_env);
     let Ok(impl2_substs) = infcx.fully_resolve(impl2_substs) else {
         let span = tcx.def_span(impl1_def_id);
         tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
@@ -279,11 +279,16 @@ fn check_predicates<'tcx>(
     span: Span,
 ) {
     let tcx = infcx.tcx;
-    let impl1_predicates: Vec<_> = traits::elaborate_predicates(
+    let instantiated = tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs);
+    let impl1_predicates: Vec<_> = traits::elaborate_predicates_with_span(
         tcx,
-        tcx.predicates_of(impl1_def_id).instantiate(tcx, impl1_substs).predicates.into_iter(),
+        std::iter::zip(
+            instantiated.predicates,
+            // Don't drop predicates (unsound!) because `spans` is too short
+            instantiated.spans.into_iter().chain(std::iter::repeat(span)),
+        ),
     )
-    .map(|obligation| obligation.predicate)
+    .map(|obligation| (obligation.predicate, obligation.cause.span))
     .collect();
 
     let mut impl2_predicates = if impl2_node.is_from_trait() {
@@ -321,7 +326,7 @@ fn check_predicates<'tcx>(
     // which is sound because we forbid impls like the following
     //
     // impl<D: Debug> AlwaysApplicable for D { }
-    let always_applicable_traits = impl1_predicates.iter().copied().filter(|&predicate| {
+    let always_applicable_traits = impl1_predicates.iter().copied().filter(|&(predicate, _)| {
         matches!(
             trait_predicate_kind(tcx, predicate),
             Some(TraitSpecializationKind::AlwaysApplicable)
@@ -345,11 +350,11 @@ fn check_predicates<'tcx>(
         }
     }
     impl2_predicates.extend(
-        traits::elaborate_predicates(tcx, always_applicable_traits)
+        traits::elaborate_predicates_with_span(tcx, always_applicable_traits)
             .map(|obligation| obligation.predicate),
     );
 
-    for predicate in impl1_predicates {
+    for (predicate, span) in impl1_predicates {
         if !impl2_predicates.contains(&predicate) {
             check_specialization_on(tcx, predicate, span)
         }
@@ -384,9 +389,17 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
                     .emit();
             }
         }
+        ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+            tcx.sess
+                .struct_span_err(
+                    span,
+                    &format!("cannot specialize on associated type `{projection_ty} == {term}`",),
+                )
+                .emit();
+        }
         _ => {
             tcx.sess
-                .struct_span_err(span, &format!("cannot specialize on `{:?}`", predicate))
+                .struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
                 .emit();
         }
     }
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index b6d4f5fcda6..dd712fd7ed7 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -223,15 +223,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         if !def_id.is_local() {
             return None;
         }
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        match tcx.hir().find(hir_id) {
-            Some(Node::Item(hir::Item { span: item_span, .. })) => {
-                Some(tcx.sess.source_map().guess_head_span(*item_span))
-            }
-            _ => {
-                span_bug!(tcx.def_span(def_id), "main has a non-function type");
-            }
-        }
+        Some(tcx.def_span(def_id))
     }
 
     fn main_fn_return_type_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
@@ -260,7 +252,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let mut diag =
             struct_span_err!(tcx.sess, generics_param_span.unwrap_or(main_span), E0131, "{}", msg);
         if let Some(generics_param_span) = generics_param_span {
-            let label = "`main` cannot have generic parameters".to_string();
+            let label = "`main` cannot have generic parameters";
             diag.span_label(generics_param_span, label);
         }
         diag.emit();
@@ -315,8 +307,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         if !return_ty.bound_vars().is_empty() {
             let msg = "`main` function return type is not allowed to have generic \
-                    parameters"
-                .to_owned();
+                    parameters";
             struct_span_err!(tcx.sess, return_ty_span, E0131, "{}", msg).emit();
             error = true;
         }
@@ -416,7 +407,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                         error = true;
                     }
                     if let hir::IsAsync::Async = sig.header.asyncness {
-                        let span = tcx.sess.source_map().guess_head_span(it.span);
+                        let span = tcx.def_span(it.def_id);
                         struct_span_err!(
                             tcx.sess,
                             span,
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 9acae8d79e7..ced919f66db 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -51,6 +51,7 @@
 use rustc_middle::hir::place::*;
 use rustc_middle::ty::adjustment;
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxIndexMap;
diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
index 3bf697e7682..70b8bcd0220 100644
--- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
+++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
@@ -1,6 +1,5 @@
 use rustc_hir as hir;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::source_map::Span;
 use rustc_trait_selection::infer::InferCtxt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::NoSolution;
@@ -14,7 +13,6 @@ pub trait InferCtxtExt<'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         body_id: hir::HirId,
         ty: Ty<'tcx>,
-        span: Span,
     ) -> Vec<OutlivesBound<'tcx>>;
 }
 
@@ -38,16 +36,14 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     ///   Note that this may cause outlives obligations to be injected
     ///   into the inference context with this body-id.
     /// - `ty`, the type that we are supposed to assume is WF.
-    /// - `span`, a span to use when normalizing, hopefully not important,
-    ///   might be useful if a `bug!` occurs.
-    #[instrument(level = "debug", skip(self, param_env, body_id, span))]
+    #[instrument(level = "debug", skip(self, param_env, body_id))]
     fn implied_outlives_bounds(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         body_id: hir::HirId,
         ty: Ty<'tcx>,
-        span: Span,
     ) -> Vec<OutlivesBound<'tcx>> {
+        let span = self.tcx.hir().span(body_id);
         let result = param_env
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
             .fully_perform(self);
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
index bafc5a0b918..324df313ef1 100644
--- a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -1,6 +1,6 @@
 use crate::structured_errors::StructuredDiagnostic;
 use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
-use rustc_middle::ty::{Ty, TypeFoldable};
+use rustc_middle::ty::{Ty, TypeVisitable};
 use rustc_session::Session;
 use rustc_span::Span;
 
diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
index afc5c1fe6cc..bb608805488 100644
--- a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
@@ -1,6 +1,6 @@
 use crate::structured_errors::StructuredDiagnostic;
 use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
-use rustc_middle::ty::{Ty, TypeFoldable};
+use rustc_middle::ty::{Ty, TypeVisitable};
 use rustc_session::Session;
 use rustc_span::Span;
 
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index 72a32dade4e..469f7d1172a 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -126,8 +126,8 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
-    fn kind(&self) -> String {
-        if self.missing_lifetimes() { "lifetime".to_string() } else { "generic".to_string() }
+    fn kind(&self) -> &str {
+        if self.missing_lifetimes() { "lifetime" } else { "generic" }
     }
 
     fn num_provided_args(&self) -> usize {
@@ -812,7 +812,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
     /// Builds the `type defined here` message.
     fn show_definition(&self, err: &mut Diagnostic) {
         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
-            if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
+            if self.tcx.sess.source_map().is_span_accessible(def_span) {
                 def_span.into()
             } else {
                 return;
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index a7dcbfff207..d79450e1ae7 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -64,74 +64,28 @@ pub fn add_constraints_from_crate<'a, 'tcx>(
 
     let crate_items = tcx.hir_crate_items(());
 
-    for id in crate_items.items() {
-        constraint_cx.check_item(id);
-    }
-
-    for id in crate_items.trait_items() {
-        if let DefKind::AssocFn = tcx.def_kind(id.def_id) {
-            constraint_cx.check_node_helper(id.hir_id());
-        }
-    }
-
-    for id in crate_items.impl_items() {
-        if let DefKind::AssocFn = tcx.def_kind(id.def_id) {
-            constraint_cx.check_node_helper(id.hir_id());
-        }
-    }
-
-    for id in crate_items.foreign_items() {
-        if let DefKind::Fn = tcx.def_kind(id.def_id) {
-            constraint_cx.check_node_helper(id.hir_id());
-        }
-    }
-
-    constraint_cx
-}
-
-impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
-    fn check_item(&mut self, id: hir::ItemId) {
-        let def_kind = self.tcx().def_kind(id.def_id);
+    for def_id in crate_items.definitions() {
+        let def_kind = tcx.def_kind(def_id);
         match def_kind {
-            DefKind::Struct | DefKind::Union => {
-                let item = self.tcx().hir().item(id);
-
-                if let hir::ItemKind::Struct(ref struct_def, _)
-                | hir::ItemKind::Union(ref struct_def, _) = item.kind
-                {
-                    self.check_node_helper(item.hir_id());
+            DefKind::Struct | DefKind::Union | DefKind::Enum => {
+                constraint_cx.build_constraints_for_item(def_id);
 
-                    if let hir::VariantData::Tuple(..) = *struct_def {
-                        self.check_node_helper(struct_def.ctor_hir_id().unwrap());
+                let adt = tcx.adt_def(def_id);
+                for variant in adt.variants() {
+                    if let Some(ctor) = variant.ctor_def_id {
+                        constraint_cx.build_constraints_for_item(ctor.expect_local());
                     }
                 }
             }
-            DefKind::Enum => {
-                let item = self.tcx().hir().item(id);
-
-                if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
-                    self.check_node_helper(item.hir_id());
-
-                    for variant in enum_def.variants {
-                        if let hir::VariantData::Tuple(..) = variant.data {
-                            self.check_node_helper(variant.data.ctor_hir_id().unwrap());
-                        }
-                    }
-                }
-            }
-            DefKind::Fn => {
-                self.check_node_helper(id.hir_id());
-            }
+            DefKind::Fn | DefKind::AssocFn => constraint_cx.build_constraints_for_item(def_id),
             _ => {}
         }
     }
 
-    fn check_node_helper(&mut self, id: hir::HirId) {
-        let tcx = self.terms_cx.tcx;
-        let def_id = tcx.hir().local_def_id(id);
-        self.build_constraints_for_item(def_id);
-    }
+    constraint_cx
+}
 
+impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.terms_cx.tcx
     }
@@ -145,8 +99,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
             return;
         }
 
-        let id = tcx.hir().local_def_id_to_hir_id(def_id);
-        let inferred_start = self.terms_cx.inferred_starts[&id];
+        let inferred_start = self.terms_cx.inferred_starts[&def_id];
         let current_item = &CurrentItem { inferred_start };
         match tcx.type_of(def_id).kind() {
             ty::Adt(def, _) => {
@@ -372,8 +325,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         }
 
         let (local, remote) = if let Some(def_id) = def_id.as_local() {
-            let id = self.tcx().hir().local_def_id_to_hir_id(def_id);
-            (Some(self.terms_cx.inferred_starts[&id]), None)
+            (Some(self.terms_cx.inferred_starts[&def_id]), None)
         } else {
             (None, Some(self.tcx().variances_of(def_id)))
         };
diff --git a/compiler/rustc_typeck/src/variance/solve.rs b/compiler/rustc_typeck/src/variance/solve.rs
index 1a4d88ced0e..97aca621aa2 100644
--- a/compiler/rustc_typeck/src/variance/solve.rs
+++ b/compiler/rustc_typeck/src/variance/solve.rs
@@ -96,8 +96,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> {
         self.terms_cx
             .inferred_starts
             .iter()
-            .map(|(&id, &InferredIndex(start))| {
-                let def_id = tcx.hir().local_def_id(id);
+            .map(|(&def_id, &InferredIndex(start))| {
                 let generics = tcx.generics_of(def_id);
                 let count = generics.count();
 
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs
index ab64befe5dc..1f763011e06 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_typeck/src/variance/terms.rs
@@ -10,9 +10,8 @@
 // a variable.
 
 use rustc_arena::DroplessArena;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
-use rustc_hir::HirIdMap;
+use rustc_hir::def_id::{LocalDefId, LocalDefIdMap};
 use rustc_middle::ty::{self, TyCtxt};
 use std::fmt;
 
@@ -52,11 +51,11 @@ pub struct TermsContext<'a, 'tcx> {
     // For marker types, UnsafeCell, and other lang items where
     // variance is hardcoded, records the item-id and the hardcoded
     // variance.
-    pub lang_items: Vec<(hir::HirId, Vec<ty::Variance>)>,
+    pub lang_items: Vec<(LocalDefId, Vec<ty::Variance>)>,
 
     // Maps from the node id of an item to the first inferred index
     // used for its type & region parameters.
-    pub inferred_starts: HirIdMap<InferredIndex>,
+    pub inferred_starts: LocalDefIdMap<InferredIndex>,
 
     // Maps from an InferredIndex to the term for that variable.
     pub inferred_terms: Vec<VarianceTermPtr<'a>>,
@@ -81,32 +80,31 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
     // - https://rustc-dev-guide.rust-lang.org/variance.html
     let crate_items = tcx.hir_crate_items(());
 
-    for id in crate_items.items() {
-        terms_cx.check_item(id);
-    }
+    for def_id in crate_items.definitions() {
+        debug!("add_inferreds for item {:?}", def_id);
 
-    for id in crate_items.trait_items() {
-        if let DefKind::AssocFn = tcx.def_kind(id.def_id) {
-            terms_cx.add_inferreds_for_item(id.hir_id());
-        }
-    }
+        let def_kind = tcx.def_kind(def_id);
 
-    for id in crate_items.impl_items() {
-        if let DefKind::AssocFn = tcx.def_kind(id.def_id) {
-            terms_cx.add_inferreds_for_item(id.hir_id());
-        }
-    }
+        match def_kind {
+            DefKind::Struct | DefKind::Union | DefKind::Enum => {
+                terms_cx.add_inferreds_for_item(def_id);
 
-    for id in crate_items.foreign_items() {
-        if let DefKind::Fn = tcx.def_kind(id.def_id) {
-            terms_cx.add_inferreds_for_item(id.hir_id());
+                let adt = tcx.adt_def(def_id);
+                for variant in adt.variants() {
+                    if let Some(ctor) = variant.ctor_def_id {
+                        terms_cx.add_inferreds_for_item(ctor.expect_local());
+                    }
+                }
+            }
+            DefKind::Fn | DefKind::AssocFn => terms_cx.add_inferreds_for_item(def_id),
+            _ => {}
         }
     }
 
     terms_cx
 }
 
-fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> {
+fn lang_items(tcx: TyCtxt<'_>) -> Vec<(LocalDefId, Vec<ty::Variance>)> {
     let lang_items = tcx.lang_items();
     let all = [
         (lang_items.phantom_data(), vec![ty::Covariant]),
@@ -114,18 +112,16 @@ fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> {
     ];
 
     all.into_iter() // iterating over (Option<DefId>, Variance)
-        .filter(|&(ref d, _)| d.is_some())
-        .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance)
         .filter_map(|(d, v)| {
-            d.as_local().map(|d| tcx.hir().local_def_id_to_hir_id(d)).map(|n| (n, v))
-        }) // (HirId, Variance)
+            let def_id = d?.as_local()?; // LocalDefId
+            Some((def_id, v))
+        })
         .collect()
 }
 
 impl<'a, 'tcx> TermsContext<'a, 'tcx> {
-    fn add_inferreds_for_item(&mut self, id: hir::HirId) {
+    fn add_inferreds_for_item(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
-        let def_id = tcx.hir().local_def_id(id);
         let count = tcx.generics_of(def_id).count();
 
         if count == 0 {
@@ -134,7 +130,7 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
 
         // Record the start of this item's inferreds.
         let start = self.inferred_terms.len();
-        let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none();
+        let newly_added = self.inferred_starts.insert(def_id, InferredIndex(start)).is_none();
         assert!(newly_added);
 
         // N.B., in the code below for writing the results back into the
@@ -146,42 +142,4 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
             (start..(start + count)).map(|i| &*arena.alloc(InferredTerm(InferredIndex(i)))),
         );
     }
-
-    fn check_item(&mut self, id: hir::ItemId) {
-        debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(id.hir_id()));
-
-        let def_kind = self.tcx.def_kind(id.def_id);
-        match def_kind {
-            DefKind::Struct | DefKind::Union => {
-                let item = self.tcx.hir().item(id);
-
-                if let hir::ItemKind::Struct(ref struct_def, _)
-                | hir::ItemKind::Union(ref struct_def, _) = item.kind
-                {
-                    self.add_inferreds_for_item(item.hir_id());
-
-                    if let hir::VariantData::Tuple(..) = *struct_def {
-                        self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap());
-                    }
-                }
-            }
-            DefKind::Enum => {
-                let item = self.tcx.hir().item(id);
-
-                if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
-                    self.add_inferreds_for_item(item.hir_id());
-
-                    for variant in enum_def.variants {
-                        if let hir::VariantData::Tuple(..) = variant.data {
-                            self.add_inferreds_for_item(variant.data.ctor_hir_id().unwrap());
-                        }
-                    }
-                }
-            }
-            DefKind::Fn => {
-                self.add_inferreds_for_item(id.hir_id());
-            }
-            _ => {}
-        }
-    }
 }
diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs
index 7a79fb77dea..904a53bb4ac 100644
--- a/library/alloc/src/borrow.rs
+++ b/library/alloc/src/borrow.rs
@@ -60,7 +60,7 @@ pub trait ToOwned {
 
     /// Uses borrowed data to replace owned data, usually by cloning.
     ///
-    /// This is borrow-generalized version of `Clone::clone_from`.
+    /// This is borrow-generalized version of [`Clone::clone_from`].
     ///
     /// # Examples
     ///
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index cc395759b20..d83bab7bbbd 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -206,7 +206,7 @@ impl<T> Box<T> {
     /// ```
     /// let five = Box::new(5);
     /// ```
-    #[cfg(all(not(no_global_oom_handling), not(bootstrap)))]
+    #[cfg(all(not(no_global_oom_handling)))]
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
@@ -215,23 +215,6 @@ impl<T> Box<T> {
         Box::new(x)
     }
 
-    /// Allocates memory on the heap and then places `x` into it.
-    ///
-    /// This doesn't actually allocate if `T` is zero-sized.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let five = Box::new(5);
-    /// ```
-    #[cfg(all(not(no_global_oom_handling), bootstrap))]
-    #[inline(always)]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    #[must_use]
-    pub fn new(x: T) -> Self {
-        box x
-    }
-
     /// Constructs a new box with uninitialized contents.
     ///
     /// # Examples
@@ -296,7 +279,7 @@ impl<T> Box<T> {
     #[must_use]
     #[inline(always)]
     pub fn pin(x: T) -> Pin<Box<T>> {
-        (#[cfg_attr(not(bootstrap), rustc_box)]
+        (#[rustc_box]
         Box::new(x))
         .into()
     }
@@ -1255,7 +1238,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
 impl<T: Default> Default for Box<T> {
     /// Creates a `Box<T>`, with the `Default` value for T.
     fn default() -> Self {
-        #[cfg_attr(not(bootstrap), rustc_box)]
+        #[rustc_box]
         Box::new(T::default())
     }
 }
@@ -1628,7 +1611,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
     /// println!("{boxed:?}");
     /// ```
     fn from(array: [T; N]) -> Box<[T]> {
-        #[cfg_attr(not(bootstrap), rustc_box)]
+        #[rustc_box]
         Box::new(array)
     }
 }
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index c08caa7b93e..d3816d70b63 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -149,7 +149,6 @@
 #![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(associated_type_bounds)]
-#![cfg_attr(bootstrap, feature(box_syntax))]
 #![feature(cfg_sanitize)]
 #![feature(const_deref)]
 #![feature(const_mut_refs)]
diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs
index 37898b6655f..88eb6aa7a83 100644
--- a/library/alloc/src/macros.rs
+++ b/library/alloc/src/macros.rs
@@ -34,7 +34,7 @@
 /// be mindful of side effects.
 ///
 /// [`Vec`]: crate::vec::Vec
-#[cfg(all(not(no_global_oom_handling), not(test), not(bootstrap)))]
+#[cfg(all(not(no_global_oom_handling), not(test)))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "vec_macro"]
@@ -54,24 +54,6 @@ macro_rules! vec {
     );
 }
 
-/// Creates a `Vec` containing the arguments (bootstrap version).
-#[cfg(all(not(no_global_oom_handling), not(test), bootstrap))]
-#[macro_export]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_diagnostic_item = "vec_macro"]
-#[allow_internal_unstable(box_syntax, liballoc_internals)]
-macro_rules! vec {
-    () => (
-        $crate::__rust_force_expr!($crate::vec::Vec::new())
-    );
-    ($elem:expr; $n:expr) => (
-        $crate::__rust_force_expr!($crate::vec::from_elem($elem, $n))
-    );
-    ($($x:expr),+ $(,)?) => (
-        $crate::__rust_force_expr!(<[_]>::into_vec(box [$($x),+]))
-    );
-}
-
 // HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is
 // required for this macro definition, is not available. Instead use the
 // `slice::into_vec`  function which is only available with cfg(test)
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index e25f98d8aa6..fa9f2131c0c 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1379,9 +1379,6 @@ impl<T, A: Allocator> Vec<T, A> {
         }
 
         let len = self.len();
-        if index > len {
-            assert_failed(index, len);
-        }
 
         // space for the new element
         if len == self.buf.capacity() {
@@ -1393,9 +1390,15 @@ impl<T, A: Allocator> Vec<T, A> {
             // The spot to put the new value
             {
                 let p = self.as_mut_ptr().add(index);
-                // Shift everything over to make space. (Duplicating the
-                // `index`th element into two consecutive places.)
-                ptr::copy(p, p.offset(1), len - index);
+                if index < len {
+                    // Shift everything over to make space. (Duplicating the
+                    // `index`th element into two consecutive places.)
+                    ptr::copy(p, p.offset(1), len - index);
+                } else if index == len {
+                    // No elements need shifting.
+                } else {
+                    assert_failed(index, len);
+                }
                 // Write it in, overwriting the first copy of the `index`th
                 // element.
                 ptr::write(p, element);
@@ -3017,7 +3020,7 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> {
     #[cfg(not(test))]
     fn from(s: [T; N]) -> Vec<T> {
         <[T]>::into_vec(
-            #[cfg_attr(not(bootstrap), rustc_box)]
+            #[rustc_box]
             Box::new(s),
         )
     }
diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs
index b6836fdc88e..99d1296a4c9 100644
--- a/library/alloc/tests/string.rs
+++ b/library/alloc/tests/string.rs
@@ -693,12 +693,6 @@ fn test_try_reserve() {
     const MAX_CAP: usize = isize::MAX as usize;
     const MAX_USIZE: usize = usize::MAX;
 
-    // On 16/32-bit, we check that allocations don't exceed isize::MAX,
-    // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
-    // Any platform that succeeds for these requests is technically broken with
-    // ptr::offset because LLVM is the worst.
-    let guards_against_isize = usize::BITS < 64;
-
     {
         // Note: basic stuff is checked by test_reserve
         let mut empty_string: String = String::new();
@@ -712,35 +706,19 @@ fn test_try_reserve() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            // Check isize::MAX + 1 does count as overflow
-            assert_matches!(
-                empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            // Check usize::MAX does count as overflow
-            assert_matches!(
-                empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            // Check isize::MAX + 1 is an OOM
-            assert_matches!(
-                empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-
-            // Check usize::MAX is an OOM
-            assert_matches!(
-                empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "usize::MAX should trigger an OOM!"
-            );
-        }
+        // Check isize::MAX + 1 does count as overflow
+        assert_matches!(
+            empty_string.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        // Check usize::MAX does count as overflow
+        assert_matches!(
+            empty_string.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -753,19 +731,13 @@ fn test_try_reserve() {
         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         // Should always overflow in the add-to-len
         assert_matches!(
             ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -785,8 +757,6 @@ fn test_try_reserve_exact() {
     const MAX_CAP: usize = isize::MAX as usize;
     const MAX_USIZE: usize = usize::MAX;
 
-    let guards_against_isize = usize::BITS < 64;
-
     {
         let mut empty_string: String = String::new();
 
@@ -799,31 +769,17 @@ fn test_try_reserve_exact() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            assert_matches!(
-                empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            assert_matches!(
-                empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-
-            assert_matches!(
-                empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "usize::MAX should trigger an OOM!"
-            );
-        }
+        assert_matches!(
+            empty_string.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        assert_matches!(
+            empty_string.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -839,19 +795,13 @@ fn test_try_reserve_exact() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         assert_matches!(
             ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
             Err(CapacityOverflow),
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 5520f6ebf19..699567be5a0 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1517,12 +1517,6 @@ fn test_try_reserve() {
     const MAX_CAP: usize = isize::MAX as usize;
     const MAX_USIZE: usize = usize::MAX;
 
-    // On 16/32-bit, we check that allocations don't exceed isize::MAX,
-    // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
-    // Any platform that succeeds for these requests is technically broken with
-    // ptr::offset because LLVM is the worst.
-    let guards_against_isize = usize::BITS < 64;
-
     {
         // Note: basic stuff is checked by test_reserve
         let mut empty_bytes: Vec<u8> = Vec::new();
@@ -1536,35 +1530,19 @@ fn test_try_reserve() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            // Check isize::MAX + 1 does count as overflow
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            // Check usize::MAX does count as overflow
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            // Check isize::MAX + 1 is an OOM
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-
-            // Check usize::MAX is an OOM
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "usize::MAX should trigger an OOM!"
-            );
-        }
+        // Check isize::MAX + 1 does count as overflow
+        assert_matches!(
+            empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        // Check usize::MAX does count as overflow
+        assert_matches!(
+            empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -1577,19 +1555,13 @@ fn test_try_reserve() {
         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         // Should always overflow in the add-to-len
         assert_matches!(
             ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -1610,19 +1582,13 @@ fn test_try_reserve() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         // Should fail in the mul-by-size
         assert_matches!(
             ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
@@ -1642,8 +1608,6 @@ fn test_try_reserve_exact() {
     const MAX_CAP: usize = isize::MAX as usize;
     const MAX_USIZE: usize = usize::MAX;
 
-    let guards_against_isize = size_of::<usize>() < 8;
-
     {
         let mut empty_bytes: Vec<u8> = Vec::new();
 
@@ -1656,31 +1620,17 @@ fn test_try_reserve_exact() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "usize::MAX should trigger an OOM!"
-            );
-        }
+        assert_matches!(
+            empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        assert_matches!(
+            empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -1696,19 +1646,13 @@ fn test_try_reserve_exact() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         assert_matches!(
             ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
             Err(CapacityOverflow),
@@ -1729,19 +1673,13 @@ fn test_try_reserve_exact() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         assert_matches!(
             ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
             Err(CapacityOverflow),
diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs
index 89cc7f905be..019d73c0b16 100644
--- a/library/alloc/tests/vec_deque.rs
+++ b/library/alloc/tests/vec_deque.rs
@@ -2,7 +2,6 @@ use std::assert_matches::assert_matches;
 use std::collections::TryReserveErrorKind::*;
 use std::collections::{vec_deque::Drain, VecDeque};
 use std::fmt::Debug;
-use std::mem::size_of;
 use std::ops::Bound::*;
 use std::panic::{catch_unwind, AssertUnwindSafe};
 
@@ -1161,12 +1160,6 @@ fn test_try_reserve() {
     const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
     const MAX_USIZE: usize = usize::MAX;
 
-    // On 16/32-bit, we check that allocations don't exceed isize::MAX,
-    // on 64-bit, we assume the OS will give an OOM for such a ridiculous size.
-    // Any platform that succeeds for these requests is technically broken with
-    // ptr::offset because LLVM is the worst.
-    let guards_against_isize = size_of::<usize>() < 8;
-
     {
         // Note: basic stuff is checked by test_reserve
         let mut empty_bytes: VecDeque<u8> = VecDeque::new();
@@ -1180,31 +1173,19 @@ fn test_try_reserve() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            // Check isize::MAX + 1 does count as overflow
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            // Check usize::MAX does count as overflow
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            // Check isize::MAX is an OOM
-            // VecDeque starts with capacity 7, always adds 1 to the capacity
-            // and also rounds the number to next power of 2 so this is the
-            // furthest we can go without triggering CapacityOverflow
-            assert_matches!(
-                empty_bytes.try_reserve(MAX_CAP).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+        // Check isize::MAX + 1 does count as overflow
+        assert_matches!(
+            empty_bytes.try_reserve(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        // Check usize::MAX does count as overflow
+        assert_matches!(
+            empty_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -1217,19 +1198,13 @@ fn test_try_reserve() {
         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         // Should always overflow in the add-to-len
         assert_matches!(
             ten_bytes.try_reserve(MAX_USIZE).map_err(|e| e.kind()),
@@ -1250,19 +1225,13 @@ fn test_try_reserve() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_u32s.try_reserve(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         // Should fail in the mul-by-size
         assert_matches!(
             ten_u32s.try_reserve(MAX_USIZE - 20).map_err(|e| e.kind()),
@@ -1282,8 +1251,6 @@ fn test_try_reserve_exact() {
     const MAX_CAP: usize = (isize::MAX as usize + 1) / 2 - 1;
     const MAX_USIZE: usize = usize::MAX;
 
-    let guards_against_isize = size_of::<usize>() < 8;
-
     {
         let mut empty_bytes: VecDeque<u8> = VecDeque::new();
 
@@ -1296,29 +1263,17 @@ fn test_try_reserve_exact() {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
 
-        if guards_against_isize {
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "usize::MAX should trigger an overflow!"
-            );
-        } else {
-            // Check isize::MAX is an OOM
-            // VecDeque starts with capacity 7, always adds 1 to the capacity
-            // and also rounds the number to next power of 2 so this is the
-            // furthest we can go without triggering CapacityOverflow
-            assert_matches!(
-                empty_bytes.try_reserve_exact(MAX_CAP).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+        assert_matches!(
+            empty_bytes.try_reserve_exact(MAX_CAP + 1).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
+        assert_matches!(
+            empty_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "usize::MAX should trigger an overflow!"
+        );
     }
 
     {
@@ -1334,19 +1289,13 @@ fn test_try_reserve_exact() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_bytes.try_reserve_exact(MAX_CAP - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         assert_matches!(
             ten_bytes.try_reserve_exact(MAX_USIZE).map_err(|e| e.kind()),
             Err(CapacityOverflow),
@@ -1367,19 +1316,13 @@ fn test_try_reserve_exact() {
         {
             panic!("isize::MAX shouldn't trigger an overflow!");
         }
-        if guards_against_isize {
-            assert_matches!(
-                ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(CapacityOverflow),
-                "isize::MAX + 1 should trigger an overflow!"
-            );
-        } else {
-            assert_matches!(
-                ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
-                Err(AllocError { .. }),
-                "isize::MAX + 1 should trigger an OOM!"
-            );
-        }
+
+        assert_matches!(
+            ten_u32s.try_reserve_exact(MAX_CAP / 4 - 9).map_err(|e| e.kind()),
+            Err(CapacityOverflow),
+            "isize::MAX + 1 should trigger an overflow!"
+        );
+
         assert_matches!(
             ten_u32s.try_reserve_exact(MAX_USIZE - 20).map_err(|e| e.kind()),
             Err(CapacityOverflow),
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 2f378836cbb..39bccdb854c 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -52,8 +52,8 @@ impl Layout {
     /// * `align` must be a power of two,
     ///
     /// * `size`, when rounded up to the nearest multiple of `align`,
-    ///    must not overflow (i.e., the rounded value must be less than
-    ///    or equal to `usize::MAX`).
+    ///    must not overflow isize (i.e., the rounded value must be
+    ///    less than or equal to `isize::MAX`).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
     #[inline]
@@ -76,7 +76,7 @@ impl Layout {
         //
         // Above implies that checking for summation overflow is both
         // necessary and sufficient.
-        if size > usize::MAX - (align - 1) {
+        if size > isize::MAX as usize - (align - 1) {
             return Err(LayoutError);
         }
 
@@ -276,8 +276,8 @@ impl Layout {
         let pad = self.padding_needed_for(self.align());
         // This cannot overflow. Quoting from the invariant of Layout:
         // > `size`, when rounded up to the nearest multiple of `align`,
-        // > must not overflow (i.e., the rounded value must be less than
-        // > `usize::MAX`)
+        // > must not overflow isize (i.e., the rounded value must be
+        // > less than or equal to `isize::MAX`)
         let new_size = self.size() + pad;
 
         // SAFETY: self.align is already known to be valid and new_size has been
@@ -298,14 +298,13 @@ impl Layout {
     pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
         // This cannot overflow. Quoting from the invariant of Layout:
         // > `size`, when rounded up to the nearest multiple of `align`,
-        // > must not overflow (i.e., the rounded value must be less than
-        // > `usize::MAX`)
+        // > must not overflow isize (i.e., the rounded value must be
+        // > less than or equal to `isize::MAX`)
         let padded_size = self.size() + self.padding_needed_for(self.align());
         let alloc_size = padded_size.checked_mul(n).ok_or(LayoutError)?;
 
-        // SAFETY: self.align is already known to be valid and alloc_size has been
-        // padded already.
-        unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) }
+        // The safe constructor is called here to enforce the isize size limit.
+        Layout::from_size_align(alloc_size, self.align()).map(|layout| (layout, padded_size))
     }
 
     /// Creates a layout describing the record for `self` followed by
@@ -362,6 +361,7 @@ impl Layout {
         let offset = self.size().checked_add(pad).ok_or(LayoutError)?;
         let new_size = offset.checked_add(next.size()).ok_or(LayoutError)?;
 
+        // The safe constructor is called here to enforce the isize size limit.
         let layout = Layout::from_size_align(new_size, new_align)?;
         Ok((layout, offset))
     }
@@ -382,6 +382,7 @@ impl Layout {
     #[inline]
     pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
         let size = self.size().checked_mul(n).ok_or(LayoutError)?;
+        // The safe constructor is called here to enforce the isize size limit.
         Layout::from_size_align(size, self.align())
     }
 
@@ -395,6 +396,7 @@ impl Layout {
     #[inline]
     pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
         let new_size = self.size().checked_add(next.size()).ok_or(LayoutError)?;
+        // The safe constructor is called here to enforce the isize size limit.
         Layout::from_size_align(new_size, self.align())
     }
 
@@ -405,16 +407,8 @@ impl Layout {
     #[inline]
     pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
         let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
-
-        // SAFETY:
-        // - Size: `array_size` cannot be too big because `size_of::<T>()` must
-        //   be a multiple of `align_of::<T>()`. Therefore, `array_size`
-        //   rounded up to the nearest multiple of `align_of::<T>()` is just
-        //   `array_size`. And `array_size` cannot be too big because it was
-        //   just checked by the `checked_mul()`.
-        // - Alignment: `align_of::<T>()` will always give an acceptable
-        //   (non-zero, power of two) alignment.
-        Ok(unsafe { Layout::from_size_align_unchecked(array_size, mem::align_of::<T>()) })
+        // The safe constructor is called here to enforce the isize size limit.
+        Layout::from_size_align(array_size, mem::align_of::<T>())
     }
 }
 
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 778f06aeb63..7c5f82f5ea4 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -93,7 +93,7 @@ impl const From<char> for u128 {
 /// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing
 /// if the code point is greater than U+00FF.
 ///
-/// See [`impl From<u8> for char`](char#impl-From<u8>) for details on the encoding.
+/// See [`impl From<u8> for char`](char#impl-From<u8>-for-char) for details on the encoding.
 #[stable(feature = "u8_from_char", since = "1.59.0")]
 impl TryFrom<char> for u8 {
     type Error = TryFromCharError;
@@ -229,7 +229,7 @@ impl TryFrom<u32> for char {
 
 /// The error type returned when a conversion from [`prim@u32`] to [`prim@char`] fails.
 ///
-/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>) method.
+/// This `struct` is created by the [`char::try_from<u32>`](char#impl-TryFrom<u32>-for-char) method.
 /// See its documentation for more.
 #[stable(feature = "try_from", since = "1.34.0")]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index fd5624812f5..06dca7e59a2 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -106,7 +106,7 @@ use crate::marker::Destruct;
 #[lang = "clone"]
 #[rustc_diagnostic_item = "Clone"]
 #[rustc_trivial_field_reads]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait Clone: Sized {
     /// Returns a copy of the value.
     ///
@@ -129,7 +129,6 @@ pub trait Clone: Sized {
     /// allocations.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn clone_from(&mut self, source: &Self)
     where
         Self: ~const Destruct,
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 064675ee7cf..1d3466696ed 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -214,7 +214,7 @@ use self::Ordering::*;
         append_const_msg,
     )
 )]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 #[rustc_diagnostic_item = "PartialEq"]
 pub trait PartialEq<Rhs: ?Sized = Self> {
     /// This method tests for `self` and `other` values to be equal, and is used
@@ -227,7 +227,6 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn ne(&self, other: &Rhs) -> bool {
         !self.eq(other)
     }
@@ -1054,7 +1053,7 @@ impl PartialOrd for Ordering {
         append_const_msg,
     )
 )]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 #[rustc_diagnostic_item = "PartialOrd"]
 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     /// This method returns an ordering between `self` and `other` values if one exists.
@@ -1098,7 +1097,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn lt(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Less))
     }
@@ -1118,7 +1116,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn le(&self, other: &Rhs) -> bool {
         // Pattern `Some(Less | Eq)` optimizes worse than negating `None | Some(Greater)`.
         // FIXME: The root cause was fixed upstream in LLVM with:
@@ -1141,7 +1138,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn gt(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Greater))
     }
@@ -1161,7 +1157,6 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(bootstrap, default_method_body_is_const)]
     fn ge(&self, other: &Rhs) -> bool {
         matches!(self.partial_cmp(other), Some(Greater | Equal))
     }
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 1d4be42b4a2..6c3bb7229e5 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -2562,7 +2562,7 @@ macro_rules! tuple {
 
 macro_rules! maybe_tuple_doc {
     ($a:ident @ #[$meta:meta] $item:item) => {
-        #[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+        #[doc(tuple_variadic)]
         #[doc = "This trait is implemented for tuples up to twelve items long."]
         #[$meta]
         $item
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index ad9e80e117f..649b4338772 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -13,8 +13,6 @@ use crate::future::Future;
 /// on all futures.
 ///
 /// ```no_run
-/// #![feature(into_future)]
-///
 /// use std::future::IntoFuture;
 ///
 /// # async fn foo() {
@@ -33,8 +31,6 @@ use crate::future::Future;
 /// multiple times before being `.await`ed.
 ///
 /// ```rust
-/// #![feature(into_future)]
-///
 /// use std::future::{ready, Ready, IntoFuture};
 ///
 /// /// Eventually multiply two numbers
@@ -91,8 +87,6 @@ use crate::future::Future;
 /// `IntoFuture::into_future` to obtain an instance of `Future`:
 ///
 /// ```rust
-/// #![feature(into_future)]
-///
 /// use std::future::IntoFuture;
 ///
 /// /// Convert the output of a future to a string.
@@ -104,14 +98,14 @@ use crate::future::Future;
 ///     format!("{:?}", fut.await)
 /// }
 /// ```
-#[unstable(feature = "into_future", issue = "67644")]
+#[stable(feature = "into_future", since = "1.64.0")]
 pub trait IntoFuture {
     /// The output that the future will produce on completion.
-    #[unstable(feature = "into_future", issue = "67644")]
+    #[stable(feature = "into_future", since = "1.64.0")]
     type Output;
 
     /// Which kind of future are we turning this into?
-    #[unstable(feature = "into_future", issue = "67644")]
+    #[stable(feature = "into_future", since = "1.64.0")]
     type IntoFuture: Future<Output = Self::Output>;
 
     /// Creates a future from a value.
@@ -121,8 +115,6 @@ pub trait IntoFuture {
     /// Basic usage:
     ///
     /// ```no_run
-    /// #![feature(into_future)]
-    ///
     /// use std::future::IntoFuture;
     ///
     /// # async fn foo() {
@@ -131,12 +123,12 @@ pub trait IntoFuture {
     /// assert_eq!("meow", fut.await);
     /// # }
     /// ```
-    #[unstable(feature = "into_future", issue = "67644")]
+    #[stable(feature = "into_future", since = "1.64.0")]
     #[lang = "into_future"]
     fn into_future(self) -> Self::IntoFuture;
 }
 
-#[unstable(feature = "into_future", issue = "67644")]
+#[stable(feature = "into_future", since = "1.64.0")]
 impl<F: Future> IntoFuture for F {
     type Output = F::Output;
     type IntoFuture = F;
diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs
index 9b89f766c67..90eecb9d4a0 100644
--- a/library/core/src/future/mod.rs
+++ b/library/core/src/future/mod.rs
@@ -29,7 +29,7 @@ pub use self::future::Future;
 #[unstable(feature = "future_join", issue = "91642")]
 pub use self::join::join;
 
-#[unstable(feature = "into_future", issue = "67644")]
+#[stable(feature = "into_future", since = "1.64.0")]
 pub use into_future::IntoFuture;
 
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index 2c152fe1b2c..cf428e0b1cf 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -180,7 +180,7 @@ mod sip;
 /// [`HashMap`]: ../../std/collections/struct.HashMap.html
 /// [`HashSet`]: ../../std/collections/struct.HashSet.html
 /// [`hash`]: Hash::hash
-/// [impl]: ../../std/primitive.str.html#impl-Hash
+/// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Hash"]
 pub trait Hash {
@@ -900,7 +900,7 @@ mod impls {
 
     macro_rules! maybe_tuple_doc {
         ($a:ident @ #[$meta:meta] $item:item) => {
-            #[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+            #[doc(tuple_variadic)]
             #[doc = "This trait is implemented for tuples up to twelve items long."]
             #[$meta]
             $item
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index d230c06a211..2895c923adc 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2356,6 +2356,9 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
 /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but
 /// with the argument order swapped.
 ///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
 /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy
 ///
 /// # Safety
@@ -2461,6 +2464,9 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
 /// order swapped. Copying takes place as if the bytes were copied from `src`
 /// to a temporary array and then copied from the array to `dst`.
 ///
+/// The copy is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
 /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove
 ///
 /// # Safety
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 093c7d29873..bd256cec8a1 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -134,7 +134,7 @@
 #![feature(const_ptr_write)]
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
-#![feature(const_slice_from_raw_parts)]
+#![feature(const_slice_from_raw_parts_mut)]
 #![feature(const_slice_ptr_len)]
 #![feature(const_str_from_utf8_unchecked_mut)]
 #![feature(const_swap)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 28ea45ed235..bca73cb770f 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -389,7 +389,7 @@
 //! [`Option`] of a collection of each contained value of the original
 //! [`Option`] values, or [`None`] if any of the elements was [`None`].
 //!
-//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E
+//! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E-for-Option%3CV%3E
 //!
 //! ```
 //! let v = [Some(2), Some(4), None, Some(8)];
@@ -405,8 +405,8 @@
 //! to provide the [`product`][Iterator::product] and
 //! [`sum`][Iterator::sum] methods.
 //!
-//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E
-//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E
+//! [impl-Product]: Option#impl-Product%3COption%3CU%3E%3E-for-Option%3CT%3E
+//! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E-for-Option%3CT%3E
 //!
 //! ```
 //! let v = [None, Some(1), Some(2), Some(3)];
diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
index f2948aac3c2..9a6153f1253 100644
--- a/library/core/src/panic/unwind_safe.rs
+++ b/library/core/src/panic/unwind_safe.rs
@@ -217,7 +217,7 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {}
 #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
 impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
 #[cfg(target_has_atomic_load_store = "128")]
-#[unstable(feature = "integer_atomics", issue = "32976")]
+#[unstable(feature = "integer_atomics", issue = "99069")]
 impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
 
 #[cfg(target_has_atomic_load_store = "ptr")]
@@ -236,7 +236,7 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
 #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
 impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
 #[cfg(target_has_atomic_load_store = "128")]
-#[unstable(feature = "integer_atomics", issue = "32976")]
+#[unstable(feature = "integer_atomics", issue = "99069")]
 impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
 
 #[cfg(target_has_atomic_load_store = "8")]
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 00793f7f920..401c8159988 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -996,7 +996,7 @@ impl<T> (T,) {}
 // Fake impl that's only really used for docs.
 #[cfg(doc)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+#[doc(tuple_variadic)]
 /// This trait is implemented on arbitrary-length tuples.
 impl<T: Clone> Clone for (T,) {
     fn clone(&self) -> Self {
@@ -1007,7 +1007,7 @@ impl<T: Clone> Clone for (T,) {
 // Fake impl that's only really used for docs.
 #[cfg(doc)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+#[doc(tuple_variadic)]
 /// This trait is implemented on arbitrary-length tuples.
 impl<T: Copy> Copy for (T,) {
     // empty
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 8fb0bfbe2e3..2fcff3dfc5c 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -507,55 +507,12 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_diagnostic_item = "ptr_null"]
-#[cfg(bootstrap)]
-pub const fn null<T>() -> *const T {
-    invalid(0)
-}
-
-/// Creates a null raw pointer.
-///
-/// # Examples
-///
-/// ```
-/// use std::ptr;
-///
-/// let p: *const i32 = ptr::null();
-/// assert!(p.is_null());
-/// ```
-#[inline(always)]
-#[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_promotable]
-#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null"]
-#[cfg(not(bootstrap))]
 pub const fn null<T: ?Sized + Thin>() -> *const T {
     from_raw_parts(invalid(0), ())
 }
 
-/// Creates a null mutable raw pointer.
-///
-/// # Examples
-///
-/// ```
-/// use std::ptr;
-///
-/// let p: *mut i32 = ptr::null_mut();
-/// assert!(p.is_null());
-/// ```
-#[inline(always)]
-#[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_promotable]
-#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
-#[rustc_diagnostic_item = "ptr_null_mut"]
-#[cfg(bootstrap)]
-pub const fn null_mut<T>() -> *mut T {
-    invalid_mut(0)
-}
-
 /// Creates an invalid pointer with the given address.
 ///
 /// This is different from `addr as *const T`, which creates a pointer that picks up a previously
@@ -707,7 +664,6 @@ where
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_null_mut"]
-#[cfg(not(bootstrap))]
 pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
     from_raw_parts_mut(invalid_mut(0), ())
 }
@@ -734,7 +690,8 @@ pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
 /// ```
 #[inline]
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")]
+#[rustc_allow_const_fn_unstable(ptr_metadata)]
 pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
     from_raw_parts(data.cast(), len)
 }
@@ -766,7 +723,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
 /// ```
 #[inline]
 #[stable(feature = "slice_from_raw_parts", since = "1.42.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
 pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
     from_raw_parts_mut(data.cast(), len)
 }
@@ -774,7 +731,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// Swaps the values at two mutable locations of the same type, without
 /// deinitializing either.
 ///
-/// But for the following two exceptions, this function is semantically
+/// But for the following exceptions, this function is semantically
 /// equivalent to [`mem::swap`]:
 ///
 /// * It operates on raw pointers instead of references. When references are
@@ -784,6 +741,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 ///   overlapping region of memory from `x` will be used. This is demonstrated
 ///   in the second example below.
 ///
+/// * The operation is "untyped" in the sense that data may be uninitialized or otherwise violate
+///   the requirements of `T`. The initialization state is preserved exactly.
+///
 /// # Safety
 ///
 /// Behavior is undefined if any of the following conditions are violated:
@@ -860,6 +820,9 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
 /// Swaps `count * size_of::<T>()` bytes between the two regions of memory
 /// beginning at `x` and `y`. The two regions must *not* overlap.
 ///
+/// The operation is "untyped" in the sense that data may be uninitialized or otherwise violate the
+/// requirements of `T`. The initialization state is preserved exactly.
+///
 /// # Safety
 ///
 /// Behavior is undefined if any of the following conditions are violated:
@@ -905,15 +868,15 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             if mem::align_of::<T>() >= mem::align_of::<$ChunkTy>()
                 && mem::size_of::<T>() % mem::size_of::<$ChunkTy>() == 0
             {
-                let x: *mut MaybeUninit<$ChunkTy> = x.cast();
-                let y: *mut MaybeUninit<$ChunkTy> = y.cast();
+                let x: *mut $ChunkTy = x.cast();
+                let y: *mut $ChunkTy = y.cast();
                 let count = count * (mem::size_of::<T>() / mem::size_of::<$ChunkTy>());
                 // SAFETY: these are the same bytes that the caller promised were
                 // ok, just typed as `MaybeUninit<ChunkTy>`s instead of as `T`s.
                 // The `if` condition above ensures that we're not violating
                 // alignment requirements, and that the division is exact so
                 // that we don't lose any bytes off the end.
-                return unsafe { swap_nonoverlapping_simple(x, y, count) };
+                return unsafe { swap_nonoverlapping_simple_untyped(x, y, count) };
             }
         };
     }
@@ -946,7 +909,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
     }
 
     // SAFETY: Same preconditions as this function
-    unsafe { swap_nonoverlapping_simple(x, y, count) }
+    unsafe { swap_nonoverlapping_simple_untyped(x, y, count) }
 }
 
 /// Same behaviour and safety conditions as [`swap_nonoverlapping`]
@@ -955,17 +918,17 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
 /// `swap_nonoverlapping` tries to use) so no need to manually SIMD it.
 #[inline]
 #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
-const unsafe fn swap_nonoverlapping_simple<T>(x: *mut T, y: *mut T, count: usize) {
+const unsafe fn swap_nonoverlapping_simple_untyped<T>(x: *mut T, y: *mut T, count: usize) {
+    let x = x.cast::<MaybeUninit<T>>();
+    let y = y.cast::<MaybeUninit<T>>();
     let mut i = 0;
     while i < count {
-        let x: &mut T =
-            // SAFETY: By precondition, `i` is in-bounds because it's below `n`
-            unsafe { &mut *x.add(i) };
-        let y: &mut T =
-            // SAFETY: By precondition, `i` is in-bounds because it's below `n`
-            // and it's distinct from `x` since the ranges are non-overlapping
-            unsafe { &mut *y.add(i) };
-        mem::swap_simple(x, y);
+        // SAFETY: By precondition, `i` is in-bounds because it's below `n`
+        let x = unsafe { &mut *x.add(i) };
+        // SAFETY: By precondition, `i` is in-bounds because it's below `n`
+        // and it's distinct from `x` since the ranges are non-overlapping
+        let y = unsafe { &mut *y.add(i) };
+        mem::swap_simple::<MaybeUninit<T>>(x, y);
 
         i += 1;
     }
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index c4dc34fff97..8a68cdf7d65 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -459,7 +459,7 @@
 //! [`Result`] of a collection of each contained value of the original
 //! [`Result`] values, or [`Err`] if any of the elements was [`Err`].
 //!
-//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E
+//! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E-for-Result%3CV%2C%20E%3E
 //!
 //! ```
 //! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)];
@@ -475,8 +475,8 @@
 //! to provide the [`product`][Iterator::product] and
 //! [`sum`][Iterator::sum] methods.
 //!
-//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E
-//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E
+//! [impl-Product]: Result#impl-Product%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E
+//! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E-for-Result%3CT%2C%20E%3E
 //!
 //! ```
 //! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs
index bf79214f423..107e71ab68b 100644
--- a/library/core/src/slice/raw.rs
+++ b/library/core/src/slice/raw.rs
@@ -85,7 +85,7 @@ use crate::ptr;
 /// [`NonNull::dangling()`]: ptr::NonNull::dangling
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")]
 #[must_use]
 pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
@@ -129,7 +129,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T]
 /// [`NonNull::dangling()`]: ptr::NonNull::dangling
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
 #[must_use]
 pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
     // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 90e2dfd5d3d..ebc769ac7ca 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -991,7 +991,7 @@ impl<T> AtomicPtr<T> {
     /// use std::sync::atomic::AtomicPtr;
     ///
     /// let ptr = &mut 5;
-    /// let atomic_ptr  = AtomicPtr::new(ptr);
+    /// let atomic_ptr = AtomicPtr::new(ptr);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1451,6 +1451,347 @@ impl<T> AtomicPtr<T> {
         }
         Err(prev)
     }
+
+    /// Offsets the pointer's address by adding `val` (in units of `T`),
+    /// returning the previous pointer.
+    ///
+    /// This is equivalent to using [`wrapping_add`] to atomically perform the
+    /// equivalent of `ptr = ptr.wrapping_add(val);`.
+    ///
+    /// This method operates in units of `T`, which means that it cannot be used
+    /// to offset the pointer by an amount which is not a multiple of
+    /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to
+    /// work with a deliberately misaligned pointer. In such cases, you may use
+    /// the [`fetch_byte_add`](Self::fetch_byte_add) method instead.
+    ///
+    /// `fetch_ptr_add` takes an [`Ordering`] argument which describes the
+    /// memory ordering of this operation. All ordering modes are possible. Note
+    /// that using [`Acquire`] makes the store part of this operation
+    /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// [`wrapping_add`]: pointer::wrapping_add
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+    /// assert_eq!(atom.fetch_ptr_add(1, Ordering::Relaxed).addr(), 0);
+    /// // Note: units of `size_of::<i64>()`.
+    /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 8);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T {
+        self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order)
+    }
+
+    /// Offsets the pointer's address by subtracting `val` (in units of `T`),
+    /// returning the previous pointer.
+    ///
+    /// This is equivalent to using [`wrapping_sub`] to atomically perform the
+    /// equivalent of `ptr = ptr.wrapping_sub(val);`.
+    ///
+    /// This method operates in units of `T`, which means that it cannot be used
+    /// to offset the pointer by an amount which is not a multiple of
+    /// `size_of::<T>()`. This can sometimes be inconvenient, as you may want to
+    /// work with a deliberately misaligned pointer. In such cases, you may use
+    /// the [`fetch_byte_sub`](Self::fetch_byte_sub) method instead.
+    ///
+    /// `fetch_ptr_sub` takes an [`Ordering`] argument which describes the memory
+    /// ordering of this operation. All ordering modes are possible. Note that
+    /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
+    /// and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// [`wrapping_sub`]: pointer::wrapping_sub
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let array = [1i32, 2i32];
+    /// let atom = AtomicPtr::new(array.as_ptr().wrapping_add(1) as *mut _);
+    ///
+    /// assert!(core::ptr::eq(
+    ///     atom.fetch_ptr_sub(1, Ordering::Relaxed),
+    ///     &array[1],
+    /// ));
+    /// assert!(core::ptr::eq(atom.load(Ordering::Relaxed), &array[0]));
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T {
+        self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order)
+    }
+
+    /// Offsets the pointer's address by adding `val` *bytes*, returning the
+    /// previous pointer.
+    ///
+    /// This is equivalent to using [`wrapping_add`] and [`cast`] to atomically
+    /// perform `ptr = ptr.cast::<u8>().wrapping_add(val).cast::<T>()`.
+    ///
+    /// `fetch_byte_add` takes an [`Ordering`] argument which describes the
+    /// memory ordering of this operation. All ordering modes are possible. Note
+    /// that using [`Acquire`] makes the store part of this operation
+    /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// [`wrapping_add`]: pointer::wrapping_add
+    /// [`cast`]: pointer::cast
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+    /// assert_eq!(atom.fetch_byte_add(1, Ordering::Relaxed).addr(), 0);
+    /// // Note: in units of bytes, not `size_of::<i64>()`.
+    /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 1);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_byte_add(&self, val: usize, order: Ordering) -> *mut T {
+        #[cfg(not(bootstrap))]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_add(self.p.get(), core::ptr::invalid_mut(val), order).cast()
+        }
+        #[cfg(bootstrap)]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_add(self.p.get().cast::<usize>(), val, order) as *mut T
+        }
+    }
+
+    /// Offsets the pointer's address by subtracting `val` *bytes*, returning the
+    /// previous pointer.
+    ///
+    /// This is equivalent to using [`wrapping_sub`] and [`cast`] to atomically
+    /// perform `ptr = ptr.cast::<u8>().wrapping_sub(val).cast::<T>()`.
+    ///
+    /// `fetch_byte_sub` takes an [`Ordering`] argument which describes the
+    /// memory ordering of this operation. All ordering modes are possible. Note
+    /// that using [`Acquire`] makes the store part of this operation
+    /// [`Relaxed`], and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// [`wrapping_sub`]: pointer::wrapping_sub
+    /// [`cast`]: pointer::cast
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let atom = AtomicPtr::<i64>::new(core::ptr::invalid_mut(1));
+    /// assert_eq!(atom.fetch_byte_sub(1, Ordering::Relaxed).addr(), 1);
+    /// assert_eq!(atom.load(Ordering::Relaxed).addr(), 0);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_byte_sub(&self, val: usize, order: Ordering) -> *mut T {
+        #[cfg(not(bootstrap))]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_sub(self.p.get(), core::ptr::invalid_mut(val), order).cast()
+        }
+        #[cfg(bootstrap)]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_sub(self.p.get().cast::<usize>(), val, order) as *mut T
+        }
+    }
+
+    /// Performs a bitwise "or" operation on the address of the current pointer,
+    /// and the argument `val`, and stores a pointer with provenance of the
+    /// current pointer and the resulting address.
+    ///
+    /// This is equivalent equivalent to using [`map_addr`] to atomically
+    /// perform `ptr = ptr.map_addr(|a| a | val)`. This can be used in tagged
+    /// pointer schemes to atomically set tag bits.
+    ///
+    /// **Caveat**: This operation returns the previous value. To compute the
+    /// stored value without losing provenance, you may use [`map_addr`]. For
+    /// example: `a.fetch_or(val).map_addr(|a| a | val)`.
+    ///
+    /// `fetch_or` takes an [`Ordering`] argument which describes the memory
+    /// ordering of this operation. All ordering modes are possible. Note that
+    /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
+    /// and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance
+    /// experiment, see the [module documentation for `ptr`][crate::ptr] for
+    /// details.
+    ///
+    /// [`map_addr`]: pointer::map_addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let pointer = &mut 3i64 as *mut i64;
+    ///
+    /// let atom = AtomicPtr::<i64>::new(pointer);
+    /// // Tag the bottom bit of the pointer.
+    /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 0);
+    /// // Extract and untag.
+    /// let tagged = atom.load(Ordering::Relaxed);
+    /// assert_eq!(tagged.addr() & 1, 1);
+    /// assert_eq!(tagged.map_addr(|p| p & !1), pointer);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_or(&self, val: usize, order: Ordering) -> *mut T {
+        #[cfg(not(bootstrap))]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_or(self.p.get(), core::ptr::invalid_mut(val), order).cast()
+        }
+        #[cfg(bootstrap)]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_or(self.p.get().cast::<usize>(), val, order) as *mut T
+        }
+    }
+
+    /// Performs a bitwise "and" operation on the address of the current
+    /// pointer, and the argument `val`, and stores a pointer with provenance of
+    /// the current pointer and the resulting address.
+    ///
+    /// This is equivalent equivalent to using [`map_addr`] to atomically
+    /// perform `ptr = ptr.map_addr(|a| a & val)`. This can be used in tagged
+    /// pointer schemes to atomically unset tag bits.
+    ///
+    /// **Caveat**: This operation returns the previous value. To compute the
+    /// stored value without losing provenance, you may use [`map_addr`]. For
+    /// example: `a.fetch_and(val).map_addr(|a| a & val)`.
+    ///
+    /// `fetch_and` takes an [`Ordering`] argument which describes the memory
+    /// ordering of this operation. All ordering modes are possible. Note that
+    /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
+    /// and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance
+    /// experiment, see the [module documentation for `ptr`][crate::ptr] for
+    /// details.
+    ///
+    /// [`map_addr`]: pointer::map_addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let pointer = &mut 3i64 as *mut i64;
+    /// // A tagged pointer
+    /// let atom = AtomicPtr::<i64>::new(pointer.map_addr(|a| a | 1));
+    /// assert_eq!(atom.fetch_or(1, Ordering::Relaxed).addr() & 1, 1);
+    /// // Untag, and extract the previously tagged pointer.
+    /// let untagged = atom.fetch_and(!1, Ordering::Relaxed)
+    ///     .map_addr(|a| a & !1);
+    /// assert_eq!(untagged, pointer);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_and(&self, val: usize, order: Ordering) -> *mut T {
+        #[cfg(not(bootstrap))]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_and(self.p.get(), core::ptr::invalid_mut(val), order).cast()
+        }
+        #[cfg(bootstrap)]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_and(self.p.get().cast::<usize>(), val, order) as *mut T
+        }
+    }
+
+    /// Performs a bitwise "xor" operation on the address of the current
+    /// pointer, and the argument `val`, and stores a pointer with provenance of
+    /// the current pointer and the resulting address.
+    ///
+    /// This is equivalent equivalent to using [`map_addr`] to atomically
+    /// perform `ptr = ptr.map_addr(|a| a ^ val)`. This can be used in tagged
+    /// pointer schemes to atomically toggle tag bits.
+    ///
+    /// **Caveat**: This operation returns the previous value. To compute the
+    /// stored value without losing provenance, you may use [`map_addr`]. For
+    /// example: `a.fetch_xor(val).map_addr(|a| a ^ val)`.
+    ///
+    /// `fetch_xor` takes an [`Ordering`] argument which describes the memory
+    /// ordering of this operation. All ordering modes are possible. Note that
+    /// using [`Acquire`] makes the store part of this operation [`Relaxed`],
+    /// and using [`Release`] makes the load part [`Relaxed`].
+    ///
+    /// **Note**: This method is only available on platforms that support atomic
+    /// operations on [`AtomicPtr`].
+    ///
+    /// This API and its claimed semantics are part of the Strict Provenance
+    /// experiment, see the [module documentation for `ptr`][crate::ptr] for
+    /// details.
+    ///
+    /// [`map_addr`]: pointer::map_addr
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(strict_provenance_atomic_ptr, strict_provenance)]
+    /// use core::sync::atomic::{AtomicPtr, Ordering};
+    ///
+    /// let pointer = &mut 3i64 as *mut i64;
+    /// let atom = AtomicPtr::<i64>::new(pointer);
+    ///
+    /// // Toggle a tag bit on the pointer.
+    /// atom.fetch_xor(1, Ordering::Relaxed);
+    /// assert_eq!(atom.load(Ordering::Relaxed).addr() & 1, 1);
+    /// ```
+    #[inline]
+    #[cfg(target_has_atomic = "ptr")]
+    #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")]
+    pub fn fetch_xor(&self, val: usize, order: Ordering) -> *mut T {
+        #[cfg(not(bootstrap))]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_xor(self.p.get(), core::ptr::invalid_mut(val), order).cast()
+        }
+        #[cfg(bootstrap)]
+        // SAFETY: data races are prevented by atomic intrinsics.
+        unsafe {
+            atomic_xor(self.p.get().cast::<usize>(), val, order) as *mut T
+        }
+    }
 }
 
 #[cfg(target_has_atomic_load_store = "8")]
@@ -2351,7 +2692,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"),
     "i8",
     "",
@@ -2371,7 +2712,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"),
     "u8",
     "",
@@ -2391,7 +2732,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"),
     "i16",
     "",
@@ -2411,7 +2752,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"),
     "u16",
     "",
@@ -2431,7 +2772,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"),
     "i32",
     "",
@@ -2451,7 +2792,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"),
     "u32",
     "",
@@ -2471,7 +2812,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"),
     "i64",
     "",
@@ -2491,7 +2832,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"),
     "u64",
     "",
@@ -2504,14 +2845,14 @@ atomic_int! {
 atomic_int! {
     cfg(target_has_atomic = "128"),
     cfg(target_has_atomic_equal_alignment = "128"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"),
     "i128",
     "#![feature(integer_atomics)]\n\n",
@@ -2524,14 +2865,14 @@ atomic_int! {
 atomic_int! {
     cfg(target_has_atomic = "128"),
     cfg(target_has_atomic_equal_alignment = "128"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
-    unstable(feature = "integer_atomics", issue = "32976"),
+    unstable(feature = "integer_atomics", issue = "99069"),
     cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"),
     "u128",
     "#![feature(integer_atomics)]\n\n",
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index ab3763cbc41..b664b0bb866 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -107,7 +107,7 @@ macro_rules! tuple_impls {
 // Otherwise, it hides the docs entirely.
 macro_rules! maybe_tuple_doc {
     ($a:ident @ #[$meta:meta] $item:item) => {
-        #[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+        #[doc(tuple_variadic)]
         #[doc = "This trait is implemented for tuples up to twelve items long."]
         #[$meta]
         $item
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index 7f8672f0354..13b12db209a 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -127,6 +127,91 @@ fn int_max() {
     assert_eq!(x.load(SeqCst), 0xf731);
 }
 
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_add_null() {
+    let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+    assert_eq!(atom.fetch_ptr_add(1, SeqCst).addr(), 0);
+    assert_eq!(atom.load(SeqCst).addr(), 8);
+
+    assert_eq!(atom.fetch_byte_add(1, SeqCst).addr(), 8);
+    assert_eq!(atom.load(SeqCst).addr(), 9);
+
+    assert_eq!(atom.fetch_ptr_sub(1, SeqCst).addr(), 9);
+    assert_eq!(atom.load(SeqCst).addr(), 1);
+
+    assert_eq!(atom.fetch_byte_sub(1, SeqCst).addr(), 1);
+    assert_eq!(atom.load(SeqCst).addr(), 0);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_add_data() {
+    let num = 0i64;
+    let n = &num as *const i64 as *mut _;
+    let atom = AtomicPtr::<i64>::new(n);
+    assert_eq!(atom.fetch_ptr_add(1, SeqCst), n);
+    assert_eq!(atom.load(SeqCst), n.wrapping_add(1));
+
+    assert_eq!(atom.fetch_ptr_sub(1, SeqCst), n.wrapping_add(1));
+    assert_eq!(atom.load(SeqCst), n);
+    let bytes_from_n = |b| n.cast::<u8>().wrapping_add(b).cast::<i64>();
+
+    assert_eq!(atom.fetch_byte_add(1, SeqCst), n);
+    assert_eq!(atom.load(SeqCst), bytes_from_n(1));
+
+    assert_eq!(atom.fetch_byte_add(5, SeqCst), bytes_from_n(1));
+    assert_eq!(atom.load(SeqCst), bytes_from_n(6));
+
+    assert_eq!(atom.fetch_byte_sub(1, SeqCst), bytes_from_n(6));
+    assert_eq!(atom.load(SeqCst), bytes_from_n(5));
+
+    assert_eq!(atom.fetch_byte_sub(5, SeqCst), bytes_from_n(5));
+    assert_eq!(atom.load(SeqCst), n);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_bitops() {
+    let atom = AtomicPtr::<i64>::new(core::ptr::null_mut());
+    assert_eq!(atom.fetch_or(0b0111, SeqCst).addr(), 0);
+    assert_eq!(atom.load(SeqCst).addr(), 0b0111);
+
+    assert_eq!(atom.fetch_and(0b1101, SeqCst).addr(), 0b0111);
+    assert_eq!(atom.load(SeqCst).addr(), 0b0101);
+
+    assert_eq!(atom.fetch_xor(0b1111, SeqCst).addr(), 0b0101);
+    assert_eq!(atom.load(SeqCst).addr(), 0b1010);
+}
+
+#[test]
+#[cfg(any(not(target_arch = "arm"), target_os = "linux"))] // Missing intrinsic in compiler-builtins
+fn ptr_bitops_tagging() {
+    #[repr(align(16))]
+    struct Tagme(u128);
+
+    let tagme = Tagme(1000);
+    let ptr = &tagme as *const Tagme as *mut Tagme;
+    let atom: AtomicPtr<Tagme> = AtomicPtr::new(ptr);
+
+    const MASK_TAG: usize = 0b1111;
+    const MASK_PTR: usize = !MASK_TAG;
+
+    assert_eq!(ptr.addr() & MASK_TAG, 0);
+
+    assert_eq!(atom.fetch_or(0b0111, SeqCst), ptr);
+    assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b111));
+
+    assert_eq!(atom.fetch_and(MASK_PTR | 0b0010, SeqCst), ptr.map_addr(|a| a | 0b111));
+    assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b0010));
+
+    assert_eq!(atom.fetch_xor(0b1011, SeqCst), ptr.map_addr(|a| a | 0b0010));
+    assert_eq!(atom.load(SeqCst), ptr.map_addr(|a| a | 0b1001));
+
+    assert_eq!(atom.fetch_and(MASK_PTR, SeqCst), ptr.map_addr(|a| a | 0b1001));
+    assert_eq!(atom.load(SeqCst), ptr);
+}
+
 static S_FALSE: AtomicBool = AtomicBool::new(false);
 static S_TRUE: AtomicBool = AtomicBool::new(true);
 static S_INT: AtomicIsize = AtomicIsize::new(0);
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 9611e197a41..2c54bfb35eb 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -73,7 +73,6 @@
 #![feature(iterator_try_reduce)]
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
-#![feature(const_slice_from_raw_parts)]
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
 #![feature(result_into_ok_or_err)]
@@ -90,6 +89,7 @@
 #![feature(slice_group_by)]
 #![feature(split_array)]
 #![feature(strict_provenance)]
+#![feature(strict_provenance_atomic_ptr)]
 #![feature(trusted_random_access)]
 #![feature(unsize)]
 #![feature(unzip_option)]
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 187a7db7fcb..bab2b1792f6 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -96,17 +96,14 @@ fn test_is_null() {
     let nmi: *mut dyn ToString = null_mut::<isize>();
     assert!(nmi.is_null());
 
-    #[cfg(not(bootstrap))]
-    {
-        extern "C" {
-            type Extern;
-        }
-        let ec: *const Extern = null::<Extern>();
-        assert!(ec.is_null());
-
-        let em: *mut Extern = null_mut::<Extern>();
-        assert!(em.is_null());
+    extern "C" {
+        type Extern;
     }
+    let ec: *const Extern = null::<Extern>();
+    assert!(ec.is_null());
+
+    let em: *mut Extern = null_mut::<Extern>();
+    assert!(em.is_null());
 }
 
 #[test]
@@ -785,6 +782,31 @@ fn nonnull_tagged_pointer_with_provenance() {
 }
 
 #[test]
+fn swap_copy_untyped() {
+    // We call `{swap,copy}{,_nonoverlapping}` at `bool` type on data that is not a valid bool.
+    // These should all do untyped copies, so this should work fine.
+    let mut x = 5u8;
+    let mut y = 6u8;
+
+    let ptr1 = &mut x as *mut u8 as *mut bool;
+    let ptr2 = &mut y as *mut u8 as *mut bool;
+
+    unsafe {
+        ptr::swap(ptr1, ptr2);
+        ptr::swap_nonoverlapping(ptr1, ptr2, 1);
+    }
+    assert_eq!(x, 5);
+    assert_eq!(y, 6);
+
+    unsafe {
+        ptr::copy(ptr1, ptr2, 1);
+        ptr::copy_nonoverlapping(ptr1, ptr2, 1);
+    }
+    assert_eq!(x, 5);
+    assert_eq!(y, 5);
+}
+
+#[test]
 fn test_const_copy() {
     const {
         let ptr1 = &1;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ba76ee31b42..298321f41e4 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -210,6 +210,8 @@
 #![allow(unused_lifetimes)]
 // Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
+// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
+#![cfg_attr(not(bootstrap), deny(ffi_unwind_calls))]
 // std may use features in a platform-specific way
 #![allow(unused_features)]
 #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
@@ -249,7 +251,6 @@
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![cfg_attr(bootstrap, feature(nll))]
 #![feature(platform_intrinsics)]
 #![feature(prelude_import)]
 #![feature(rustc_attrs)]
@@ -585,7 +586,7 @@ mod backtrace_rs;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
 pub use core::{
-    assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, r#try, todo,
+    assert_eq, assert_ne, debug_assert, debug_assert_eq, debug_assert_ne, matches, todo, r#try,
     unimplemented, unreachable, write, writeln,
 };
 
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 06300035633..69b72a81c5b 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -7,6 +7,7 @@ use crate::io::prelude::*;
 
 use crate::fmt;
 use crate::io::{self, IoSlice, IoSliceMut};
+use crate::iter::FusedIterator;
 use crate::net::{Shutdown, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -1009,6 +1010,9 @@ impl<'a> Iterator for Incoming<'a> {
     }
 }
 
+#[stable(feature = "tcp_listener_incoming_fused_iterator", since = "1.64.0")]
+impl FusedIterator for Incoming<'_> {}
+
 #[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
 impl Iterator for IntoIncoming {
     type Item = io::Result<TcpStream>;
@@ -1017,6 +1021,9 @@ impl Iterator for IntoIncoming {
     }
 }
 
+#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
+impl FusedIterator for IntoIncoming {}
+
 impl AsInner<net_imp::TcpListener> for TcpListener {
     fn as_inner(&self) -> &net_imp::TcpListener {
         &self.0
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index dd965ddc01e..d661a13edc5 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -355,3 +355,34 @@ impl From<OwnedFd> for crate::net::UdpSocket {
         ))))
     }
 }
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+/// This impl allows implementing traits that require `AsFd` on Arc.
+/// ```
+/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
+/// # #[cfg(target_os = "wasi")]
+/// # use std::os::wasi::io::AsFd;
+/// # #[cfg(unix)]
+/// # use std::os::unix::io::AsFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+///
+/// trait MyTrait: AsFd {}
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+impl<T: AsFd> AsFd for crate::sync::Arc<T> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        (**self).as_fd()
+    }
+}
+
+#[stable(feature = "io_safety", since = "1.63.0")]
+impl<T: AsFd> AsFd for Box<T> {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        (**self).as_fd()
+    }
+}
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 47ee88d97fb..ff4e25b792a 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -73,7 +73,7 @@ pub trait FromRawFd {
     ///
     /// # Safety
     ///
-    /// The `fd` passed in must be a valid an open file descriptor.
+    /// The `fd` passed in must be a valid and open file descriptor.
     ///
     /// # Example
     ///
@@ -222,3 +222,34 @@ impl<'a> AsRawFd for io::StderrLock<'a> {
         libc::STDERR_FILENO
     }
 }
+
+/// This impl allows implementing traits that require `AsRawFd` on Arc.
+/// ```
+/// # #[cfg(any(unix, target_os = "wasi"))] mod group_cfg {
+/// # #[cfg(target_os = "wasi")]
+/// # use std::os::wasi::io::AsRawFd;
+/// # #[cfg(unix)]
+/// # use std::os::unix::io::AsRawFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+/// trait MyTrait: AsRawFd {
+/// }
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
+impl<T: AsRawFd> AsRawFd for crate::sync::Arc<T> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        (**self).as_raw_fd()
+    }
+}
+
+#[stable(feature = "asrawfd_ptrs", since = "1.63.0")]
+impl<T: AsRawFd> AsRawFd for Box<T> {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        (**self).as_raw_fd()
+    }
+}
diff --git a/library/std/src/os/windows/ffi.rs b/library/std/src/os/windows/ffi.rs
index a9493a94cac..96bab59d3f8 100644
--- a/library/std/src/os/windows/ffi.rs
+++ b/library/std/src/os/windows/ffi.rs
@@ -129,6 +129,7 @@ pub trait OsStrExt: Sealed {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl OsStrExt for OsStr {
+    #[inline]
     fn encode_wide(&self) -> EncodeWide<'_> {
         self.as_inner().inner.encode_wide()
     }
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index a6b75493e6e..073168cf2d2 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -234,3 +234,26 @@ impl ChildExt for process::Child {
         self.handle.main_thread_handle()
     }
 }
+
+/// Windows-specific extensions to [`process::ExitCode`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+pub trait ExitCodeExt: Sealed {
+    /// Creates a new `ExitCode` from the raw underlying `u32` return value of
+    /// a process.
+    ///
+    /// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
+    /// macro returned from the `GetExitCodeProcess` function to signal that the
+    /// process has yet to run to completion.
+    #[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+    fn from_raw(raw: u32) -> Self;
+}
+
+#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+impl ExitCodeExt for process::ExitCode {
+    fn from_raw(raw: u32) -> Self {
+        process::ExitCode::from_inner(From::from(raw))
+    }
+}
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 00793f7f920..401c8159988 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -996,7 +996,7 @@ impl<T> (T,) {}
 // Fake impl that's only really used for docs.
 #[cfg(doc)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+#[doc(tuple_variadic)]
 /// This trait is implemented on arbitrary-length tuples.
 impl<T: Clone> Clone for (T,) {
     fn clone(&self) -> Self {
@@ -1007,7 +1007,7 @@ impl<T: Clone> Clone for (T,) {
 // Fake impl that's only really used for docs.
 #[cfg(doc)]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(bootstrap), doc(tuple_variadic))]
+#[doc(tuple_variadic)]
 /// This trait is implemented on arbitrary-length tuples.
 impl<T: Copy> Copy for (T,) {
     // empty
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index ab1a1e6c76f..d6cba7e7598 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1724,6 +1724,10 @@ impl crate::error::Error for ExitStatusError {}
 #[stable(feature = "process_exitcode", since = "1.61.0")]
 pub struct ExitCode(imp::ExitCode);
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for ExitCode {}
+
 #[stable(feature = "process_exitcode", since = "1.61.0")]
 impl ExitCode {
     /// The canonical `ExitCode` for successful termination on this platform.
@@ -1814,6 +1818,18 @@ impl From<u8> for ExitCode {
     }
 }
 
+impl AsInner<imp::ExitCode> for ExitCode {
+    fn as_inner(&self) -> &imp::ExitCode {
+        &self.0
+    }
+}
+
+impl FromInner<imp::ExitCode> for ExitCode {
+    fn from_inner(s: imp::ExitCode) -> ExitCode {
+        ExitCode(s)
+    }
+}
+
 impl Child {
     /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
     /// error is returned.
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 5469487df1e..c7a42ef9a93 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -326,7 +326,9 @@ union IO_STATUS_BLOCK_union {
 }
 impl Default for IO_STATUS_BLOCK_union {
     fn default() -> Self {
-        Self { Pointer: ptr::null_mut() }
+        let mut this = Self { Pointer: ptr::null_mut() };
+        this.Status = STATUS_PENDING;
+        this
     }
 }
 #[repr(C)]
@@ -335,6 +337,16 @@ pub struct IO_STATUS_BLOCK {
     u: IO_STATUS_BLOCK_union,
     pub Information: usize,
 }
+impl IO_STATUS_BLOCK {
+    pub fn status(&self) -> NTSTATUS {
+        // SAFETY: If `self.u.Status` was set then this is obviously safe.
+        // If `self.u.Pointer` was set then this is the equivalent to converting
+        // the pointer to an integer, which is also safe.
+        // Currently the only safe way to construct `IO_STATUS_BLOCK` outside of
+        // this module is to call the `default` method, which sets the `Status`.
+        unsafe { self.u.Status }
+    }
+}
 
 pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn(
     dwErrorCode: DWORD,
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 1e7b6e1eab0..e24b09cc96e 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -1,5 +1,8 @@
 #![unstable(issue = "none", feature = "windows_handle")]
 
+#[cfg(test)]
+mod tests;
+
 use crate::cmp;
 use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf};
 use crate::mem;
@@ -248,14 +251,18 @@ impl Handle {
             offset.map(|n| n as _).as_ref(),
             None,
         );
+
+        let status = if status == c::STATUS_PENDING {
+            c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE);
+            io_status.status()
+        } else {
+            status
+        };
         match status {
             // If the operation has not completed then abort the process.
             // Doing otherwise means that the buffer and stack may be written to
             // after this function returns.
-            c::STATUS_PENDING => {
-                eprintln!("I/O error: operation failed to complete synchronously");
-                crate::process::abort();
-            }
+            c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
 
             // Return `Ok(0)` when there's nothing more to read.
             c::STATUS_END_OF_FILE => Ok(0),
@@ -294,13 +301,17 @@ impl Handle {
                 None,
             )
         };
+        let status = if status == c::STATUS_PENDING {
+            unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) };
+            io_status.status()
+        } else {
+            status
+        };
         match status {
             // If the operation has not completed then abort the process.
             // Doing otherwise means that the buffer may be read and the stack
             // written to after this function returns.
-            c::STATUS_PENDING => {
-                rtabort!("I/O error: operation failed to complete synchronously");
-            }
+            c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
 
             // Success!
             status if c::nt_success(status) => Ok(io_status.Information),
diff --git a/library/std/src/sys/windows/handle/tests.rs b/library/std/src/sys/windows/handle/tests.rs
new file mode 100644
index 00000000000..d836dae4c30
--- /dev/null
+++ b/library/std/src/sys/windows/handle/tests.rs
@@ -0,0 +1,22 @@
+use crate::sys::pipe::{anon_pipe, Pipes};
+use crate::{thread, time};
+
+/// Test the synchronous fallback for overlapped I/O.
+#[test]
+fn overlapped_handle_fallback() {
+    // Create some pipes. `ours` will be asynchronous.
+    let Pipes { ours, theirs } = anon_pipe(true, false).unwrap();
+
+    let async_readable = ours.into_handle();
+    let sync_writeable = theirs.into_handle();
+
+    thread::scope(|_| {
+        thread::sleep(time::Duration::from_millis(100));
+        sync_writeable.write(b"hello world!").unwrap();
+    });
+
+    // The pipe buffer starts empty so reading won't complete synchronously unless
+    // our fallback path works.
+    let mut buffer = [0u8; 1024];
+    async_readable.read(&mut buffer).unwrap();
+}
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 9fd399f4ba1..02d5af4719a 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -707,6 +707,12 @@ impl From<u8> for ExitCode {
     }
 }
 
+impl From<u32> for ExitCode {
+    fn from(code: u32) -> Self {
+        ExitCode(c::DWORD::from(code))
+    }
+}
+
 fn zeroed_startupinfo() -> c::STARTUPINFO {
     c::STARTUPINFO {
         cb: 0,
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index 000f5fa3f58..f981b9c4954 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -196,6 +196,7 @@ Test Attributes:
 pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     // Parse matches.
     let opts = optgroups();
+    let binary = args.get(0).map(|c| &**c).unwrap_or("...");
     let args = args.get(1..).unwrap_or(args);
     let matches = match opts.parse(args) {
         Ok(m) => m,
@@ -205,7 +206,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
     // Check if help was requested.
     if matches.opt_present("h") {
         // Show help and do nothing more.
-        usage(&args[0], &opts);
+        usage(binary, &opts);
         return None;
     }
 
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 52d737de7ae..4a6ba6e10c3 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -1,7 +1,6 @@
 #![no_std]
 #![unstable(feature = "panic_unwind", issue = "32837")]
 #![feature(link_cfg)]
-#![cfg_attr(bootstrap, feature(native_link_modifiers_bundle))]
 #![feature(staged_api)]
 #![feature(c_unwind)]
 #![feature(cfg_target_abi)]
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 206bc38efb3..85afc1f5f6c 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - The options `infodir`, `localstatedir`, and `gpg-password-file` are no longer allowed in config.toml. Previously, they were ignored without warning. Note that `infodir` and `localstatedir` are still accepted by `./configure`, with a warning. [#82451](https://github.com/rust-lang/rust/pull/82451)
 - Change the names for `dist` commands to match the component they generate. [#90684](https://github.com/rust-lang/rust/pull/90684)
 - The `build.fast-submodules` option has been removed. Fast submodule checkouts are enabled unconditionally. Automatic submodule handling can still be disabled with `build.submodules = false`.
+- Several unsupported `./configure` options have been removed: `optimize`, `parallel-compiler`. These can still be enabled with `--set`, although it isn't recommended.
 
 ### Non-breaking changes
 
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 6fcbd7a2156..664ffa1ddd2 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -47,6 +47,7 @@ version = "0.0.0"
 dependencies = [
  "cc",
  "cmake",
+ "fd-lock",
  "filetime",
  "getopts",
  "hex",
@@ -202,6 +203,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 
 [[package]]
+name = "errno"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "fd-lock"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517"
+dependencies = [
+ "cfg-if",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
 name = "filetime"
 version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -285,6 +318,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "io-lifetimes"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb"
+
+[[package]]
 name = "itoa"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -303,6 +342,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
 
 [[package]]
+name = "linux-raw-sys"
+version = "0.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
+
+[[package]]
 name = "log"
 version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -474,6 +519,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
 
 [[package]]
+name = "rustix"
+version = "0.35.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef258c11e17f5c01979a10543a30a4e12faef6aab217a74266e747eefa3aed88"
+dependencies = [
+ "bitflags",
+ "errno",
+ "io-lifetimes",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
 name = "ryu"
 version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -658,6 +717,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
+[[package]]
 name = "xattr"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index b9bd3d0cf78..84f6aaf99c1 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -36,6 +36,7 @@ test = false
 
 [dependencies]
 cmake = "0.1.38"
+fd-lock = "3.0.6"
 filetime = "0.2"
 num_cpus = "1.0"
 getopts = "0.2.19"
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index 9c41ab69c8b..9b4861ccd95 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -7,12 +7,28 @@
 
 use std::env;
 
-use bootstrap::{Build, Config, Subcommand, VERSION};
+use bootstrap::{t, Build, Config, Subcommand, VERSION};
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
     let config = Config::parse(&args);
 
+    let mut build_lock;
+    let _build_lock_guard;
+    if cfg!(any(unix, windows)) {
+        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock"))));
+        _build_lock_guard = match build_lock.try_write() {
+            Ok(lock) => lock,
+            err => {
+                println!("warning: build directory locked, waiting for lock");
+                drop(err);
+                t!(build_lock.write())
+            }
+        };
+    } else {
+        println!("warning: file locking not supported for target, not locking build directory");
+    }
+
     // check_version warnings are not printed during setup
     let changelog_suggestion =
         if matches!(config.cmd, Subcommand::Setup { .. }) { None } else { check_version(&config) };
diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs
index 5f85fc5aa59..87c1d22e771 100644
--- a/src/bootstrap/bin/rustdoc.rs
+++ b/src/bootstrap/bin/rustdoc.rs
@@ -31,9 +31,7 @@ fn main() {
 
     let mut cmd = Command::new(rustdoc);
 
-    // cfg(bootstrap)
-    // NOTE: the `--test` special-casing can be removed when https://github.com/rust-lang/cargo/pull/10594 lands on beta.
-    if target.is_some() || args.iter().any(|x| x == "--test") {
+    if target.is_some() {
         // The stage0 compiler has a special sysroot distinct from what we
         // actually downloaded, so we just always pass the `--sysroot` option,
         // unless one is already set.
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 6ead79ef040..9301c5a2ff3 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -15,44 +15,6 @@ import tempfile
 
 from time import time, sleep
 
-# Acquire a lock on the build directory to make sure that
-# we don't cause a race condition while building
-# Lock is created in `build_dir/lock.db`
-def acquire_lock(build_dir):
-    try:
-        import sqlite3
-
-        path = os.path.join(build_dir, "lock.db")
-        try:
-            con = sqlite3.Connection(path, timeout=0)
-            curs = con.cursor()
-            curs.execute("BEGIN EXCLUSIVE")
-            # The lock is released when the cursor is dropped
-            return curs
-        # If the database is busy then lock has already been acquired
-        # so we wait for the lock.
-        # We retry every quarter second so that execution is passed back to python
-        # so that it can handle signals
-        except sqlite3.OperationalError:
-            del con
-            del curs
-            print("Waiting for lock on build directory")
-            con = sqlite3.Connection(path, timeout=0.25)
-            curs = con.cursor()
-            while True:
-                try:
-                    curs.execute("BEGIN EXCLUSIVE")
-                    break
-                except sqlite3.OperationalError:
-                    pass
-                sleep(0.25)
-            return curs
-    except ImportError:
-        print("warning: sqlite3 not available in python, skipping build directory lock")
-        print("please file an issue on rust-lang/rust")
-        print("this is not a problem for non-concurrent x.py invocations")
-        return None
-
 def support_xz():
     try:
         with tempfile.NamedTemporaryFile(delete=False) as temp_file:
@@ -190,6 +152,10 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
     if verbose:
         print("running: " + ' '.join(args))
     sys.stdout.flush()
+    # Ensure that the .exe is used on Windows just in case a Linux ELF has been
+    # compiled in the same directory.
+    if os.name == 'nt' and not args[0].endswith('.exe'):
+        args[0] += '.exe'
     # Use Popen here instead of call() as it apparently allows powershell on
     # Windows to not lock up waiting for input presumably.
     ret = subprocess.Popen(args, **kwargs)
@@ -928,11 +894,8 @@ def bootstrap(help_triggered):
 
     build.build = args.build or build.build_triple()
 
-    # Acquire the lock before doing any build actions
-    # The lock is released when `lock` is dropped
     if not os.path.exists(build.build_dir):
         os.makedirs(build.build_dir)
-    lock = acquire_lock(build.build_dir)
 
     # Fetch/build the bootstrap
     build.download_toolchain()
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 62b5416cee8..fa6a5ee1668 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -13,7 +13,6 @@ use std::process::{Command, Stdio};
 use std::time::{Duration, Instant};
 
 use crate::cache::{Cache, Interned, INTERNER};
-use crate::compile;
 use crate::config::{SplitDebuginfo, TargetSelection};
 use crate::dist;
 use crate::doc;
@@ -26,6 +25,7 @@ use crate::tool::{self, SourceType};
 use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
 use crate::EXTRA_CHECK_CFGS;
 use crate::{check, Config};
+use crate::{compile, Crate};
 use crate::{Build, CLang, DocTests, GitRepo, Mode};
 
 pub use crate::Compiler;
@@ -304,9 +304,7 @@ impl StepDescription {
         if paths.is_empty() || builder.config.include_default_paths {
             for (desc, should_run) in v.iter().zip(&should_runs) {
                 if desc.default && should_run.is_really_default() {
-                    for pathset in &should_run.paths {
-                        desc.maybe_run(builder, vec![pathset.clone()]);
-                    }
+                    desc.maybe_run(builder, should_run.paths.iter().cloned().collect());
                 }
             }
         }
@@ -348,11 +346,7 @@ impl StepDescription {
             eprintln!(
                 "note: if you are adding a new Step to bootstrap itself, make sure you register it with `describe!`"
             );
-            #[cfg(not(test))]
-            std::process::exit(1);
-            #[cfg(test)]
-            // so we can use #[should_panic]
-            panic!()
+            crate::detail_exit(1);
         }
     }
 }
@@ -424,8 +418,16 @@ impl<'a> ShouldRun<'a> {
     /// any of its (local) dependencies.
     ///
     /// `make_run` will be called a single time with all matching command-line paths.
-    pub fn krate(mut self, name: &str) -> Self {
-        for krate in self.builder.in_tree_crates(name, None) {
+    pub fn crate_or_deps(self, name: &str) -> Self {
+        let crates = self.builder.in_tree_crates(name, None);
+        self.crates(crates)
+    }
+
+    /// Indicates it should run if the command-line selects any of the given crates.
+    ///
+    /// `make_run` will be called a single time with all matching command-line paths.
+    pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self {
+        for krate in crates {
             let path = krate.local_path(self.builder);
             self.paths.insert(PathSet::one(path, self.kind));
         }
@@ -581,6 +583,7 @@ impl<'a> Builder<'a> {
         match kind {
             Kind::Build => describe!(
                 compile::Std,
+                compile::Rustc,
                 compile::Assemble,
                 compile::CodegenBackend,
                 compile::StartupObjects,
@@ -694,6 +697,7 @@ impl<'a> Builder<'a> {
                 doc::RustcBook,
                 doc::CargoBook,
                 doc::Clippy,
+                doc::Miri,
                 doc::EmbeddedBook,
                 doc::EditionGuide,
             ),
@@ -945,6 +949,7 @@ impl<'a> Builder<'a> {
     }
 
     pub(crate) fn download_component(&self, url: &str, dest_path: &Path, help_on_error: &str) {
+        self.verbose(&format!("download {url}"));
         // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
         let tempfile = self.tempdir().join(dest_path.file_name().unwrap());
         // While bootstrap itself only supports http and https downloads, downstream forks might
@@ -1000,7 +1005,7 @@ impl<'a> Builder<'a> {
             if !help_on_error.is_empty() {
                 eprintln!("{}", help_on_error);
             }
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
     }
 
@@ -1429,7 +1434,7 @@ impl<'a> Builder<'a> {
                         "error: `x.py clippy` requires a host `rustc` toolchain with the `clippy` component"
                     );
                     eprintln!("help: try `rustup component add clippy`");
-                    std::process::exit(1);
+                    crate::detail_exit(1);
                 });
                 if !t!(std::str::from_utf8(&output.stdout)).contains("nightly") {
                     rustflags.arg("--cfg=bootstrap");
@@ -1760,7 +1765,8 @@ impl<'a> Builder<'a> {
             let needs_unstable_opts = target.contains("linux")
                 || target.contains("windows")
                 || target.contains("bsd")
-                || target.contains("dragonfly");
+                || target.contains("dragonfly")
+                || target.contains("illumos");
 
             if needs_unstable_opts {
                 rustflags.arg("-Zunstable-options");
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 70cb0de7cce..c084e77d3a9 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -57,6 +57,24 @@ fn check_cli<const N: usize>(paths: [&str; N]) {
     );
 }
 
+macro_rules! std {
+    ($host:ident => $target:ident, stage = $stage:literal) => {
+        compile::Std::new(
+            Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage },
+            TargetSelection::from_user(stringify!($target)),
+        )
+    };
+}
+
+macro_rules! rustc {
+    ($host:ident => $target:ident, stage = $stage:literal) => {
+        compile::Rustc::new(
+            Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage },
+            TargetSelection::from_user(stringify!($target)),
+        )
+    };
+}
+
 #[test]
 fn test_valid() {
     // make sure multi suite paths are accepted
@@ -117,6 +135,17 @@ fn test_exclude_kind() {
     assert!(run_build(&[path], config).contains::<tool::CargoTest>());
 }
 
+/// Ensure that if someone passes both a single crate and `library`, all library crates get built.
+#[test]
+fn alias_and_path_for_library() {
+    let mut cache =
+        run_build(&["library".into(), "core".into()], configure("build", &["A"], &["A"]));
+    assert_eq!(
+        first(cache.all::<compile::Std>()),
+        &[std!(A => A, stage = 0), std!(A => A, stage = 1)]
+    );
+}
+
 mod defaults {
     use super::{configure, first, run_build};
     use crate::builder::*;
@@ -130,10 +159,7 @@ mod defaults {
         let a = TargetSelection::from_user("A");
         assert_eq!(
             first(cache.all::<compile::Std>()),
-            &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            ]
+            &[std!(A => A, stage = 0), std!(A => A, stage = 1),]
         );
         assert!(!cache.all::<compile::Assemble>().is_empty());
         // Make sure rustdoc is only built once.
@@ -143,10 +169,7 @@ mod defaults {
             // - this is the compiler it's _linked_ to, not built with.
             &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
         );
-        assert_eq!(
-            first(cache.all::<compile::Rustc>()),
-            &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
-        );
+        assert_eq!(first(cache.all::<compile::Rustc>()), &[rustc!(A => A, stage = 0)],);
     }
 
     #[test]
@@ -155,10 +178,7 @@ mod defaults {
         let mut cache = run_build(&[], config);
 
         let a = TargetSelection::from_user("A");
-        assert_eq!(
-            first(cache.all::<compile::Std>()),
-            &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
-        );
+        assert_eq!(first(cache.all::<compile::Std>()), &[std!(A => A, stage = 0)]);
         assert!(!cache.all::<compile::Assemble>().is_empty());
         assert_eq!(
             first(cache.all::<tool::Rustdoc>()),
@@ -185,10 +205,10 @@ mod defaults {
         assert_eq!(
             first(cache.all::<compile::Std>()),
             &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                std!(A => A, stage = 0),
+                std!(A => A, stage = 1),
+                std!(A => B, stage = 0),
+                std!(A => B, stage = 1),
             ]
         );
         assert_eq!(
@@ -208,10 +228,7 @@ mod defaults {
         );
         assert_eq!(
             first(cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b },
-            ]
+            &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 0),]
         );
     }
 
@@ -334,11 +351,11 @@ mod dist {
         assert_eq!(
             first(cache.all::<compile::Std>()),
             &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+                std!(A => A, stage = 0),
+                std!(A => A, stage = 1),
+                std!(A => A, stage = 2),
+                std!(A => B, stage = 1),
+                std!(A => B, stage = 2),
             ],
         );
         assert_eq!(first(cache.all::<dist::Src>()), &[dist::Src]);
@@ -346,7 +363,6 @@ mod dist {
 
     #[test]
     fn dist_only_cross_host() {
-        let a = TargetSelection::from_user("A");
         let b = TargetSelection::from_user("B");
         let mut config = configure(&["A", "B"], &["A", "B"]);
         config.docs = false;
@@ -360,10 +376,7 @@ mod dist {
         );
         assert_eq!(
             first(cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
-            ]
+            &[rustc!(A => A, stage = 0), rustc!(A => B, stage = 1),]
         );
     }
 
@@ -450,11 +463,11 @@ mod dist {
         assert_eq!(
             first(cache.all::<compile::Std>()),
             &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+                std!(A => A, stage = 0),
+                std!(A => A, stage = 1),
+                std!(A => A, stage = 2),
+                std!(A => B, stage = 1),
+                std!(A => B, stage = 2),
             ]
         );
         assert_eq!(
@@ -474,33 +487,29 @@ mod dist {
         let mut builder = Builder::new(&build);
         builder.run_step_descriptions(
             &Builder::get_step_descriptions(Kind::Build),
-            &["compiler/rustc".into(), "library/std".into()],
+            &["compiler/rustc".into(), "library".into()],
         );
 
-        let a = TargetSelection::from_user("A");
-        let b = TargetSelection::from_user("B");
-        let c = TargetSelection::from_user("C");
-
         assert_eq!(
             first(builder.cache.all::<compile::Std>()),
             &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
+                std!(A => A, stage = 0),
+                std!(A => A, stage = 1),
+                std!(A => A, stage = 2),
+                std!(A => B, stage = 1),
+                std!(A => B, stage = 2),
+                std!(A => C, stage = 2),
             ]
         );
-        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        assert_eq!(builder.cache.all::<compile::Assemble>().len(), 5);
         assert_eq!(
             first(builder.cache.all::<compile::Rustc>()),
             &[
-                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
-                compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
+                rustc!(A => A, stage = 0),
+                rustc!(A => A, stage = 1),
+                rustc!(A => A, stage = 2),
+                rustc!(A => B, stage = 1),
+                rustc!(A => B, stage = 2),
             ]
         );
     }
@@ -513,15 +522,10 @@ mod dist {
         builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
 
         let a = TargetSelection::from_user("A");
-        let c = TargetSelection::from_user("C");
 
         assert_eq!(
             first(builder.cache.all::<compile::Std>()),
-            &[
-                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-            ]
+            &[std!(A => A, stage = 0), std!(A => A, stage = 1), std!(A => C, stage = 2),]
         );
         assert_eq!(
             first(builder.cache.all::<compile::Assemble>()),
@@ -533,10 +537,7 @@ mod dist {
         );
         assert_eq!(
             first(builder.cache.all::<compile::Rustc>()),
-            &[
-                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
-            ]
+            &[rustc!(A => A, stage = 0), rustc!(A => A, stage = 1),]
         );
     }
 
diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs
index 97f0bfdc484..be5c9bb0788 100644
--- a/src/bootstrap/cache.rs
+++ b/src/bootstrap/cache.rs
@@ -4,13 +4,12 @@ use std::cell::RefCell;
 use std::cmp::{Ord, Ordering, PartialOrd};
 use std::collections::HashMap;
 use std::convert::AsRef;
-use std::ffi::OsStr;
 use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::Deref;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
 use std::sync::Mutex;
 
 // FIXME: replace with std::lazy after it gets stabilized and reaches beta
@@ -20,15 +19,9 @@ use crate::builder::Step;
 
 pub struct Interned<T>(usize, PhantomData<*const T>);
 
-impl Default for Interned<String> {
+impl<T: Internable + Default> Default for Interned<T> {
     fn default() -> Self {
-        INTERNER.intern_string(String::default())
-    }
-}
-
-impl Default for Interned<PathBuf> {
-    fn default() -> Self {
-        INTERNER.intern_path(PathBuf::default())
+        T::default().intern()
     }
 }
 
@@ -77,87 +70,48 @@ impl fmt::Display for Interned<String> {
     }
 }
 
-impl fmt::Debug for Interned<String> {
+impl<T, U: ?Sized + fmt::Debug> fmt::Debug for Interned<T>
+where
+    Self: Deref<Target = U>,
+{
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s: &str = &*self;
-        f.write_fmt(format_args!("{:?}", s))
-    }
-}
-impl fmt::Debug for Interned<PathBuf> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let s: &Path = &*self;
+        let s: &U = &*self;
         f.write_fmt(format_args!("{:?}", s))
     }
 }
 
-impl Hash for Interned<String> {
+impl<T: Internable + Hash> Hash for Interned<T> {
     fn hash<H: Hasher>(&self, state: &mut H) {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).hash(state)
     }
 }
 
-impl Hash for Interned<PathBuf> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let l = INTERNER.paths.lock().unwrap();
-        l.get(*self).hash(state)
+impl<T: Internable + Deref> Deref for Interned<T> {
+    type Target = T::Target;
+    fn deref(&self) -> &'static Self::Target {
+        let l = T::intern_cache().lock().unwrap();
+        unsafe { mem::transmute::<&Self::Target, &'static Self::Target>(l.get(*self)) }
     }
 }
 
-impl Deref for Interned<String> {
-    type Target = str;
-    fn deref(&self) -> &'static str {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
+impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Interned<T> {
+    fn as_ref(&self) -> &'static U {
+        let l = T::intern_cache().lock().unwrap();
+        unsafe { mem::transmute::<&U, &'static U>(l.get(*self).as_ref()) }
     }
 }
 
-impl Deref for Interned<PathBuf> {
-    type Target = Path;
-    fn deref(&self) -> &'static Path {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
-    }
-}
-
-impl AsRef<Path> for Interned<PathBuf> {
-    fn as_ref(&self) -> &'static Path {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
-    }
-}
-
-impl AsRef<Path> for Interned<String> {
-    fn as_ref(&self) -> &'static Path {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
-    }
-}
-
-impl AsRef<OsStr> for Interned<PathBuf> {
-    fn as_ref(&self) -> &'static OsStr {
-        let l = INTERNER.paths.lock().unwrap();
-        unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
-    }
-}
-
-impl AsRef<OsStr> for Interned<String> {
-    fn as_ref(&self) -> &'static OsStr {
-        let l = INTERNER.strs.lock().unwrap();
-        unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
-    }
-}
-
-impl PartialOrd<Interned<String>> for Interned<String> {
+impl<T: Internable + PartialOrd> PartialOrd for Interned<T> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).partial_cmp(l.get(*other))
     }
 }
 
-impl Ord for Interned<String> {
+impl<T: Internable + Ord> Ord for Interned<T> {
     fn cmp(&self, other: &Self) -> Ordering {
-        let l = INTERNER.strs.lock().unwrap();
+        let l = T::intern_cache().lock().unwrap();
         l.get(*self).cmp(l.get(*other))
     }
 }
@@ -208,6 +162,33 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
 pub struct Interner {
     strs: Mutex<TyIntern<String>>,
     paths: Mutex<TyIntern<PathBuf>>,
+    lists: Mutex<TyIntern<Vec<String>>>,
+}
+
+trait Internable: Clone + Eq + Hash + 'static {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
+
+    fn intern(self) -> Interned<Self> {
+        Self::intern_cache().lock().unwrap().intern(self)
+    }
+}
+
+impl Internable for String {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
+        &INTERNER.strs
+    }
+}
+
+impl Internable for PathBuf {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
+        &INTERNER.paths
+    }
+}
+
+impl Internable for Vec<String> {
+    fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
+        &INTERNER.lists
+    }
 }
 
 impl Interner {
@@ -221,6 +202,10 @@ impl Interner {
     pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
         self.paths.lock().unwrap().intern(s)
     }
+
+    pub fn intern_list(&self, v: Vec<String>) -> Interned<Vec<String>> {
+        self.lists.lock().unwrap().intern(v)
+    }
 }
 
 pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 731ebc41bb9..4985b054678 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -184,8 +184,8 @@ impl Step for Rustc {
             // the sysroot for the compiler to find. Otherwise, we're going to
             // fail when building crates that need to generate code (e.g., build
             // scripts and their dependencies).
-            builder.ensure(crate::compile::Std { target: compiler.host, compiler });
-            builder.ensure(crate::compile::Std { target, compiler });
+            builder.ensure(crate::compile::Std::new(compiler, compiler.host));
+            builder.ensure(crate::compile::Std::new(compiler, target));
         } else {
             builder.ensure(Std { target });
         }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index b4807d1ab3a..c099fedc3a7 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -13,7 +13,7 @@ use std::fs;
 use std::io::prelude::*;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
-use std::process::{exit, Command, Stdio};
+use std::process::{Command, Stdio};
 use std::str;
 
 use serde::Deserialize;
@@ -29,10 +29,31 @@ use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_da
 use crate::LLVM_TOOLS;
 use crate::{CLang, Compiler, DependencyType, GitRepo, Mode};
 
-#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
     pub target: TargetSelection,
     pub compiler: Compiler,
+    /// Whether to build only a subset of crates in the standard library.
+    ///
+    /// This shouldn't be used from other steps; see the comment on [`Rustc`].
+    crates: Interned<Vec<String>>,
+}
+
+impl Std {
+    pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
+        Self { target, compiler, crates: Default::default() }
+    }
+}
+
+/// Return a `-p=x -p=y` string suitable for passing to a cargo invocation.
+fn build_crates_in_set(run: &RunConfig<'_>) -> Interned<Vec<String>> {
+    let mut crates = Vec::new();
+    for krate in &run.paths {
+        let path = krate.assert_single_path();
+        let crate_name = run.builder.crate_paths[&path.path];
+        crates.push(format!("-p={crate_name}"));
+    }
+    INTERNER.intern_list(crates)
 }
 
 impl Step for Std {
@@ -43,15 +64,22 @@ impl Step for Std {
         // When downloading stage1, the standard library has already been copied to the sysroot, so
         // there's no need to rebuild it.
         let builder = run.builder;
-        run.all_krates("test")
+        run.crate_or_deps("test")
             .path("library")
             .lazy_default_condition(Box::new(|| !builder.download_rustc()))
     }
 
     fn make_run(run: RunConfig<'_>) {
+        // Normally, people will pass *just* library if they pass it.
+        // But it's possible (although strange) to pass something like `library std core`.
+        // Build all crates anyway, as if they hadn't passed the other args.
+        let has_library =
+            run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
+        let crates = if has_library { Default::default() } else { build_crates_in_set(&run) };
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
+            crates,
         });
     }
 
@@ -76,7 +104,7 @@ impl Step for Std {
             || builder.config.keep_stage_std.contains(&compiler.stage)
         {
             builder.info("Warning: Using a potentially old libstd. This may not behave well.");
-            builder.ensure(StdLink { compiler, target_compiler: compiler, target });
+            builder.ensure(StdLink::from_std(self, compiler));
             return;
         }
 
@@ -86,7 +114,7 @@ impl Step for Std {
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         if compiler_to_use != compiler {
-            builder.ensure(Std { compiler: compiler_to_use, target });
+            builder.ensure(Std::new(compiler_to_use, target));
             builder.info(&format!("Uplifting stage1 std ({} -> {})", compiler_to_use.host, target));
 
             // Even if we're not building std this stage, the new sysroot must
@@ -94,11 +122,7 @@ impl Step for Std {
             copy_third_party_objects(builder, &compiler, target);
             copy_self_contained_objects(builder, &compiler, target);
 
-            builder.ensure(StdLink {
-                compiler: compiler_to_use,
-                target_compiler: compiler,
-                target,
-            });
+            builder.ensure(StdLink::from_std(self, compiler_to_use));
             return;
         }
 
@@ -115,17 +139,16 @@ impl Step for Std {
         run_cargo(
             builder,
             cargo,
-            vec![],
+            self.crates.to_vec(),
             &libstd_stamp(builder, compiler, target),
             target_deps,
             false,
         );
 
-        builder.ensure(StdLink {
-            compiler: builder.compiler(compiler.stage, builder.config.build),
-            target_compiler: compiler,
-            target,
-        });
+        builder.ensure(StdLink::from_std(
+            self,
+            builder.compiler(compiler.stage, builder.config.build),
+        ));
     }
 }
 
@@ -366,6 +389,19 @@ struct StdLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
     pub target: TargetSelection,
+    /// Not actually used; only present to make sure the cache invalidation is correct.
+    crates: Interned<Vec<String>>,
+}
+
+impl StdLink {
+    fn from_std(std: Std, host_compiler: Compiler) -> Self {
+        Self {
+            compiler: host_compiler,
+            target_compiler: std.compiler,
+            target: std.target,
+            crates: std.crates,
+        }
+    }
 }
 
 impl Step for StdLink {
@@ -524,6 +560,18 @@ impl Step for StartupObjects {
 pub struct Rustc {
     pub target: TargetSelection,
     pub compiler: Compiler,
+    /// Whether to build a subset of crates, rather than the whole compiler.
+    ///
+    /// This should only be requested by the user, not used within rustbuild itself.
+    /// Using it within rustbuild can lead to confusing situation where lints are replayed
+    /// in two different steps.
+    crates: Interned<Vec<String>>,
+}
+
+impl Rustc {
+    pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
+        Self { target, compiler, crates: Default::default() }
+    }
 }
 
 impl Step for Rustc {
@@ -532,13 +580,22 @@ impl Step for Rustc {
     const DEFAULT: bool = false;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.never()
+        let mut crates = run.builder.in_tree_crates("rustc-main", None);
+        for (i, krate) in crates.iter().enumerate() {
+            if krate.name == "rustc-main" {
+                crates.swap_remove(i);
+                break;
+            }
+        }
+        run.crates(crates)
     }
 
     fn make_run(run: RunConfig<'_>) {
+        let crates = build_crates_in_set(&run);
         run.builder.ensure(Rustc {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
             target: run.target,
+            crates,
         });
     }
 
@@ -560,33 +617,29 @@ impl Step for Rustc {
             return;
         }
 
-        builder.ensure(Std { compiler, target });
+        builder.ensure(Std::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
             builder.info("Warning: Using a potentially old librustc. This may not behave well.");
             builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
-            builder.ensure(RustcLink { compiler, target_compiler: compiler, target });
+            builder.ensure(RustcLink::from_rustc(self, compiler));
             return;
         }
 
         let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
         if compiler_to_use != compiler {
-            builder.ensure(Rustc { compiler: compiler_to_use, target });
+            builder.ensure(Rustc::new(compiler_to_use, target));
             builder
                 .info(&format!("Uplifting stage1 rustc ({} -> {})", builder.config.build, target));
-            builder.ensure(RustcLink {
-                compiler: compiler_to_use,
-                target_compiler: compiler,
-                target,
-            });
+            builder.ensure(RustcLink::from_rustc(self, compiler_to_use));
             return;
         }
 
         // Ensure that build scripts and proc macros have a std / libproc_macro to link against.
-        builder.ensure(Std {
-            compiler: builder.compiler(self.compiler.stage, builder.config.build),
-            target: builder.config.build,
-        });
+        builder.ensure(Std::new(
+            builder.compiler(self.compiler.stage, builder.config.build),
+            builder.config.build,
+        ));
 
         let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
         rustc_cargo(builder, &mut cargo, target);
@@ -633,17 +686,16 @@ impl Step for Rustc {
         run_cargo(
             builder,
             cargo,
-            vec![],
+            self.crates.to_vec(),
             &librustc_stamp(builder, compiler, target),
             vec![],
             false,
         );
 
-        builder.ensure(RustcLink {
-            compiler: builder.compiler(compiler.stage, builder.config.build),
-            target_compiler: compiler,
-            target,
-        });
+        builder.ensure(RustcLink::from_rustc(
+            self,
+            builder.compiler(compiler.stage, builder.config.build),
+        ));
     }
 }
 
@@ -758,6 +810,19 @@ struct RustcLink {
     pub compiler: Compiler,
     pub target_compiler: Compiler,
     pub target: TargetSelection,
+    /// Not actually used; only present to make sure the cache invalidation is correct.
+    crates: Interned<Vec<String>>,
+}
+
+impl RustcLink {
+    fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self {
+        Self {
+            compiler: host_compiler,
+            target_compiler: rustc.compiler,
+            target: rustc.target,
+            crates: rustc.crates,
+        }
+    }
 }
 
 impl Step for RustcLink {
@@ -821,7 +886,7 @@ impl Step for CodegenBackend {
         let target = self.target;
         let backend = self.backend;
 
-        builder.ensure(Rustc { compiler, target });
+        builder.ensure(Rustc::new(compiler, target));
 
         if builder.config.keep_stage.contains(&compiler.stage) {
             builder.info(
@@ -1103,7 +1168,7 @@ impl Step for Assemble {
         // link to these. (FIXME: Is that correct? It seems to be correct most
         // of the time but I think we do link to these for stage2/bin compilers
         // when not performing a full bootstrap).
-        builder.ensure(Rustc { compiler: build_compiler, target: target_compiler.host });
+        builder.ensure(Rustc::new(build_compiler, target_compiler.host));
 
         for &backend in builder.config.rust_codegen_backends.iter() {
             if backend == "llvm" {
@@ -1328,7 +1393,7 @@ pub fn run_cargo(
     });
 
     if !ok {
-        exit(1);
+        crate::detail_exit(1);
     }
 
     // Ok now we need to actually find all the files listed in `toplevel`. We've
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 2fc18c9e79e..39d86ccbdbf 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -11,7 +11,7 @@ use std::ffi::OsStr;
 use std::fmt;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process::{exit, Command};
+use std::process::Command;
 use std::str::FromStr;
 
 use crate::builder::{Builder, TaskPath};
@@ -805,8 +805,6 @@ impl Config {
         let get_toml = |_| TomlConfig::default();
         #[cfg(not(test))]
         let get_toml = |file: &Path| {
-            use std::process;
-
             let contents =
                 t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
             // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
@@ -817,7 +815,7 @@ impl Config {
                 Ok(table) => table,
                 Err(err) => {
                     eprintln!("failed to parse TOML configuration '{}': {}", file.display(), err);
-                    process::exit(2);
+                    crate::detail_exit(2);
                 }
             }
         };
@@ -1128,11 +1126,7 @@ impl Config {
             config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config);
             config.rust_profile_use = flags.rust_profile_use.or(rust.profile_use);
             config.rust_profile_generate = flags.rust_profile_generate.or(rust.profile_generate);
-            config.download_rustc_commit = download_ci_rustc_commit(
-                &config.stage0_metadata,
-                rust.download_rustc,
-                config.verbose > 0,
-            );
+            config.download_rustc_commit = download_ci_rustc_commit(&config, rust.download_rustc);
         } else {
             config.rust_profile_use = flags.rust_profile_use;
             config.rust_profile_generate = flags.rust_profile_generate;
@@ -1304,6 +1298,15 @@ impl Config {
         config
     }
 
+    /// A git invocation which runs inside the source directory.
+    ///
+    /// Use this rather than `Command::new("git")` in order to support out-of-tree builds.
+    pub(crate) fn git(&self) -> Command {
+        let mut git = Command::new("git");
+        git.current_dir(&self.src);
+        git
+    }
+
     /// Try to find the relative path of `bindir`, otherwise return it in full.
     pub fn bindir_relative(&self) -> &Path {
         let bindir = &self.bindir;
@@ -1453,9 +1456,8 @@ fn threads_from_config(v: u32) -> u32 {
 
 /// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
 fn download_ci_rustc_commit(
-    stage0_metadata: &Stage0Metadata,
+    config: &Config,
     download_rustc: Option<StringOrBool>,
-    verbose: bool,
 ) -> Option<String> {
     // If `download-rustc` is not set, default to rebuilding.
     let if_unchanged = match download_rustc {
@@ -1468,7 +1470,7 @@ fn download_ci_rustc_commit(
     };
 
     // Handle running from a directory other than the top level
-    let top_level = output(Command::new("git").args(&["rev-parse", "--show-toplevel"]));
+    let top_level = output(config.git().args(&["rev-parse", "--show-toplevel"]));
     let top_level = top_level.trim_end();
     let compiler = format!("{top_level}/compiler/");
     let library = format!("{top_level}/library/");
@@ -1476,9 +1478,10 @@ fn download_ci_rustc_commit(
     // Look for a version to compare to based on the current commit.
     // Only commits merged by bors will have CI artifacts.
     let merge_base = output(
-        Command::new("git")
+        config
+            .git()
             .arg("rev-list")
-            .arg(format!("--author={}", stage0_metadata.config.git_merge_commit_email))
+            .arg(format!("--author={}", config.stage0_metadata.config.git_merge_commit_email))
             .args(&["-n1", "--first-parent", "HEAD"]),
     );
     let commit = merge_base.trim_end();
@@ -1487,17 +1490,18 @@ fn download_ci_rustc_commit(
         println!("help: maybe your repository history is too shallow?");
         println!("help: consider disabling `download-rustc`");
         println!("help: or fetch enough history to include one upstream commit");
-        exit(1);
+        crate::detail_exit(1);
     }
 
     // Warn if there were changes to the compiler or standard library since the ancestor commit.
-    let has_changes = !t!(Command::new("git")
+    let has_changes = !t!(config
+        .git()
         .args(&["diff-index", "--quiet", &commit, "--", &compiler, &library])
         .status())
     .success();
     if has_changes {
         if if_unchanged {
-            if verbose {
+            if config.verbose > 0 {
                 println!(
                     "warning: saw changes to compiler/ or library/ since {commit}; \
                           ignoring `download-rustc`"
@@ -1560,7 +1564,7 @@ fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
         builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
         builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustdoc"));
         let lib_dir = bin_root.join("lib");
-        for lib in t!(fs::read_dir(lib_dir)) {
+        for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
             let lib = t!(lib);
             if lib.path().extension() == Some(OsStr::new("so")) {
                 builder.fix_bin_or_dylib(&lib.path());
@@ -1636,6 +1640,7 @@ fn download_component(
         }
         Some(sha256)
     } else if tarball.exists() {
+        builder.unpack(&tarball, &bin_root, prefix);
         return;
     } else {
         None
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index 2fc036082cb..6b139decb55 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -31,11 +31,10 @@ def v(*args):
     options.append(Option(*args, value=True))
 
 
-o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code (use `--disable-optimize` for that)")
+o("debug", "rust.debug", "enables debugging environment; does not affect optimization of bootstrapped code")
 o("docs", "build.docs", "build standard library documentation")
 o("compiler-docs", "build.compiler-docs", "build compiler documentation")
 o("optimize-tests", "rust.optimize-tests", "build tests with optimizations")
-o("parallel-compiler", "rust.parallel-compiler", "build a multi-threaded rustc")
 o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests")
 o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds")
 o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds")
@@ -70,7 +69,6 @@ v("llvm-libunwind", "rust.llvm-libunwind", "use LLVM libunwind")
 
 # Optimization and debugging options. These may be overridden by the release
 # channel, etc.
-o("optimize", "rust.optimize", "build optimized rust code")
 o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
 o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
 o("llvm-plugins", "llvm.plugins", "build LLVM with plugin interface")
@@ -161,7 +159,7 @@ v("default-linker", "rust.default-linker", "the default linker")
 # Many of these are saved below during the "writing configuration" step
 # (others are conditionally saved).
 o("manage-submodules", "build.submodules", "let the build manage the git submodules")
-o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two")
+o("full-bootstrap", "build.full-bootstrap", "build three compilers instead of two (not recommended except for testing reproducible builds)")
 o("extended", "build.extended", "build an extended rust tool set")
 
 v("tools", None, "List of extended tools will be installed")
@@ -493,4 +491,3 @@ with bootstrap.output('Makefile') as f:
 
 p("")
 p("run `python {}/x.py --help`".format(rust_dir))
-p("")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 74ec9cab5ca..4aadc3943c9 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -557,7 +557,7 @@ impl Step for Std {
             return None;
         }
 
-        builder.ensure(compile::Std { compiler, target });
+        builder.ensure(compile::Std::new(compiler, target));
 
         let mut tarball = Tarball::new(builder, "rust-std", &target.triple);
         tarball.include_target_in_component_name(true);
@@ -603,7 +603,7 @@ impl Step for RustcDev {
             return None;
         }
 
-        builder.ensure(compile::Rustc { compiler, target });
+        builder.ensure(compile::Rustc::new(compiler, target));
 
         let tarball = Tarball::new(builder, "rustc-dev", &target.triple);
 
@@ -666,7 +666,7 @@ impl Step for Analysis {
             return None;
         }
 
-        builder.ensure(compile::Std { compiler, target });
+        builder.ensure(compile::Std::new(compiler, target));
         let src = builder
             .stage_out(compiler, Mode::Std)
             .join(target.triple)
@@ -2025,6 +2025,8 @@ impl Step for RustDev {
         let mut tarball = Tarball::new(builder, "rust-dev", &target.triple);
         tarball.set_overlay(OverlayKind::LLVM);
 
+        builder.ensure(crate::native::Llvm { target });
+
         let src_bindir = builder.llvm_out(target).join("bin");
         // If updating this list, you likely want to change
         // src/bootstrap/download-ci-llvm-stamp as well, otherwise local users
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index be6655ddb61..5b961456076 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -534,7 +534,9 @@ impl Step for Rustc {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.krate("rustc-main").path("compiler").default_condition(builder.config.compiler_docs)
+        run.crate_or_deps("rustc-main")
+            .path("compiler")
+            .default_condition(builder.config.compiler_docs)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -567,7 +569,7 @@ impl Step for Rustc {
         // Build the standard library, so that proc-macros can use it.
         // (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.)
         let compiler = builder.compiler(stage, builder.config.build);
-        builder.ensure(compile::Std { compiler, target: builder.config.build });
+        builder.ensure(compile::Std::new(compiler, builder.config.build));
 
         builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
 
@@ -643,7 +645,7 @@ impl Step for Rustc {
 }
 
 macro_rules! tool_doc {
-    ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?] $(,)?) => {
+    ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?], in_tree = $in_tree:expr $(,)?) => {
         #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
         pub struct $tool {
             target: TargetSelection,
@@ -656,7 +658,7 @@ macro_rules! tool_doc {
 
             fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
                 let builder = run.builder;
-                run.krate($should_run).default_condition(builder.config.compiler_docs)
+                run.crate_or_deps($should_run).default_condition(builder.config.compiler_docs)
             }
 
             fn make_run(run: RunConfig<'_>) {
@@ -683,7 +685,7 @@ macro_rules! tool_doc {
                 // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed
                 // with strange errors, but only on a full bors test ...
                 let compiler = builder.compiler(stage, builder.config.build);
-                builder.ensure(compile::Rustc { compiler, target });
+                builder.ensure(compile::Rustc::new(compiler, target));
 
                 builder.info(
                     &format!(
@@ -699,6 +701,12 @@ macro_rules! tool_doc {
                 t!(fs::create_dir_all(&out_dir));
                 t!(symlink_dir_force(&builder.config, &out, &out_dir));
 
+                let source_type = if $in_tree == true {
+                    SourceType::InTree
+                } else {
+                    SourceType::Submodule
+                };
+
                 // Build cargo command.
                 let mut cargo = prepare_tool_cargo(
                     builder,
@@ -707,7 +715,7 @@ macro_rules! tool_doc {
                     target,
                     "doc",
                     $path,
-                    SourceType::InTree,
+                    source_type,
                     &[],
                 );
 
@@ -723,20 +731,38 @@ macro_rules! tool_doc {
                 cargo.rustdocflag("--show-type-layout");
                 cargo.rustdocflag("--generate-link-to-definition");
                 cargo.rustdocflag("-Zunstable-options");
-                builder.run(&mut cargo.into());
+                if $in_tree == true {
+                    builder.run(&mut cargo.into());
+                } else {
+                    // Allow out-of-tree docs to fail (since the tool might be in a broken state).
+                    if !builder.try_run(&mut cargo.into()) {
+                        builder.info(&format!(
+                            "WARNING: tool {} failed to document; ignoring failure because it is an out-of-tree tool",
+                            stringify!($tool).to_lowercase(),
+                        ));
+                    }
+                }
             }
         }
     }
 }
 
-tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", ["rustdoc", "rustdoc-json-types"]);
+tool_doc!(
+    Rustdoc,
+    "rustdoc-tool",
+    "src/tools/rustdoc",
+    ["rustdoc", "rustdoc-json-types"],
+    in_tree = true
+);
 tool_doc!(
     Rustfmt,
     "rustfmt-nightly",
     "src/tools/rustfmt",
     ["rustfmt-nightly", "rustfmt-config_proc_macro"],
+    in_tree = true
 );
-tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]);
+tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"], in_tree = true);
+tool_doc!(Miri, "miri", "src/tools/miri", ["miri"], in_tree = false);
 
 #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct ErrorIndex {
@@ -866,7 +892,7 @@ impl Step for RustcBook {
         let rustc = builder.rustc(self.compiler);
         // The tool runs `rustc` for extracting output examples, so it needs a
         // functional sysroot.
-        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+        builder.ensure(compile::Std::new(self.compiler, self.target));
         let mut cmd = builder.tool_cmd(Tool::LintDocs);
         cmd.arg("--src");
         cmd.arg(builder.src.join("compiler"));
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 7ebae55efc1..eec19ab4fc9 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -4,7 +4,6 @@
 //! has various flags to configure how it's run.
 
 use std::path::PathBuf;
-use std::process;
 
 use getopts::Options;
 
@@ -261,7 +260,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                 // subcommand.
                 println!("{}\n", subcommand_help);
                 let exit_code = if args.is_empty() { 0 } else { 1 };
-                process::exit(exit_code);
+                crate::detail_exit(exit_code);
             }
         };
 
@@ -347,7 +346,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
             } else if verbose {
                 panic!("No paths available for subcommand `{}`", subcommand.as_str());
             }
-            process::exit(exit_code);
+            crate::detail_exit(exit_code);
         };
 
         // Done specifying what options are possible, so do the getopts parsing
@@ -379,7 +378,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                 "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
                  You may need to move some options to after the subcommand.\n"
             );
-            process::exit(1);
+            crate::detail_exit(1);
         }
         // Extra help text for some commands
         match subcommand {
@@ -600,7 +599,7 @@ Arguments:
                         eprintln!("error: {}", err);
                         eprintln!("help: the available profiles are:");
                         eprint!("{}", Profile::all_for_help("- "));
-                        std::process::exit(1);
+                        crate::detail_exit(1);
                     })
                 } else {
                     t!(crate::setup::interactive_path())
@@ -614,7 +613,7 @@ Arguments:
                 || matches.opt_str("keep-stage-std").is_some()
             {
                 eprintln!("--keep-stage not yet supported for x.py check");
-                process::exit(1);
+                crate::detail_exit(1);
             }
         }
 
@@ -805,7 +804,7 @@ fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
         Some("warn") => Some(false),
         Some(value) => {
             eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,);
-            process::exit(1);
+            crate::detail_exit(1);
         }
         None => None,
     }
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 60a53c28686..37322670e65 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -32,7 +32,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F
                         code, run `./x.py fmt` instead.",
                 cmd_debug,
             );
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
     }
 }
@@ -72,7 +72,9 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         Err(_) => false,
     };
     if git_available {
-        let in_working_tree = match Command::new("git")
+        let in_working_tree = match build
+            .config
+            .git()
             .arg("rev-parse")
             .arg("--is-inside-work-tree")
             .stdout(Stdio::null())
@@ -84,10 +86,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
         };
         if in_working_tree {
             let untracked_paths_output = output(
-                Command::new("git")
-                    .arg("status")
-                    .arg("--porcelain")
-                    .arg("--untracked-files=normal"),
+                build.config.git().arg("status").arg("--porcelain").arg("--untracked-files=normal"),
             );
             let untracked_paths = untracked_paths_output
                 .lines()
@@ -114,7 +113,7 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
 
     let rustfmt_path = build.initial_rustfmt().unwrap_or_else(|| {
         eprintln!("./x.py fmt is not supported on this channel");
-        std::process::exit(1);
+        crate::detail_exit(1);
     });
     assert!(rustfmt_path.exists(), "{}", rustfmt_path.display());
     let src = build.src.clone();
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 40ff0381c8b..c1190c9192d 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -109,7 +109,7 @@ use std::env;
 use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
-use std::process::{self, Command};
+use std::process::Command;
 use std::str;
 
 use filetime::FileTime;
@@ -118,8 +118,7 @@ use once_cell::sync::OnceCell;
 use crate::builder::Kind;
 use crate::config::{LlvmLibunwind, TargetSelection};
 use crate::util::{
-    check_run, exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed,
-    CiEnv,
+    check_run, exe, libdir, mtime, output, run, run_suppressed, try_run, try_run_suppressed, CiEnv,
 };
 
 mod builder;
@@ -644,7 +643,8 @@ impl Build {
             return;
         }
         let output = output(
-            Command::new("git")
+            self.config
+                .git()
                 .args(&["config", "--file"])
                 .arg(&self.config.src.join(".gitmodules"))
                 .args(&["--get-regexp", "path"]),
@@ -712,7 +712,7 @@ impl Build {
             for failure in failures.iter() {
                 eprintln!("  - {}\n", failure);
             }
-            process::exit(1);
+            detail_exit(1);
         }
 
         #[cfg(feature = "build-metrics")]
@@ -1281,12 +1281,12 @@ impl Build {
         // That's our beta number!
         // (Note that we use a `..` range, not the `...` symmetric difference.)
         let count = output(
-            Command::new("git")
+            self.config
+                .git()
                 .arg("rev-list")
                 .arg("--count")
                 .arg("--merges")
-                .arg("refs/remotes/origin/master..HEAD")
-                .current_dir(&self.src),
+                .arg("refs/remotes/origin/master..HEAD"),
         );
         let n = count.trim().parse().unwrap();
         self.prerelease_version.set(Some(n));
@@ -1618,7 +1618,7 @@ Alternatively, set `download-ci-llvm = true` in that `[llvm]` section
 to download LLVM rather than building it.
 "
                 );
-                std::process::exit(1);
+                detail_exit(1);
             }
         }
 
@@ -1647,6 +1647,20 @@ fn chmod(path: &Path, perms: u32) {
 #[cfg(windows)]
 fn chmod(_path: &Path, _perms: u32) {}
 
+/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
+/// If the test is running and code is an error code, it will cause a panic.
+fn detail_exit(code: i32) -> ! {
+    // Successful exit
+    if code == 0 {
+        std::process::exit(0);
+    }
+    if cfg!(test) {
+        panic!("status code: {}", code);
+    } else {
+        std::panic::resume_unwind(Box::new(code));
+    }
+}
+
 impl Compiler {
     pub fn with_stage(mut self, stage: u32) -> Compiler {
         self.stage = stage;
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 8395be40f9b..01ba0169b20 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -118,7 +118,7 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
     if !config.llvm_from_ci {
         return;
     }
-    let mut rev_list = Command::new("git");
+    let mut rev_list = config.git();
     rev_list.args(&[
         PathBuf::from("rev-list"),
         format!("--author={}", builder.config.stage0_metadata.config.git_merge_commit_email).into(),
@@ -147,8 +147,8 @@ pub(crate) fn maybe_download_ci_llvm(builder: &Builder<'_>) {
     let key = format!("{}{}", llvm_sha, config.llvm_assertions);
     if program_out_of_date(&llvm_stamp, &key) && !config.dry_run {
         download_ci_llvm(builder, &llvm_sha);
-        for binary in ["llvm-config", "FileCheck"] {
-            builder.fix_bin_or_dylib(&llvm_root.join("bin").join(binary));
+        for entry in t!(fs::read_dir(llvm_root.join("bin"))) {
+            builder.fix_bin_or_dylib(&t!(entry).path());
         }
 
         // Update the timestamp of llvm-config to force rustc_llvm to be
@@ -429,13 +429,21 @@ impl Step for Llvm {
             //        should use llvm-tblgen from there, also should verify that it
             //        actually exists most of the time in normal installs of LLVM.
             let host_bin = builder.llvm_out(builder.config.build).join("bin");
-            cfg.define("CMAKE_CROSSCOMPILING", "True");
             cfg.define("LLVM_TABLEGEN", host_bin.join("llvm-tblgen").with_extension(EXE_EXTENSION));
+            // LLVM_NM is required for cross compiling using MSVC
             cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION));
             cfg.define(
                 "LLVM_CONFIG_PATH",
                 host_bin.join("llvm-config").with_extension(EXE_EXTENSION),
             );
+            if builder.config.llvm_clang {
+                let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin");
+                let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION);
+                if !builder.config.dry_run && !clang_tblgen.exists() {
+                    panic!("unable to find {}", clang_tblgen.display());
+                }
+                cfg.define("CLANG_TABLEGEN", clang_tblgen);
+            }
         }
 
         let llvm_version_suffix = if let Some(ref suffix) = builder.config.llvm_version_suffix {
@@ -487,16 +495,14 @@ impl Step for Llvm {
             let version = output(cmd.arg("--version"));
             let major = version.split('.').next().unwrap();
             let lib_name = match llvm_version_suffix {
-                Some(s) => format!("lib/libLLVM-{}{}.dylib", major, s),
-                None => format!("lib/libLLVM-{}.dylib", major),
+                Some(s) => format!("libLLVM-{}{}.dylib", major, s),
+                None => format!("libLLVM-{}.dylib", major),
             };
 
-            // The reason why we build the library path from llvm-config is because
-            // the output of llvm-config depends on its location in the file system.
-            // Make sure we create the symlink exactly where it's needed.
-            let llvm_base = build_llvm_config.parent().unwrap().parent().unwrap();
-            let lib_llvm = llvm_base.join(lib_name);
-            t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
+            let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
+            if !lib_llvm.exists() {
+                t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
+            }
         }
 
         t!(stamp.write());
@@ -547,6 +553,8 @@ fn configure_cmake(
     cfg.target(&target.triple).host(&builder.config.build.triple);
 
     if target != builder.config.build {
+        cfg.define("CMAKE_CROSSCOMPILING", "True");
+
         if target.contains("netbsd") {
             cfg.define("CMAKE_SYSTEM_NAME", "NetBSD");
         } else if target.contains("freebsd") {
@@ -564,6 +572,17 @@ fn configure_cmake(
         // Since, the LLVM itself makes rather limited use of version checks in
         // CMakeFiles (and then only in tests), and so far no issues have been
         // reported, the system version is currently left unset.
+
+        if target.contains("darwin") {
+            // Make sure that CMake does not build universal binaries on macOS.
+            // Explicitly specifiy the one single target architecture.
+            if target.starts_with("aarch64") {
+                // macOS uses a different name for building arm64
+                cfg.define("CMAKE_OSX_ARCHITECTURES", "arm64");
+            } else {
+                cfg.define("CMAKE_OSX_ARCHITECTURES", target.triple.split('-').next().unwrap());
+            }
+        }
     }
 
     let sanitize_cc = |cc: &Path| {
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 64c5dd7aea7..cae41286f08 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -104,7 +104,7 @@ You should install cmake, or set `download-ci-llvm = true` in the
 than building it.
 "
             );
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
     }
 
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 82f55440ce5..a5a39a5a3cf 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -94,7 +94,7 @@ pub fn setup(config: &Config, profile: Profile) {
             "note: this will use the configuration in {}",
             profile.include_path(&config.src).display()
         );
-        std::process::exit(1);
+        crate::detail_exit(1);
     }
 
     let settings = format!(
@@ -136,7 +136,7 @@ pub fn setup(config: &Config, profile: Profile) {
 
     println!();
 
-    t!(install_git_hook_maybe(&config.src));
+    t!(install_git_hook_maybe(&config));
 
     println!();
 
@@ -287,7 +287,7 @@ pub fn interactive_path() -> io::Result<Profile> {
         io::stdin().read_line(&mut input)?;
         if input.is_empty() {
             eprintln!("EOF on stdin, when expecting answer to question.  Giving up.");
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
         break match parse_with_abbrev(&input) {
             Ok(profile) => profile,
@@ -302,7 +302,7 @@ pub fn interactive_path() -> io::Result<Profile> {
 }
 
 // install a git hook to automatically run tidy --bless, if they want
-fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
+fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
     let mut input = String::new();
     println!(
         "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
@@ -328,13 +328,12 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
     };
 
     if should_install {
-        let src = src_path.join("src").join("etc").join("pre-push.sh");
-        let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map(
-            |output| {
+        let src = config.src.join("src").join("etc").join("pre-push.sh");
+        let git =
+            t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
                 assert!(output.status.success(), "failed to run `git`");
                 PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
-            }
-        ));
+            }));
         let dst = git.join("hooks").join("pre-push");
         match fs::hard_link(src, &dst) {
             Err(e) => eprintln!(
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 9958306b576..4c6b5ba0afc 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -225,7 +225,7 @@ impl Step for Cargotest {
     /// test` to ensure that we don't regress the test suites there.
     fn run(self, builder: &Builder<'_>) {
         let compiler = builder.compiler(self.stage, self.host);
-        builder.ensure(compile::Rustc { compiler, target: compiler.host });
+        builder.ensure(compile::Rustc::new(compiler, compiler.host));
         let cargo = builder.ensure(tool::Cargo { compiler, target: compiler.host });
 
         // Note that this is a short, cryptic, and not scoped directory name. This
@@ -603,7 +603,7 @@ impl Step for CompiletestTest {
 
         // We need `ToolStd` for the locally-built sysroot because
         // compiletest uses unstable features of the `test` crate.
-        builder.ensure(compile::Std { compiler, target: host });
+        builder.ensure(compile::Std::new(compiler, host));
         let cargo = tool::prepare_tool_cargo(
             builder,
             compiler,
@@ -673,7 +673,7 @@ impl Step for Clippy {
         }
 
         if !builder.config.cmd.bless() {
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
 
         let mut cargo = builder.cargo(compiler, Mode::ToolRustc, SourceType::InTree, host, "run");
@@ -896,7 +896,7 @@ impl Step for RustdocGUI {
         let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
         let npm = builder.config.npm.as_ref().expect("npm isn't available");
 
-        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+        builder.ensure(compile::Std::new(self.compiler, self.target));
 
         // The goal here is to check if the necessary packages are installed, and if not, we
         // panic.
@@ -1021,7 +1021,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy`
                     PATH = inferred_rustfmt_dir.display(),
                     CHAN = builder.config.channel,
                 );
-                std::process::exit(1);
+                crate::detail_exit(1);
             }
             crate::format::format(&builder, !builder.config.cmd.bless(), &[]);
         }
@@ -1251,7 +1251,7 @@ help: to test the compiler, use `--stage 1` instead
 help: to test the standard library, use `--stage 0 library/std` instead
 note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
             );
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
 
         let compiler = self.compiler;
@@ -1273,12 +1273,12 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         }
 
         if suite.ends_with("fulldeps") {
-            builder.ensure(compile::Rustc { compiler, target });
+            builder.ensure(compile::Rustc::new(compiler, target));
         }
 
-        builder.ensure(compile::Std { compiler, target });
+        builder.ensure(compile::Std::new(compiler, target));
         // ensure that `libproc_macro` is available on the host.
-        builder.ensure(compile::Std { compiler, target: compiler.host });
+        builder.ensure(compile::Std::new(compiler, compiler.host));
 
         // Also provide `rust_test_helpers` for the host.
         builder.ensure(native::TestHelpers { target: compiler.host });
@@ -1363,13 +1363,10 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         if let Some(ref npm) = builder.config.npm {
             cmd.arg("--npm").arg(npm);
         }
-
-        let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
-        if !is_rustdoc {
-            if builder.config.rust_optimize_tests {
-                flags.push("-O".to_string());
-            }
+        if builder.config.rust_optimize_tests {
+            cmd.arg("--optimize-tests");
         }
+        let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
         flags.push(builder.config.cmd.rustc_args().join(" "));
 
@@ -1646,7 +1643,7 @@ impl BookTest {
     fn run_ext_doc(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
 
-        builder.ensure(compile::Std { compiler, target: compiler.host });
+        builder.ensure(compile::Std::new(compiler, compiler.host));
 
         // mdbook just executes a binary named "rustdoc", so we need to update
         // PATH so that it points to our rustdoc.
@@ -1674,7 +1671,7 @@ impl BookTest {
     fn run_local_doc(self, builder: &Builder<'_>) {
         let compiler = self.compiler;
 
-        builder.ensure(compile::Std { compiler, target: compiler.host });
+        builder.ensure(compile::Std::new(compiler, compiler.host));
 
         // Do a breadth-first traversal of the `src/doc` directory and just run
         // tests for all files that end in `*.md`
@@ -1793,7 +1790,7 @@ impl Step for ErrorIndex {
         builder.run_quiet(&mut tool);
         // The tests themselves need to link to std, so make sure it is
         // available.
-        builder.ensure(compile::Std { compiler, target: compiler.host });
+        builder.ensure(compile::Std::new(compiler, compiler.host));
         markdown_test(builder, compiler, &output);
     }
 }
@@ -1870,7 +1867,7 @@ impl Step for CrateLibrustc {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.krate("rustc-main")
+        run.crate_or_deps("rustc-main")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1912,7 +1909,7 @@ impl Step for Crate {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.krate("test")
+        run.crate_or_deps("test")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1943,7 +1940,7 @@ impl Step for Crate {
         let mode = self.mode;
         let test_kind = self.test_kind;
 
-        builder.ensure(compile::Std { compiler, target });
+        builder.ensure(compile::Std::new(compiler, target));
         builder.ensure(RemoteCopyLibs { compiler, target });
 
         // If we're not doing a full bootstrap but we're testing a stage2
@@ -2065,7 +2062,7 @@ impl Step for CrateRustdoc {
             // isn't really necessary.
             builder.compiler_for(builder.top_stage, target, target)
         };
-        builder.ensure(compile::Rustc { compiler, target });
+        builder.ensure(compile::Rustc::new(compiler, target));
 
         let mut cargo = tool::prepare_tool_cargo(
             builder,
@@ -2180,7 +2177,7 @@ impl Step for CrateRustdocJsonTypes {
         // `compiler`, then it would cause rustdoc to be built *again*, which
         // isn't really necessary.
         let compiler = builder.compiler_for(builder.top_stage, target, target);
-        builder.ensure(compile::Rustc { compiler, target });
+        builder.ensure(compile::Rustc::new(compiler, target));
 
         let mut cargo = tool::prepare_tool_cargo(
             builder,
@@ -2248,7 +2245,7 @@ impl Step for RemoteCopyLibs {
             return;
         }
 
-        builder.ensure(compile::Std { compiler, target });
+        builder.ensure(compile::Std::new(compiler, target));
 
         builder.info(&format!("REMOTE copy libs to emulator ({})", target));
 
@@ -2418,7 +2415,7 @@ impl Step for TierCheck {
 
     /// Tests the Platform Support page in the rustc book.
     fn run(self, builder: &Builder<'_>) {
-        builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host });
+        builder.ensure(compile::Std::new(self.compiler, self.compiler.host));
         let mut cargo = tool::prepare_tool_cargo(
             builder,
             self.compiler,
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 5be6841e988..f659ccbe250 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -2,7 +2,7 @@ use std::collections::HashSet;
 use std::env;
 use std::fs;
 use std::path::{Path, PathBuf};
-use std::process::{exit, Command};
+use std::process::Command;
 
 use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
 use crate::channel::GitInfo;
@@ -51,10 +51,10 @@ impl Step for ToolBuild {
 
         match self.mode {
             Mode::ToolRustc => {
-                builder.ensure(compile::Std { compiler, target: compiler.host });
-                builder.ensure(compile::Rustc { compiler, target });
+                builder.ensure(compile::Std::new(compiler, compiler.host));
+                builder.ensure(compile::Rustc::new(compiler, target));
             }
-            Mode::ToolStd => builder.ensure(compile::Std { compiler, target }),
+            Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)),
             Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
             _ => panic!("unexpected Mode for tool build"),
         }
@@ -204,7 +204,7 @@ impl Step for ToolBuild {
 
         if !is_expected {
             if !is_optional_tool {
-                exit(1);
+                crate::detail_exit(1);
             } else {
                 None
             }
@@ -367,7 +367,7 @@ bootstrap_tool!(
     Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
-    RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
+    RustInstaller, "src/tools/rust-installer", "rust-installer", is_external_tool = true;
     RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
     LintDocs, "src/tools/lint-docs", "lint-docs";
@@ -512,8 +512,8 @@ impl Step for Rustdoc {
         // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually
         // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build
         // it.
-        builder.ensure(compile::Std { compiler: build_compiler, target: target_compiler.host });
-        builder.ensure(compile::Rustc { compiler: build_compiler, target: target_compiler.host });
+        builder.ensure(compile::Std::new(build_compiler, target_compiler.host));
+        builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host));
         // NOTE: this implies that `download-rustc` is pretty useless when compiling with the stage0
         // compiler, since you do just as much work.
         if !builder.config.dry_run && builder.download_rustc() && build_compiler.stage == 0 {
diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs
index 3ee6a42d987..2cfeae7dc78 100644
--- a/src/bootstrap/toolstate.rs
+++ b/src/bootstrap/toolstate.rs
@@ -93,7 +93,7 @@ fn print_error(tool: &str, submodule: &str) {
     eprintln!("If you do NOT intend to update '{}', please ensure you did not accidentally", tool);
     eprintln!("change the submodule at '{}'. You may ask your reviewer for the", submodule);
     eprintln!("proper steps.");
-    std::process::exit(3);
+    crate::detail_exit(3);
 }
 
 fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
@@ -108,7 +108,7 @@ fn check_changed_files(toolstates: &HashMap<Box<str>, ToolState>) {
         Ok(o) => o,
         Err(e) => {
             eprintln!("Failed to get changed files: {:?}", e);
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
     };
 
@@ -179,7 +179,7 @@ impl Step for ToolStateCheck {
         }
 
         if did_error {
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
 
         check_changed_files(&toolstates);
@@ -225,7 +225,7 @@ impl Step for ToolStateCheck {
         }
 
         if did_error {
-            std::process::exit(1);
+            crate::detail_exit(1);
         }
 
         if builder.config.channel == "nightly" && env::var_os("TOOLSTATE_PUBLISH").is_some() {
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index 4b2b058a780..b627e503789 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -22,6 +22,7 @@ use crate::config::{Config, TargetSelection};
 ///
 /// This is currently used judiciously throughout the build system rather than
 /// using a `Result` with `try!`, but this may change one day...
+#[macro_export]
 macro_rules! t {
     ($e:expr) => {
         match $e {
@@ -37,7 +38,7 @@ macro_rules! t {
         }
     };
 }
-pub(crate) use t;
+pub use t;
 
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
@@ -335,7 +336,7 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
 
 pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) {
     if !try_run(cmd, print_cmd_on_fail) {
-        std::process::exit(1);
+        crate::detail_exit(1);
     }
 }
 
@@ -374,7 +375,7 @@ pub fn check_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool {
 
 pub fn run_suppressed(cmd: &mut Command) {
     if !try_run_suppressed(cmd) {
-        std::process::exit(1);
+        crate::detail_exit(1);
     }
 }
 
@@ -464,7 +465,7 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool {
 
 fn fail(s: &str) -> ! {
     eprintln!("\n\n{}\n\n", s);
-    std::process::exit(1);
+    crate::detail_exit(1);
 }
 
 /// Copied from `std::path::absolute` until it stabilizes.
diff --git a/src/ci/docker/host-x86_64/dist-various-2/shared.sh b/src/ci/docker/host-x86_64/dist-various-2/shared.sh
index 267d8b79cc2..291f26bdaeb 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/shared.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/shared.sh
@@ -33,15 +33,3 @@ function retry {
     }
   done
 }
-
-# Copied from ../../init_repo.sh
-function fetch_github_commit_archive {
-    local module=$1
-    local cached="download-${module//\//-}.tar.gz"
-    retry sh -c "rm -f $cached && \
-        curl -f -sSL -o $cached $2"
-    mkdir $module
-    touch "$module/.git"
-    tar -C $module --strip-components=1 -xf $cached
-    rm $cached
-}
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
index 7651947c525..13d440423b2 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile
@@ -35,7 +35,6 @@ ENV RUST_CONFIGURE_ARGS \
       --build=x86_64-unknown-linux-gnu \
       --enable-debug \
       --enable-lld \
-      --enable-optimize \
       --set llvm.use-linker=lld \
       --set target.x86_64-unknown-linux-gnu.linker=clang \
       --set target.x86_64-unknown-linux-gnu.cc=clang \
diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh
index 65e15950559..3e5dc4af04a 100644
--- a/src/ci/docker/scripts/musl.sh
+++ b/src/ci/docker/scripts/musl.sh
@@ -33,7 +33,7 @@ if [ ! -d $MUSL ]; then
 fi
 
 cd $MUSL
-./configure --enable-optimize --enable-debug --disable-shared --prefix=/musl-$TAG "$@"
+./configure --enable-debug --disable-shared --prefix=/musl-$TAG "$@"
 if [ "$TAG" = "i586" -o "$TAG" = "i686" ]; then
   hide_output make -j$(nproc) AR=ar RANLIB=ranlib
 else
diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh
deleted file mode 100755
index e8c1e2b0f59..00000000000
--- a/src/ci/init_repo.sh
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env bash
-
-set -o errexit
-set -o pipefail
-set -o nounset
-
-ci_dir=$(cd $(dirname $0) && pwd)
-. "$ci_dir/shared.sh"
-
-REPO_DIR="$1"
-CACHE_DIR="$2"
-
-cache_src_dir="$CACHE_DIR/src"
-
-if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then
-    echo "Error: $REPO_DIR does not exist or is not a git repo"
-    exit 1
-fi
-cd $REPO_DIR
-if [ ! -d "$CACHE_DIR" ]; then
-    echo "Error: $CACHE_DIR does not exist or is not an absolute path"
-    exit 1
-fi
-
-rm -rf "$CACHE_DIR"
-mkdir "$CACHE_DIR"
-
-# On the beta channel we'll be automatically calculating the prerelease version
-# via the git history, so unshallow our shallow clone from CI.
-if [ "$(releaseChannel)" = "beta" ]; then
-  git fetch origin --unshallow beta master
-fi
-
-# Duplicated in docker/dist-various-2/shared.sh
-function fetch_github_commit_archive {
-    local module=$1
-    local cached="download-${module//\//-}.tar.gz"
-    retry sh -c "rm -f $cached && \
-        curl -f -sSL -o $cached $2"
-    mkdir $module
-    touch "$module/.git"
-    # On Windows, the default behavior is to emulate symlinks by copying
-    # files. However, that ends up being order-dependent while extracting,
-    # which can cause a failure if the symlink comes first. This env var
-    # causes tar to use real symlinks instead, which are allowed to dangle.
-    export MSYS=winsymlinks:nativestrict
-    tar -C $module --strip-components=1 -xf $cached
-    rm $cached
-}
-
-# Archive downloads are temporarily disabled due to sudden 504
-# gateway timeout errors.
-# included="src/llvm-project src/doc/book src/doc/rust-by-example"
-included=""
-modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
-modules=($modules)
-use_git=""
-urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)"
-urls=($urls)
-# shellcheck disable=SC2068
-for i in ${!modules[@]}; do
-    module=${modules[$i]}
-    if [[ " $included " = *" $module "* ]]; then
-        commit="$(git ls-tree HEAD $module | awk '{print $3}')"
-        git rm $module
-        url=${urls[$i]}
-        url=${url/\.git/}
-        fetch_github_commit_archive $module "$url/archive/$commit.tar.gz" &
-        bg_pids[${i}]=$!
-        continue
-    else
-        use_git="$use_git $module"
-    fi
-done
-retry sh -c "git submodule deinit -f $use_git && \
-    git submodule sync && \
-    git submodule update -j 16 --init --recursive --depth 1 $use_git"
-# STATUS=0
-# for pid in ${bg_pids[*]}
-# do
-#     wait $pid || STATUS=1
-# done
-# exit ${STATUS}
diff --git a/src/ci/run.sh b/src/ci/run.sh
index b0314047c07..16d8bdb8153 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -132,7 +132,7 @@ trap datecheck EXIT
 SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true
 
 if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
-  $SRC/configure --enable-parallel-compiler
+  $SRC/configure --set rust.parallel-compiler
   CARGO_INCREMENTAL=0 $PYTHON ../x.py check
   rm -f config.toml
   rm -rf build
diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh
index 0b44ea3c90b..3eb4b8f9058 100755
--- a/src/ci/scripts/checkout-submodules.sh
+++ b/src/ci/scripts/checkout-submodules.sh
@@ -2,16 +2,70 @@
 # Check out all our submodules, but more quickly than using git by using one of
 # our custom scripts
 
-set -euo pipefail
-IFS=$'\n\t'
+set -o errexit
+set -o pipefail
+set -o nounset
 
-source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+if [ ! -d ".git" ]; then
+    echo "Error: This must run in the root of the repository"
+    exit 1
+fi
+
+ci_dir=$(cd $(dirname $0) && pwd)/..
+. "$ci_dir/shared.sh"
 
-if isWindows; then
-    path="/c/cache/rustsrc"
-else
-    path="${HOME}/rustsrc"
+# On the beta channel we'll be automatically calculating the prerelease version
+# via the git history, so unshallow our shallow clone from CI.
+if [ "$(releaseChannel)" = "beta" ]; then
+  git fetch origin --unshallow beta master
 fi
 
-mkdir -p "${path}"
-"$(cd "$(dirname "$0")" && pwd)/../init_repo.sh" . "${path}"
+function fetch_github_commit_archive {
+    local module=$1
+    local cached="download-${module//\//-}.tar.gz"
+    retry sh -c "rm -f $cached && \
+        curl -f -sSL -o $cached $2"
+    mkdir $module
+    touch "$module/.git"
+    # On Windows, the default behavior is to emulate symlinks by copying
+    # files. However, that ends up being order-dependent while extracting,
+    # which can cause a failure if the symlink comes first. This env var
+    # causes tar to use real symlinks instead, which are allowed to dangle.
+    export MSYS=winsymlinks:nativestrict
+    tar -C $module --strip-components=1 -xf $cached
+    rm $cached
+}
+
+# Archive downloads are temporarily disabled due to sudden 504
+# gateway timeout errors.
+# included="src/llvm-project src/doc/book src/doc/rust-by-example"
+included=""
+modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
+modules=($modules)
+use_git=""
+urls="$(git config --file .gitmodules --get-regexp '\.url$' | cut -d' ' -f2)"
+urls=($urls)
+# shellcheck disable=SC2068
+for i in ${!modules[@]}; do
+    module=${modules[$i]}
+    if [[ " $included " = *" $module "* ]]; then
+        commit="$(git ls-tree HEAD $module | awk '{print $3}')"
+        git rm $module
+        url=${urls[$i]}
+        url=${url/\.git/}
+        fetch_github_commit_archive $module "$url/archive/$commit.tar.gz" &
+        bg_pids[${i}]=$!
+        continue
+    else
+        use_git="$use_git $module"
+    fi
+done
+retry sh -c "git submodule deinit -f $use_git && \
+    git submodule sync && \
+    git submodule update -j 16 --init --recursive --depth 1 $use_git"
+# STATUS=0
+# for pid in ${bg_pids[*]}
+# do
+#     wait $pid || STATUS=1
+# done
+# exit ${STATUS}
diff --git a/src/doc/book b/src/doc/book
-Subproject efbafdba3618487fbc9305318fcab9775132ac1
+Subproject cf2653a5ca553cbbb4a17f1a7db1947820f6a77
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject e17dcef5e96346ee3d7fa56820ddc7e5c39636b
+Subproject 766979590da8100998f0d662499d4a901d8d164
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 3a43983b76174342b7dbd3e12ea2c49f762e52b
+Subproject 70db9e4189f64d1d8e2451b1046111fb356b6dc
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 1095df2a5850f2d345fad43a30633133365875b
+Subproject 83724ca387a2a1cd3e8d848f62820020760e358
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 048d925f0a955aac601c4160c0e7f05771bcf63
+Subproject eb83839e903a0a8f1406f7e941886273f189b26
diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
new file mode 100644
index 00000000000..c5e86f17df7
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
@@ -0,0 +1,9 @@
+## `dwarf-version`
+
+This option controls the version of DWARF that the compiler emits, on platforms
+that use DWARF to encode debug information. It takes one of the following
+values:
+
+* `2`: DWARF version 2 (the default on certain platforms, like macOS).
+* `4`: DWARF version 4 (the default on certain platforms, like Linux).
+* `5`: DWARF version 5.
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6ee725edcfc..efa73a79e99 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -629,6 +629,7 @@ fn clean_ty_generics<'tcx>(
         .params
         .iter()
         .filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None,
             ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
             ty::GenericParamDefKind::Type { synthetic, .. } => {
                 if param.name == kw::SelfUpper {
@@ -1704,8 +1705,8 @@ fn clean_ty<'tcx>(this: Ty<'tcx>, cx: &mut DocContext<'tcx>, def_id: Option<DefI
             ImplTrait(bounds)
         }
 
-        ty::Closure(..) | ty::Generator(..) => Tuple(vec![]), // FIXME(pcwalton)
-
+        ty::Closure(..) => panic!("Closure"),
+        ty::Generator(..) => panic!("Generator"),
         ty::Bound(..) => panic!("Bound"),
         ty::Placeholder(..) => panic!("Placeholder"),
         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
@@ -1759,7 +1760,6 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     match tcx.def_kind(parent) {
         DefKind::Struct | DefKind::Union => false,
         DefKind::Variant => true,
-        // FIXME: what about DefKind::Ctor?
         parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
     }
 }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 16574f94c00..22b1e2335fd 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -340,17 +340,98 @@ pub(crate) fn is_literal_expr(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
     false
 }
 
+/// Build a textual representation of an unevaluated constant expression.
+///
+/// If the const expression is too complex, an underscore `_` is returned.
+/// For const arguments, it's `{ _ }` to be precise.
+/// This means that the output is not necessarily valid Rust code.
+///
+/// Currently, only
+///
+/// * literals (optionally with a leading `-`)
+/// * unit `()`
+/// * blocks (`{ … }`) around simple expressions and
+/// * paths without arguments
+///
+/// are considered simple enough. Simple blocks are included since they are
+/// necessary to disambiguate unit from the unit type.
+/// This list might get extended in the future.
+///
+/// Without this censoring, in a lot of cases the output would get too large
+/// and verbose. Consider `match` expressions, blocks and deeply nested ADTs.
+/// Further, private and `doc(hidden)` fields of structs would get leaked
+/// since HIR datatypes like the `body` parameter do not contain enough
+/// semantic information for this function to be able to hide them –
+/// at least not without significant performance overhead.
+///
+/// Whenever possible, prefer to evaluate the constant first and try to
+/// use a different method for pretty-printing. Ideally this function
+/// should only ever be used as a fallback.
 pub(crate) fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
     let hir = tcx.hir();
     let value = &hir.body(body).value;
 
-    let snippet = if !value.span.from_expansion() {
-        tcx.sess.source_map().span_to_snippet(value.span).ok()
-    } else {
-        None
-    };
+    #[derive(PartialEq, Eq)]
+    enum Classification {
+        Literal,
+        Simple,
+        Complex,
+    }
 
-    snippet.unwrap_or_else(|| rustc_hir_pretty::id_to_string(&hir, body.hir_id))
+    use Classification::*;
+
+    fn classify(expr: &hir::Expr<'_>) -> Classification {
+        match &expr.kind {
+            hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
+                if matches!(expr.kind, hir::ExprKind::Lit(_)) { Literal } else { Complex }
+            }
+            hir::ExprKind::Lit(_) => Literal,
+            hir::ExprKind::Tup([]) => Simple,
+            hir::ExprKind::Block(hir::Block { stmts: [], expr: Some(expr), .. }, _) => {
+                if classify(expr) == Complex { Complex } else { Simple }
+            }
+            // Paths with a self-type or arguments are too “complex” following our measure since
+            // they may leak private fields of structs (with feature `adt_const_params`).
+            // Consider: `<Self as Trait<{ Struct { private: () } }>>::CONSTANT`.
+            // Paths without arguments are definitely harmless though.
+            hir::ExprKind::Path(hir::QPath::Resolved(_, hir::Path { segments, .. })) => {
+                if segments.iter().all(|segment| segment.args.is_none()) { Simple } else { Complex }
+            }
+            // FIXME: Claiming that those kinds of QPaths are simple is probably not true if the Ty
+            //        contains const arguments. Is there a *concise* way to check for this?
+            hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => Simple,
+            // FIXME: Can they contain const arguments and thus leak private struct fields?
+            hir::ExprKind::Path(hir::QPath::LangItem(..)) => Simple,
+            _ => Complex,
+        }
+    }
+
+    let classification = classify(value);
+
+    if classification == Literal
+    && !value.span.from_expansion()
+    && let Ok(snippet) = tcx.sess.source_map().span_to_snippet(value.span) {
+        // For literals, we avoid invoking the pretty-printer and use the source snippet instead to
+        // preserve certain stylistic choices the user likely made for the sake legibility like
+        //
+        // * hexadecimal notation
+        // * underscores
+        // * character escapes
+        //
+        // FIXME: This passes through `-/*spacer*/0` verbatim.
+        snippet
+    } else if classification == Simple {
+        // Otherwise we prefer pretty-printing to get rid of extraneous whitespace, comments and
+        // other formatting artifacts.
+        rustc_hir_pretty::id_to_string(&hir, body.hir_id)
+    } else if tcx.def_kind(hir.body_owner_def_id(body).to_def_id()) == DefKind::AnonConst {
+        // FIXME: Omit the curly braces if the enclosing expression is an array literal
+        //        with a repeated element (an `ExprKind::Repeat`) as in such case it
+        //        would not actually need any disambiguation.
+        "{ _ }".to_owned()
+    } else {
+        "_".to_owned()
+    }
 }
 
 /// Given a type Path, resolve it to a Type using the TyCtxt
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 50d154dd278..272188f8299 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -73,6 +73,8 @@ pub(crate) struct Options {
     pub(crate) proc_macro_crate: bool,
     /// How to format errors and warnings.
     pub(crate) error_format: ErrorOutputType,
+    /// Width of output buffer to truncate errors appropriately.
+    pub(crate) diagnostic_width: Option<usize>,
     /// Library search paths to hand to the compiler.
     pub(crate) libs: Vec<SearchPath>,
     /// Library search paths strings to hand to the compiler.
@@ -237,9 +239,6 @@ pub(crate) struct RenderOptions {
     pub(crate) resource_suffix: String,
     /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
     /// default.
-    //
-    // FIXME(misdreavus): the flag name is `--disable-minification` but the meaning is inverted
-    // once read.
     pub(crate) enable_minification: bool,
     /// Whether to create an index page in the root of the output directory. If this is true but
     /// `enable_index_page` is None, generate a static listing of crates instead.
@@ -334,11 +333,12 @@ impl Options {
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
             config::parse_json(matches);
         let error_format = config::parse_error_format(matches, color, json_rendered);
+        let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
         let codegen_options = CodegenOptions::build(matches, error_format);
         let debugging_opts = DebuggingOptions::build(matches, error_format);
 
-        let diag = new_handler(error_format, None, &debugging_opts);
+        let diag = new_handler(error_format, None, diagnostic_width, &debugging_opts);
 
         // check for deprecated options
         check_deprecated_options(matches, &diag);
@@ -353,11 +353,7 @@ impl Options {
             print_flag_list("-C", config::CG_OPTIONS);
             return Err(0);
         }
-        let w_flags = matches.opt_strs("W");
-        if w_flags.iter().any(|x| *x == "help") {
-            print_flag_list("-W", config::DB_OPTIONS);
-            return Err(0);
-        }
+
         if matches.opt_strs("passes") == ["list"] {
             println!("Available passes for running rustdoc:");
             for pass in passes::PASSES {
@@ -439,15 +435,19 @@ impl Options {
             return Err(0);
         }
 
-        if matches.free.is_empty() {
+        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+
+        let input = PathBuf::from(if describe_lints {
+            "" // dummy, this won't be used
+        } else if matches.free.is_empty() {
             diag.struct_err("missing file operand").emit();
             return Err(1);
-        }
-        if matches.free.len() > 1 {
+        } else if matches.free.len() > 1 {
             diag.struct_err("too many file operands").emit();
             return Err(1);
-        }
-        let input = PathBuf::from(&matches.free[0]);
+        } else {
+            &matches.free[0]
+        });
 
         let libs = matches
             .opt_strs("L")
@@ -698,12 +698,11 @@ impl Options {
         let with_examples = matches.opt_strs("with-examples");
         let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
         Ok(Options {
             input,
             proc_macro_crate,
             error_format,
+            diagnostic_width,
             libs,
             lib_strs,
             externs,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 51b245e36ba..8c494ee28cc 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -154,6 +154,7 @@ impl<'tcx> DocContext<'tcx> {
 pub(crate) fn new_handler(
     error_format: ErrorOutputType,
     source_map: Option<Lrc<source_map::SourceMap>>,
+    diagnostic_width: Option<usize>,
     debugging_opts: &DebuggingOptions,
 ) -> rustc_errors::Handler {
     let fallback_bundle =
@@ -169,7 +170,7 @@ pub(crate) fn new_handler(
                     fallback_bundle,
                     short,
                     debugging_opts.teach,
-                    debugging_opts.terminal_width,
+                    diagnostic_width,
                     false,
                 )
                 .ui_testing(debugging_opts.ui_testing),
@@ -187,7 +188,7 @@ pub(crate) fn new_handler(
                     fallback_bundle,
                     pretty,
                     json_rendered,
-                    debugging_opts.terminal_width,
+                    diagnostic_width,
                     false,
                 )
                 .ui_testing(debugging_opts.ui_testing),
@@ -208,6 +209,7 @@ pub(crate) fn create_config(
         crate_name,
         proc_macro_crate,
         error_format,
+        diagnostic_width,
         libs,
         externs,
         mut cfgs,
@@ -266,6 +268,7 @@ pub(crate) fn create_config(
         actually_rustdoc: true,
         debugging_opts,
         error_format,
+        diagnostic_width,
         edition,
         describe_lints,
         crate_name,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 056eda089c1..84ab8d988bd 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -146,6 +146,10 @@ impl Buffer {
     pub(crate) fn reserve(&mut self, additional: usize) {
         self.buffer.reserve(additional)
     }
+
+    pub(crate) fn len(&self) -> usize {
+        self.buffer.len()
+    }
 }
 
 fn comma_sep<T: fmt::Display>(
@@ -264,6 +268,12 @@ impl clean::Generics {
     }
 }
 
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub(crate) enum Ending {
+    Newline,
+    NoNewline,
+}
+
 /// * The Generics from which to emit a where-clause.
 /// * The number of spaces to indent each line with.
 /// * Whether the where-clause needs to add a comma and newline after the last bound.
@@ -271,7 +281,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
     gens: &'a clean::Generics,
     cx: &'a Context<'tcx>,
     indent: usize,
-    end_newline: bool,
+    ending: Ending,
 ) -> impl fmt::Display + 'a + Captures<'tcx> {
     use fmt::Write;
 
@@ -338,7 +348,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
 
         let where_preds = comma_sep(where_predicates, false);
         let clause = if f.alternate() {
-            if end_newline {
+            if ending == Ending::Newline {
                 // add a space so stripping <br> tags and breaking spaces still renders properly
                 format!(" where{where_preds}, ")
             } else {
@@ -352,7 +362,7 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>(
             }
             let where_preds = where_preds.to_string().replace("<br>", &br_with_padding);
 
-            if end_newline {
+            if ending == Ending::Newline {
                 let mut clause = "&nbsp;".repeat(indent.saturating_sub(1));
                 // add a space so stripping <br> tags and breaking spaces still renders properly
                 write!(
@@ -1163,7 +1173,7 @@ impl clean::Impl {
                 fmt_type(&self.for_, f, use_absolute, cx)?;
             }
 
-            fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, true), f)?;
+            fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, Ending::Newline), f)?;
             Ok(())
         })
     }
@@ -1283,10 +1293,6 @@ impl clean::FnDecl {
         let mut args = Buffer::html();
         let mut args_plain = Buffer::new();
         for (i, input) in self.inputs.values.iter().enumerate() {
-            if i == 0 {
-                args.push_str("<br>");
-            }
-
             if let Some(selfty) = input.to_self() {
                 match selfty {
                     clean::SelfValue => {
@@ -1312,8 +1318,7 @@ impl clean::FnDecl {
                 }
             } else {
                 if i > 0 {
-                    args.push_str(" <br>");
-                    args_plain.push_str(" ");
+                    args.push_str("<br>");
                 }
                 if input.is_const {
                     args.push_str("const ");
@@ -1360,13 +1365,14 @@ impl clean::FnDecl {
             let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
             let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
             format!(
-                "({args}{close}){arrow}",
+                "({pad}{args}{close}){arrow}",
+                pad = if self.inputs.values.is_empty() { "" } else { &full_pad },
                 args = args.replace("<br>", &full_pad),
                 close = close_pad,
                 arrow = arrow
             )
         } else {
-            format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
+            format!("({args}){arrow}", args = args.replace("<br>", " "), arrow = arrow)
         };
 
         if f.alternate() {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 1ef41d62e5e..459b0fed6e8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -70,7 +70,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
     href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
-    print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError,
+    print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError,
     PrintWithSpace,
 };
 use crate::html::highlight;
@@ -634,7 +634,6 @@ fn render_impls(
                 &[],
                 ImplRenderingParameters {
                     show_def_docs: true,
-                    is_on_foreign_type: false,
                     show_default_items: true,
                     show_non_assoc_items: true,
                     toggle_open_by_default,
@@ -716,12 +715,14 @@ fn assoc_const(
         ty = ty.print(cx),
     );
     if let Some(default) = default {
+        write!(w, " = ");
+
         // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
         //        hood which adds noisy underscores and a type suffix to number literals.
         //        This hurts readability in this context especially when more complex expressions
         //        are involved and it doesn't add much of value.
         //        Find a way to print constants here without all that jazz.
-        write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())));
+        write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx()))));
     }
 }
 
@@ -746,7 +747,7 @@ fn assoc_type(
     if !bounds.is_empty() {
         write!(w, ": {}", print_generic_bounds(bounds, cx))
     }
-    write!(w, "{}", print_where_clause(generics, cx, indent, false));
+    write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
     if let Some(default) = default {
         write!(w, " = {}", default.print(cx))
     }
@@ -795,10 +796,10 @@ fn assoc_method(
         header_len += 4;
         let indent_str = "    ";
         render_attributes_in_pre(w, meth, indent_str);
-        (4, indent_str, false)
+        (4, indent_str, Ending::NoNewline)
     } else {
         render_attributes_in_code(w, meth);
-        (0, "", true)
+        (0, "", Ending::Newline)
     };
     w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
     write!(
@@ -1069,7 +1070,6 @@ fn render_assoc_items_inner(
                 &[],
                 ImplRenderingParameters {
                     show_def_docs: true,
-                    is_on_foreign_type: false,
                     show_default_items: true,
                     show_non_assoc_items: true,
                     toggle_open_by_default: true,
@@ -1285,7 +1285,6 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
 #[derive(Clone, Copy, Debug)]
 struct ImplRenderingParameters {
     show_def_docs: bool,
-    is_on_foreign_type: bool,
     show_default_items: bool,
     /// Whether or not to show methods.
     show_non_assoc_items: bool,
@@ -1413,7 +1412,10 @@ fn render_impl(
                         id, item_type, in_trait_class,
                     );
                     render_rightside(w, cx, item, containing_item, render_mode);
-                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                    if trait_.is_some() {
+                        // Anchors are only used on trait impls.
+                        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                    }
                     w.write_str("<h4 class=\"code-header\">");
                     render_assoc_item(
                         w,
@@ -1436,7 +1438,10 @@ fn render_impl(
                     id, item_type, in_trait_class
                 );
                 render_rightside(w, cx, item, containing_item, render_mode);
-                write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                if trait_.is_some() {
+                    // Anchors are only used on trait impls.
+                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_const(
                     w,
@@ -1458,7 +1463,10 @@ fn render_impl(
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
                 write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
-                write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                if trait_.is_some() {
+                    // Anchors are only used on trait impls.
+                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
                     w,
@@ -1481,7 +1489,10 @@ fn render_impl(
                     "<section id=\"{}\" class=\"{}{} has-srclink\">",
                     id, item_type, in_trait_class
                 );
-                write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                if trait_.is_some() {
+                    // Anchors are only used on trait impls.
+                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
                     w,
@@ -1601,7 +1612,6 @@ fn render_impl(
             parent,
             rendering_params.show_def_docs,
             use_absolute,
-            rendering_params.is_on_foreign_type,
             aliases,
         );
         if toggled {
@@ -1686,21 +1696,12 @@ pub(crate) fn render_impl_summary(
     containing_item: &clean::Item,
     show_def_docs: bool,
     use_absolute: Option<bool>,
-    is_on_foreign_type: bool,
     // This argument is used to reference same type with different paths to avoid duplication
     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
     aliases: &[String],
 ) {
-    let id = cx.derive_id(match i.inner_impl().trait_ {
-        Some(ref t) => {
-            if is_on_foreign_type {
-                get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
-            } else {
-                format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
-            }
-        }
-        None => "impl".to_string(),
-    });
+    let id =
+        cx.derive_id(get_id_for_impl(&i.inner_impl().for_, i.inner_impl().trait_.as_ref(), cx));
     let aliases = if aliases.is_empty() {
         String::new()
     } else {
@@ -1984,21 +1985,18 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 let mut ret = impls
                     .iter()
                     .filter_map(|it| {
-                        if let Some(ref i) = it.inner_impl().trait_ {
-                            let i_display = format!("{:#}", i.print(cx));
-                            let out = Escape(&i_display);
-                            let encoded =
-                                id_map.derive(small_url_encode(format!("impl-{:#}", i.print(cx))));
-                            let prefix = match it.inner_impl().polarity {
-                                ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
-                                ty::ImplPolarity::Negative => "!",
-                            };
-                            let generated =
-                                format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
-                            if links.insert(generated.clone()) { Some(generated) } else { None }
-                        } else {
-                            None
-                        }
+                        let trait_ = it.inner_impl().trait_.as_ref()?;
+                        let encoded =
+                            id_map.derive(get_id_for_impl(&it.inner_impl().for_, Some(trait_), cx));
+
+                        let i_display = format!("{:#}", trait_.print(cx));
+                        let out = Escape(&i_display);
+                        let prefix = match it.inner_impl().polarity {
+                            ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
+                            ty::ImplPolarity::Negative => "!",
+                        };
+                        let generated = format!("<a href=\"#{}\">{}{}</a>", encoded, prefix, out);
+                        if links.insert(generated.clone()) { Some(generated) } else { None }
                     })
                     .collect::<Vec<String>>();
                 ret.sort();
@@ -2145,12 +2143,11 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     }
 }
 
-fn get_id_for_impl_on_foreign_type(
-    for_: &clean::Type,
-    trait_: &clean::Path,
-    cx: &Context<'_>,
-) -> String {
-    small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx)))
+fn get_id_for_impl(for_: &clean::Type, trait_: Option<&clean::Path>, cx: &Context<'_>) -> String {
+    match trait_ {
+        Some(t) => small_url_encode(format!("impl-{:#}-for-{:#}", t.print(cx), for_.print(cx))),
+        None => small_url_encode(format!("impl-{:#}", for_.print(cx))),
+    }
 }
 
 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
@@ -2159,10 +2156,7 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String
             i.trait_.as_ref().map(|trait_| {
                 // Alternative format produces no URLs,
                 // so this parameter does nothing.
-                (
-                    format!("{:#}", i.for_.print(cx)),
-                    get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
-                )
+                (format!("{:#}", i.for_.print(cx)), get_id_for_impl(&i.for_, Some(trait_), cx))
             })
         }
         _ => None,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 0fe99463f1d..daacc57a55a 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -29,7 +29,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
     join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
-    Buffer, PrintWithSpace,
+    Buffer, Ending, PrintWithSpace,
 };
 use crate::html::highlight;
 use crate::html::layout::Page;
@@ -62,6 +62,17 @@ struct ItemVars<'a> {
     src_href: Option<&'a str>,
 }
 
+/// Calls `print_where_clause` and returns `true` if a `where` clause was generated.
+fn print_where_clause_and_check<'a, 'tcx: 'a>(
+    buffer: &mut Buffer,
+    gens: &'a clean::Generics,
+    cx: &'a Context<'tcx>,
+) -> bool {
+    let len_before = buffer.len();
+    write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline));
+    len_before != buffer.len()
+}
+
 pub(super) fn print_item(
     cx: &mut Context<'_>,
     item: &clean::Item,
@@ -508,7 +519,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
                 abi = abi,
                 name = name,
                 generics = f.generics.print(cx),
-                where_clause = print_where_clause(&f.generics, cx, 0, true),
+                where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
                 decl = f.decl.full_print(header_len, 0, header.asyncness, cx),
                 notable_traits = notable_traits_decl(&f.decl, cx),
             );
@@ -545,7 +556,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             );
 
             if !t.generics.where_predicates.is_empty() {
-                write!(w, "{}", print_where_clause(&t.generics, cx, 0, true));
+                write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
             } else {
                 w.write_str(" ");
             }
@@ -853,7 +864,6 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
                     &[],
                     ImplRenderingParameters {
                         show_def_docs: false,
-                        is_on_foreign_type: true,
                         show_default_items: false,
                         show_non_assoc_items: true,
                         toggle_open_by_default: false,
@@ -1015,7 +1025,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &
                 "trait {}{}{} = {};",
                 it.name.unwrap(),
                 t.generics.print(cx),
-                print_where_clause(&t.generics, cx, 0, true),
+                print_where_clause(&t.generics, cx, 0, Ending::Newline),
                 bounds(&t.bounds, true, cx)
             );
         });
@@ -1039,7 +1049,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl
                 "type {}{}{where_clause} = impl {bounds};",
                 it.name.unwrap(),
                 t.generics.print(cx),
-                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
                 bounds = bounds(&t.bounds, false, cx),
             );
         });
@@ -1064,7 +1074,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
                 "type {}{}{where_clause} = {type_};",
                 it.name.unwrap(),
                 t.generics.print(cx),
-                where_clause = print_where_clause(&t.generics, cx, 0, true),
+                where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
                 type_ = t.type_.print(cx),
             );
         });
@@ -1152,17 +1162,21 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
             render_attributes_in_pre(w, it, "");
             write!(
                 w,
-                "{}enum {}{}{}",
+                "{}enum {}{}",
                 it.visibility.print_with_space(it.item_id, cx),
                 it.name.unwrap(),
                 e.generics.print(cx),
-                print_where_clause(&e.generics, cx, 0, true),
             );
+            if !print_where_clause_and_check(w, &e.generics, cx) {
+                // If there wasn't a `where` clause, we add a whitespace.
+                w.write_str(" ");
+            }
+
             let variants_stripped = e.has_stripped_entries();
             if count_variants == 0 && !variants_stripped {
-                w.write_str(" {}");
+                w.write_str("{}");
             } else {
-                w.write_str(" {\n");
+                w.write_str("{\n");
                 let toggle = should_hide_fields(count_variants);
                 if toggle {
                     toggle_open(w, format_args!("{} variants", count_variants));
@@ -1360,6 +1374,15 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
                 typ = c.type_.print(cx),
             );
 
+            // FIXME: The code below now prints
+            //            ` = _; // 100i32`
+            //        if the expression is
+            //            `50 + 50`
+            //        which looks just wrong.
+            //        Should we print
+            //            ` = 100i32;`
+            //        instead?
+
             let value = c.value(cx.tcx());
             let is_literal = c.is_literal(cx.tcx());
             let expr = c.expr(cx.tcx());
@@ -1618,7 +1641,6 @@ fn render_implementor(
         aliases,
         ImplRenderingParameters {
             show_def_docs: false,
-            is_on_foreign_type: false,
             show_default_items: false,
             show_non_assoc_items: false,
             toggle_open_by_default: false,
@@ -1634,13 +1656,21 @@ fn render_union(
     tab: &str,
     cx: &Context<'_>,
 ) {
-    write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap());
-    if let Some(g) = g {
-        write!(w, "{}", g.print(cx));
-        write!(w, "{}", print_where_clause(g, cx, 0, true));
+    write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(),);
+
+    let where_displayed = g
+        .map(|g| {
+            write!(w, "{}", g.print(cx));
+            print_where_clause_and_check(w, g, cx)
+        })
+        .unwrap_or(false);
+
+    // If there wasn't a `where` clause, we add a whitespace.
+    if !where_displayed {
+        w.write_str(" ");
     }
 
-    write!(w, " {{\n{}", tab);
+    write!(w, "{{\n{}", tab);
     let count_fields =
         fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
     let toggle = should_hide_fields(count_fields);
@@ -1692,10 +1722,14 @@ fn render_struct(
     }
     match ty {
         CtorKind::Fictive => {
-            if let Some(g) = g {
-                write!(w, "{}", print_where_clause(g, cx, 0, true),)
+            let where_diplayed = g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false);
+
+            // If there wasn't a `where` clause, we add a whitespace.
+            if !where_diplayed {
+                w.write_str(" {");
+            } else {
+                w.write_str("{");
             }
-            w.write_str(" {");
             let count_fields =
                 fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
             let has_visible_fields = count_fields > 0;
@@ -1750,7 +1784,7 @@ fn render_struct(
             }
             w.write_str(")");
             if let Some(g) = g {
-                write!(w, "{}", print_where_clause(g, cx, 0, false),)
+                write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
             }
             // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
             if structhead {
@@ -1760,7 +1794,7 @@ fn render_struct(
         CtorKind::Const => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", print_where_clause(g, cx, 0, false),)
+                write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
             }
             w.write_str(";");
         }
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index 2817a8fe144..fcd925bb358 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -91,5 +91,6 @@ module.exports = {
         "no-script-url": "error",
         "no-sequences": "error",
         "no-throw-literal": "error",
+        "no-div-regex": "error",
     }
 };
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index f7b4fdb736c..5c7b56ec140 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -418,7 +418,7 @@ nav.sub {
 	background-color: var(--sidebar-background-color);
 }
 
-#sidebar-toggle:hover {
+#sidebar-toggle > button:hover, #sidebar-toggle > button:focus {
 	background-color: var(--sidebar-background-color-hover);
 }
 
@@ -924,7 +924,6 @@ table,
 #crate-search {
 	min-width: 115px;
 	margin-top: 5px;
-	margin-left: 0.25em;
 	padding-left: 0.3125em;
 	padding-right: 23px;
 	border: 1px solid;
@@ -941,6 +940,8 @@ table,
 	background-size: 20px;
 	background-position: calc(100% - 1px) 56%;
 	background-image: /* AUTOREPLACE: */url("down-arrow.svg");
+	max-width: 100%;
+	text-overflow: ellipsis;
 }
 .search-container {
 	margin-top: 4px;
@@ -1401,7 +1402,6 @@ pre.rust {
 	position: sticky;
 	top: 0;
 	left: 0;
-	cursor: pointer;
 	font-weight: bold;
 	font-size: 1.25rem;
 	border-bottom: 1px solid;
@@ -1422,7 +1422,24 @@ pre.rust {
 	border-bottom: 1px solid;
 	margin-bottom: 6px;
 }
-
+#sidebar-toggle > button {
+	background: none;
+	color: inherit;
+	cursor: pointer;
+	text-align: center;
+	border: none;
+	outline: none;
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	/* work around button layout strangeness: https://stackoverflow.com/q/7271561 */
+	width: 100%;
+	/* iOS button gradient: https://stackoverflow.com/q/5438567 */
+	-webkit-appearance: none;
+	opacity: 1;
+}
 #settings-menu, #help-button {
 	margin-left: 4px;
 	outline: none;
@@ -1578,38 +1595,23 @@ kbd {
 	margin-bottom: 1em;
 }
 
-div.children {
-	padding-left: 27px;
-	display: none;
+details.dir-entry {
+	padding-left: 4px;
 }
-div.name {
+
+details.dir-entry > summary {
+	margin: 0 0 0 13px;
+	list-style-position: outside;
 	cursor: pointer;
-	position: relative;
-	margin-left: 16px;
-}
-div.files > a {
-	display: block;
-	padding: 0 3px;
 }
-div.files > a:hover, div.name:hover {
-	background-color: #a14b4b;
+
+details.dir-entry div.folders, details.dir-entry div.files {
+	padding-left: 23px;
 }
-div.name.expand + .children {
+
+details.dir-entry a {
 	display: block;
 }
-div.name::before {
-	content: "\25B6";
-	padding-left: 4px;
-	font-size: 0.625rem;
-	position: absolute;
-	left: -16px;
-	top: 4px;
-}
-div.name.expand::before {
-	transform: rotate(90deg);
-	left: -15px;
-	top: 2px;
-}
 
 /* The hideme class is used on summary tags that contain a span with
 	placeholder text shown only when the toggle is closed. For instance,
@@ -1738,6 +1740,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 
 /* Media Queries */
 
+/*
+WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY;
+If you update this line, then you also need to update the line with the same warning
+in storage.js plus the media query with (max-width: 700px)
+*/
 @media (min-width: 701px) {
 	/* In case there is no documentation before a code block, we need to add some margin at the top
 	to prevent an overlay between the "collapse toggle" and the information tooltip.
@@ -1758,6 +1765,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 	}
 }
 
+/*
+WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
+If you update this line, then you also need to update the line with the same warning
+in storage.js plus the media query with (min-width: 701px)
+*/
 @media (max-width: 700px) {
 	/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
 	   or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
@@ -2045,9 +2057,19 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 }
 
 @media print {
-	nav.sub, .content .out-of-band {
+	nav.sidebar, nav.sub, .content .out-of-band, a.srclink, #copy-path,
+	details.rustdoc-toggle[open] > summary::before, details.rustdoc-toggle > summary::before,
+	details.rustdoc-toggle.top-doc > summary {
 		display: none;
 	}
+
+	.docblock {
+		margin-left: 0;
+	}
+
+	main {
+		padding: 10px;
+	}
 }
 
 @media (max-width: 464px) {
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 7756e877ef7..b25f5e9fdb1 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -575,11 +575,12 @@ kbd {
 	color: #fff;
 	border-bottom-color: #5c6773;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #14191f;
 	color: #ffb44c;
 }
-#source-sidebar div.files > .selected {
+#source-sidebar div.files > a.selected {
 	background-color: #14191f;
 	color: #ffb44c;
 }
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 04d5778f59c..184d0e77a90 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -178,9 +178,6 @@ a {
 	color: #D2991D;
 }
 
-a.test-arrow {
-	color: #dedede;
-}
 body.source .example-wrap pre.rust a {
 	background: #333;
 }
@@ -255,6 +252,7 @@ pre.rust .question-mark {
 }
 
 a.test-arrow {
+	color: #dedede;
 	background-color: rgba(78, 139, 202, 0.2);
 }
 
@@ -432,10 +430,11 @@ kbd {
 #source-sidebar > .title {
 	border-bottom-color: #ccc;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #444;
 }
-#source-sidebar div.files > .selected {
+#source-sidebar div.files > a.selected {
 	background-color: #333;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 5310736037a..c6ba13fe1d6 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -175,9 +175,6 @@ a {
 	color: #3873AD;
 }
 
-a.test-arrow {
-	color: #f5f5f5;
-}
 body.source .example-wrap pre.rust a {
 	background: #eee;
 }
@@ -239,7 +236,8 @@ pre.rust .question-mark {
 }
 
 a.test-arrow {
-	background-color: rgb(78, 139, 202, 0.2);
+	color: #f5f5f5;
+	background-color: rgba(78, 139, 202, 0.2);
 }
 
 a.test-arrow:hover{
@@ -414,13 +412,13 @@ kbd {
 #source-sidebar > .title {
 	border-bottom-color: #ccc;
 }
-#source-sidebar div.files > a:hover, div.name:hover {
+#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
+#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
 	background-color: #E0E0E0;
 }
-#source-sidebar div.files > .selected {
+#source-sidebar div.files > a.selected {
 	background-color: #fff;
 }
-
 .scraped-example-list .scrape-help {
 	border-color: #555;
 	color: #333;
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index acb1d8d7b5c..1e9bfa5cc89 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -2,7 +2,7 @@
 /* global sourcesIndex */
 
 // Local js definitions:
-/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
+/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage */
 
 "use strict";
@@ -12,34 +12,34 @@
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
 let oldScrollPosition = 0;
 
+function closeSidebarIfMobile() {
+    if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+        updateLocalStorage("source-sidebar-show", "false");
+    }
+}
+
 function createDirEntry(elem, parent, fullPath, hasFoundFile) {
-    const name = document.createElement("div");
-    name.className = "name";
+    const dirEntry = document.createElement("details");
+    const summary = document.createElement("summary");
+
+    dirEntry.className = "dir-entry";
 
     fullPath += elem["name"] + "/";
 
-    name.onclick = ev => {
-        if (hasClass(ev.target, "expand")) {
-            removeClass(ev.target, "expand");
-        } else {
-            addClass(ev.target, "expand");
-        }
-    };
-    name.innerText = elem["name"];
+    summary.innerText = elem["name"];
+    dirEntry.appendChild(summary);
 
-    const children = document.createElement("div");
-    children.className = "children";
     const folders = document.createElement("div");
     folders.className = "folders";
     if (elem.dirs) {
         for (const dir of elem.dirs) {
             if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
-                addClass(name, "expand");
+                dirEntry.open = true;
                 hasFoundFile = true;
             }
         }
     }
-    children.appendChild(folders);
+    dirEntry.appendChild(folders);
 
     const files = document.createElement("div");
     files.className = "files";
@@ -48,25 +48,25 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
             const file = document.createElement("a");
             file.innerText = file_text;
             file.href = rootPath + "src/" + fullPath + file_text + ".html";
+            file.addEventListener("click", closeSidebarIfMobile);
             const w = window.location.href.split("#")[0];
             if (!hasFoundFile && w === file.href) {
                 file.className = "selected";
-                addClass(name, "expand");
+                dirEntry.open = true;
                 hasFoundFile = true;
             }
             files.appendChild(file);
         }
     }
-    children.appendChild(files);
-    parent.appendChild(name);
-    parent.appendChild(children);
+    dirEntry.appendChild(files);
+    parent.appendChild(dirEntry);
     return hasFoundFile;
 }
 
 function toggleSidebar() {
-    const child = this.children[0];
+    const child = this.parentNode.children[0];
     if (child.innerText === ">") {
-        if (window.innerWidth < 701) {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
             // This is to keep the scroll position on mobile.
             oldScrollPosition = window.scrollY;
             document.body.style.position = "fixed";
@@ -76,7 +76,7 @@ function toggleSidebar() {
         child.innerText = "<";
         updateLocalStorage("source-sidebar-show", "true");
     } else {
-        if (window.innerWidth < 701) {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
             // This is to keep the scroll position on mobile.
             document.body.style.position = "";
             document.body.style.top = "";
@@ -93,15 +93,15 @@ function toggleSidebar() {
 function createSidebarToggle() {
     const sidebarToggle = document.createElement("div");
     sidebarToggle.id = "sidebar-toggle";
-    sidebarToggle.onclick = toggleSidebar;
 
-    const inner = document.createElement("div");
+    const inner = document.createElement("button");
 
     if (getCurrentValue("source-sidebar-show") === "true") {
         inner.innerText = "<";
     } else {
         inner.innerText = ">";
     }
+    inner.onclick = toggleSidebar;
 
     sidebarToggle.appendChild(inner);
     return sidebarToggle;
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 1c4c8834488..0c5389d45e5 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"];
 window.currentTheme = document.getElementById("themeStyle");
 window.mainTheme = document.getElementById("mainThemeStyle");
 
+// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
+// If you update this line, then you also need to update the two media queries with the same
+// warning in rustdoc.css
+window.RUSTDOC_MOBILE_BREAKPOINT = 701;
+
 const settingsDataset = (function() {
     const settingsElement = document.getElementById("default-settings");
     if (settingsElement === null) {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index db4c3d10237..0d3ec7ecb64 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -11,7 +11,6 @@
 #![feature(drain_filter)]
 #![feature(let_chains)]
 #![feature(let_else)]
-#![cfg_attr(bootstrap, feature(nll))]
 #![feature(test)]
 #![feature(never_type)]
 #![feature(once_cell)]
@@ -76,7 +75,7 @@ use std::env::{self, VarError};
 use std::io;
 use std::process;
 
-use rustc_driver::{abort_on_err, describe_lints};
+use rustc_driver::abort_on_err;
 use rustc_errors::ErrorGuaranteed;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
@@ -463,6 +462,14 @@ fn opts() -> Vec<RustcOptGroup> {
                 "human|json|short",
             )
         }),
+        unstable("diagnostic-width", |o| {
+            o.optopt(
+                "",
+                "diagnostic-width",
+                "Provide width of the output for truncated error messages",
+                "WIDTH",
+            )
+        }),
         stable("json", |o| {
             o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
         }),
@@ -734,7 +741,12 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
 }
 
 fn main_options(options: config::Options) -> MainResult {
-    let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
+    let diag = core::new_handler(
+        options.error_format,
+        None,
+        options.diagnostic_width,
+        &options.debugging_opts,
+    );
 
     match (options.should_test, options.markdown_input()) {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
@@ -771,15 +783,24 @@ fn main_options(options: config::Options) -> MainResult {
     let config = core::create_config(options);
 
     interface::create_compiler_and_run(config, |compiler| {
-        compiler.enter(|queries| {
-            let sess = compiler.session();
+        let sess = compiler.session();
 
-            if sess.opts.describe_lints {
-                let (_, lint_store) = &*queries.register_plugins()?.peek();
-                describe_lints(sess, lint_store, true);
-                return Ok(());
-            }
+        if sess.opts.describe_lints {
+            let mut lint_store = rustc_lint::new_lint_store(
+                sess.opts.debugging_opts.no_interleave_lints,
+                sess.unstable_options(),
+            );
+            let registered_lints = if let Some(register_lints) = compiler.register_lints() {
+                register_lints(sess, &mut lint_store);
+                true
+            } else {
+                false
+            };
+            rustc_driver::describe_lints(sess, &lint_store, registered_lints);
+            return Ok(());
+        }
 
+        compiler.enter(|queries| {
             // We need to hold on to the complete resolver, so we cause everything to be
             // cloned for the analysis passes to use. Suboptimal, but necessary in the
             // current architecture.
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index e3b349af661..0172ef5700b 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,7 +1,8 @@
 //! Validates syntax inside Rust code blocks (\`\`\`rust).
 use rustc_data_structures::sync::{Lock, Lrc};
-use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle};
-use rustc_middle::lint::LintDiagnosticBuilder;
+use rustc_errors::{
+    emitter::Emitter, Applicability, Diagnostic, Handler, LazyFallbackBundle, LintDiagnosticBuilder,
+};
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
@@ -52,7 +53,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
             None,
             None,
         );
-        let expn_id = LocalExpnId::fresh(expn_data, self.cx.tcx.create_stable_hashing_context());
+        let expn_id =
+            self.cx.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
         let span = DUMMY_SP.fresh_expansion(expn_id);
 
         let is_empty = rustc_driver::catch_fatal_errors(|| {
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index f6c599297fc..c0fe8b49cfd 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -303,7 +303,7 @@ pub(crate) fn run(
         // Run call-finder on all items
         let mut calls = FxHashMap::default();
         let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
-        tcx.hir().deep_visit_all_item_likes(&mut finder);
+        tcx.hir().visit_all_item_likes_in_crate(&mut finder);
 
         // Sort call locations within a given file in document order
         for fn_calls in calls.values_mut() {
diff --git a/src/llvm-project b/src/llvm-project
-Subproject d1ddc34c4b23468f6d2bf553084834b104e16dd
+Subproject 8b6b5014fdad3a750f7242a6bfdcad83619498d
diff --git a/src/stage0.json b/src/stage0.json
index b6b502f4cf0..64b8aca3960 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -16,349 +16,349 @@
     "tool is executed."
   ],
   "compiler": {
-    "date": "2022-05-20",
+    "date": "2022-06-29",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2022-05-20",
+    "date": "2022-06-29",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2022-05-20/cargo-beta-aarch64-apple-darwin.tar.gz": "a07568445804e70f92f8b022a7397d44ac1a4ffc10633715a6ec5d48c27ea45a",
-    "dist/2022-05-20/cargo-beta-aarch64-apple-darwin.tar.xz": "574cb9ee69d5132317b159fa15a0651207361c1673d4c41b839bfd0f5c905b4e",
-    "dist/2022-05-20/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68e566b8d4d022b4f88771d7784e092e7c78b0e2198ad901048b5831b5a1a5d4",
-    "dist/2022-05-20/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f2808f120588bdf97fe5551150eaef2658967fef3e5e5ae3c531156a7312e883",
-    "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "92f31b6ccf0953a07c71e43b898273ad2e304afe840e4b03769122e4a6758553",
-    "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6da85884371a794de85953b48d03549badb86684e2008491064ce120afab31ad",
-    "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "34c9ead4dcc520424ba281ec99466b921970f64320dd051ea73a09cd39f012bf",
-    "dist/2022-05-20/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "ab59385f4c61976f8f2fb31b6463b007eeaa0a71ca8dbbe884e33de4a0143c9d",
-    "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "68fc1f164b9f7a5c1f44d62e37c8c71a6518eff70d3397333c2fb268960ddc45",
-    "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "159e5e293afa533bb0259157fb2e32145d8c87921c253e45aad64c27a765df3a",
-    "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "aa05252a10605158ae9baca676e9ca755fb6d042d4db9121d3e933c610fe8afa",
-    "dist/2022-05-20/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6d090a90bf9c96a3955813ccdd956bf1ef1ee5c1431090f3ca4002f63703ab5",
-    "dist/2022-05-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "52bd65f5d845a4ca51b055e1e0e340b07a82aa7269730fef27d1c151bb0a25cd",
-    "dist/2022-05-20/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c1f96a5d59c3c93be54d82e0b2082651347e53e10ef664332f74bd6f8189849c",
-    "dist/2022-05-20/cargo-beta-i686-pc-windows-gnu.tar.gz": "2ce5513fb746305d61ea301301e93f4879b3cf794298ac77aec0e3eb8dea072d",
-    "dist/2022-05-20/cargo-beta-i686-pc-windows-gnu.tar.xz": "64a800315d0e0555c1c9fb24312c9f6375f4a3ac02b975ed413e764d238c4698",
-    "dist/2022-05-20/cargo-beta-i686-pc-windows-msvc.tar.gz": "1c3464b48509b0e5dee428ecb3ea27c6ec463cc0148f1d04d7d2778b0d654295",
-    "dist/2022-05-20/cargo-beta-i686-pc-windows-msvc.tar.xz": "89f1072af529ea55884882c11f15f8109a3790407903c6f8026b27b21d2fe0fb",
-    "dist/2022-05-20/cargo-beta-i686-unknown-linux-gnu.tar.gz": "57f76852b21ff37e98f441f8b7f81bb8ced7dbc310df0f03a19c907220dd6bfc",
-    "dist/2022-05-20/cargo-beta-i686-unknown-linux-gnu.tar.xz": "2b8885f946f9dce27098318b7c5b9095c6e62a109614355fb176c33a6cd6451f",
-    "dist/2022-05-20/cargo-beta-mips-unknown-linux-gnu.tar.gz": "8b39dd25f1d3a26ec6f8fc1af32f848a0e71ed408f6f2a3f6489eead634f44d9",
-    "dist/2022-05-20/cargo-beta-mips-unknown-linux-gnu.tar.xz": "36c47221f6c80a6e8ff3c1fb8310decfe4a8a6a247d9ad4eceb61f82cc82fdf4",
-    "dist/2022-05-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "eac280aae12b8825bd6dc39a674e27cc6b46f830ef3fc6887b1afcc6b75728eb",
-    "dist/2022-05-20/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "80577e2157820a70107c55102a251a08c94f3fef3841262f55f85d276ec3bac5",
-    "dist/2022-05-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "4c29ad8defc9b59f401da078452f9f9a7c0beb75f5edf1b91f4ac4270c707d3a",
-    "dist/2022-05-20/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "78831636bf6e2d95d7172dfa3e811ad09c363b4178f2359fc597f8470e0981d5",
-    "dist/2022-05-20/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "aaf75a7ea07f00888d394d69a6d438aa5c18f8e3afd93c35fd0323ac01c14064",
-    "dist/2022-05-20/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "026535dae96b5aed3e435d1b4d6297aeb8430587d90c074b15215a91e59a719d",
-    "dist/2022-05-20/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "a3c7d6bfb93f9d15d1a5bd183c985ae939c6f39ce060e177cefbe4fd7e66c48c",
-    "dist/2022-05-20/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "a060b3581966433d2d874e75e4f94a180a8296b23401dd41d60fd8d633f96910",
-    "dist/2022-05-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "77dc67bc9663de62e26752e2658468d859546f3b3dff4f33c2f2efec18a48a13",
-    "dist/2022-05-20/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "cd44e2a0a68f83f9f714f6c7142a20e244b19c2a15b136cb58d71578393bcfab",
-    "dist/2022-05-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0e296167172d82604e9dd36e3369662086903edf07ca4b9fd307d89b1051c8c3",
-    "dist/2022-05-20/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "28577c0e0dc0a9aae045bd834f3f5f9e4e9b3828528b1d702310baba8a8f77d6",
-    "dist/2022-05-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "83e3f41b7b32b77343bdc3776cd372d730eb20c382b73df84b3a427f24673814",
-    "dist/2022-05-20/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1ee99bae6c41bbcd461c26d117424f338e55dd020dbdc9481c76b407593740b4",
-    "dist/2022-05-20/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "529e3f38f37505ba406c3a77cbf0745dddbc87fc1296889e724194c56f5d7064",
-    "dist/2022-05-20/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "304b8e4c493d9429bb8723a7e002a04405d2a67087cfd601f140827b8069bd4c",
-    "dist/2022-05-20/cargo-beta-x86_64-apple-darwin.tar.gz": "93583a3eb5f77ea810e5938bf5c172279122d4ddedab116da507256444d0df7c",
-    "dist/2022-05-20/cargo-beta-x86_64-apple-darwin.tar.xz": "98e75e460994b723c31a0efc7467b0ff59d57e08692ef472d95f66b5fbd57ac7",
-    "dist/2022-05-20/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "652e67a93015f18b66b9cf938c1d8465498024d5c9e2f1f00eaac45500e0c1ff",
-    "dist/2022-05-20/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "84d3d0a3bd0c8f7f68796cac7fa27aa7054fb47fee5199d1fd3d1dd62d80fe99",
-    "dist/2022-05-20/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "9316dec3a49621107945f62688cea261b85ea85bce77368a44d1e69e1afe7b1b",
-    "dist/2022-05-20/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "8abaf2a07bbeee46421bb2a261507cda1e4c50384b0cd1008754ae34bb2b89cc",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-freebsd.tar.gz": "17c47c467fa31e1807f76ade9e7b9eee991808b713dcd5f27f38cd11cd24fb7e",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-freebsd.tar.xz": "00ca9259f5f881427e1284f60b81a0b0b9dffd6f6b63428995ac2eb8d16eeac7",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-illumos.tar.gz": "c83811cb7bd17e612aa74218b260d4090a4ab375b3dffd6109b4544a2f0894d0",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-illumos.tar.xz": "c8b8ba1cd11ee76a909540132f44b9969273287231e6014eaf71e9b72bf6931a",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "77decd4386bf91bf39e9f3608d6ded89c88dbb009d685913d2e7f4ebc9d6d64c",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "6268bfcf05e9dfb5e0d24490e4150908a233536e5c76edc3506fa174c84482ea",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "68d689586123f3f26fac77436c8f760e39afdc099a6eaf3ab8e3e000eb5db195",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "dc2d76e52bf422bcc7e65b632252970659cb416af3f7f8e0f060d8e93d94ddc6",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-netbsd.tar.gz": "98389a862cef3f4b0cfe1e26dac8c125be4b138441dec3aa72e1ad2215c0920a",
-    "dist/2022-05-20/cargo-beta-x86_64-unknown-netbsd.tar.xz": "7fe62803ee7ad464d26ad33ffe1c4babce4dd129392c9b64ddbfc58df07791a6",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-darwin.tar.gz": "d45607fb802929f9b61a83348141f18ec50af949bb474d22c08431e2628a90e4",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-darwin.tar.xz": "978bab21c453918e00cd7a61741696eb34e7099da4a69c03ad9badabba62b9b1",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "df3e94d9f805a6424bde33d3a56c8ff849c1f697f7df2ff041718e0ef3b89721",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "60fa331aba8e90db42be0540c2f274355a662dab6d184484c5be1797eb56f6d2",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-ios.tar.gz": "3dabf5b1046221d9d3d933bab7c5e10b001173c0388a51324631420aa0ac7d29",
-    "dist/2022-05-20/rust-std-beta-aarch64-apple-ios.tar.xz": "d09cab1c57cc755c01d844da79a1579410e55bfcade5fbc5ecd74c5356278828",
-    "dist/2022-05-20/rust-std-beta-aarch64-fuchsia.tar.gz": "94f7de28d908e919ded94e3789cd2da7e13f86ec2c141134260b531627956fed",
-    "dist/2022-05-20/rust-std-beta-aarch64-fuchsia.tar.xz": "789019d7dcf82403fb17e3c833f708547ec6aec51e054b9cebf783a4a0dbba02",
-    "dist/2022-05-20/rust-std-beta-aarch64-linux-android.tar.gz": "f8d70b9f15b1177796d0b2f7fb3273e154f70601b638d3f28fd67058b714575e",
-    "dist/2022-05-20/rust-std-beta-aarch64-linux-android.tar.xz": "65b50ffc7ca059df5391d2eba3b0aad6fb14ca1ffec879e5df59cf220d2aa48b",
-    "dist/2022-05-20/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "04c897d04111dfa2dfcf236bbe460cf3839943ae2da2112b4a2ccdbe7f0a3f39",
-    "dist/2022-05-20/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "8a93c339b1bf9b861497101c9e35622fb750d6e0d909eee87d012c424e06d415",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "5664d843370fdf6d5460f8fd6deaaf6da3c019f6d11375a35952b101c0dbc0cd",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "051922c23e96812354a2a4ad46ec0a02e901f9bf1ad9ee1960aa043c2b88fb0e",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "26ee4cefcf20efc100d345d657c76d24b0cfdd404f1d20cfeca831a65565eab9",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "4e11588e86fcd7f80218cbf7d5fb3be2c54b7058f29e76b0cf26a3a72fa290a4",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1dd1f1c1aded585c6d202f4fe1a275caf96b5ce4fc7f0be620fa36a05fafc72",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "9103f4c7ff155671e5d2df6faaf4776b08fbe655f5e94928ace212b888aa6aea",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-none.tar.gz": "65a03cf02a1ca34e2235717d517dba4b80de6bfaa42434ab12e50fe81ec27cfd",
-    "dist/2022-05-20/rust-std-beta-aarch64-unknown-none.tar.xz": "ff0492a699428be3136c8050155bfb7960bd21d1e4b8a53cf3620365c36983a9",
-    "dist/2022-05-20/rust-std-beta-arm-linux-androideabi.tar.gz": "983f3505a4313fa90556ecc48b8a793d3585ca7a429a7dd837270e8161f6b34a",
-    "dist/2022-05-20/rust-std-beta-arm-linux-androideabi.tar.xz": "6facf6686308af39ff29c9aad192aa563652cbc697e4d7a43935ee9f965ffc8a",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c77e94254c7236ec9127f3dda57845ce6f7162569d6d124d72ce6d41c10268e0",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "772c7569d1da63842a2f6a851f9aa0adfbd9499b3596e77e76d82ac93099adb3",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "2dcdc29b939d651534664fcdb1653933a2500dc98ff59b90cd988fc12f4832c7",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "a75a25b06820990b4720a60caa9d4f4b4b5a85a34078b552c52380db4239756c",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "f75de884f9219e2cd8a233b80c1aaedea1fae5a7d7b64a899b1c067c5072005e",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "69c5795861212db53e2761319ea2d408a80aef8632d8c55748be49d648a42c85",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "2809b4223232acaaba171f3d7551ac581ae5e5e848abaf7fcc0b859f04ccb830",
-    "dist/2022-05-20/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "94d389e8bec1bd6037dc1dfcd2758aee3d831ca037827018779a4da5e07dec53",
-    "dist/2022-05-20/rust-std-beta-armebv7r-none-eabi.tar.gz": "589e78687bafb13eb5ae1140c21a23b26fb549671c97ecde5ba8bd1549508ae0",
-    "dist/2022-05-20/rust-std-beta-armebv7r-none-eabi.tar.xz": "e9a81de6ceca0c0a38135e42a0ab92ab05275b594f9c03422c613f09d754054c",
-    "dist/2022-05-20/rust-std-beta-armebv7r-none-eabihf.tar.gz": "5805e2f656f1d5aca95977d82dcf4d08f073e3639c965d35df8e74785c29f158",
-    "dist/2022-05-20/rust-std-beta-armebv7r-none-eabihf.tar.xz": "64baad7526366882ae4aa9b837c9949b8382e2affdecd5dc514aea141a755804",
-    "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "be7e91e7c96d2e6c7c11677f6abbc92e6efd16941a5307baaa1d16b91d527fbd",
-    "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "bdb77d554f7971dbc2a42ddeb6ca4104344ef00dd803e099898ff0c70c47d165",
-    "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fa12aaf9db48d22dd3e2dd025a1738badf92ecb0659ebbbf9a530f909ce569fa",
-    "dist/2022-05-20/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "c9eb5998f89efb8bafa247a36b9377e6df06a6e0532bc3c231893d9917840180",
-    "dist/2022-05-20/rust-std-beta-armv7-linux-androideabi.tar.gz": "cb0d6f97d5f688d2e027e325af383274cddd78a890363dd78234cd249f33a274",
-    "dist/2022-05-20/rust-std-beta-armv7-linux-androideabi.tar.xz": "82491be82ab194aa8f7138985b0f071036c717b012f45c366b01d2d176b8b700",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "2805da58cbeb8254184bf652e2bc761bd20affd083473538da90386259885901",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "d04641e9efee308dc9348ab0a10fc297e9c2e1981dd683285b4b908279e07b94",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6c1db32221e1b75495de1730e7aa4c705cea0849bb5ce8ff297dc7cbe2cb22c6",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c7acf447bbb3ed25c7d97558787496987c9df8e628629b2ddb5bf47407af6bf1",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "32446694a280adde3224466f0b0d8dfeb88cee5d480f51ef324847189526ac87",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "43c54c38c7cf200d0cf7c0c9319ef0f1a21dcd700e0c1230dcd144e15361833e",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "c036a956f0db31aa089e1da0cc9deda358bc2ec3f6cad02061ba7e44e03c426c",
-    "dist/2022-05-20/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "90eee1c9a8150542beb429f910219e9eecd1b77672b29c5319b070fa5b6595bf",
-    "dist/2022-05-20/rust-std-beta-armv7a-none-eabi.tar.gz": "7472b16814ce29a30af4be48c0ec2711e590999521d1a519a6f12168beddff7c",
-    "dist/2022-05-20/rust-std-beta-armv7a-none-eabi.tar.xz": "2d01cd24d609f3f0d4d126dc4a966b0360144ba0234776e3586bf466a8878627",
-    "dist/2022-05-20/rust-std-beta-armv7r-none-eabi.tar.gz": "25a2f1bf856274a899fef8579a8b6efa816333fc054fe3e05e0e5d344d35977b",
-    "dist/2022-05-20/rust-std-beta-armv7r-none-eabi.tar.xz": "63bf6e02d710511d0f3aba7b692d5f5f66a670ea78922310f5469bf4027b4ea6",
-    "dist/2022-05-20/rust-std-beta-armv7r-none-eabihf.tar.gz": "0077251287e4ba5941744ce767a13c7223488488d6351ed22edb272c7d4f0153",
-    "dist/2022-05-20/rust-std-beta-armv7r-none-eabihf.tar.xz": "8d516d72d1315350b977057ba16aaccfce5ceeb7a5038e12071c60bb108f0b64",
-    "dist/2022-05-20/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "7b722a519009706c966c4eb6174fba5e858066040cbe72f6f85241c2b5ad0fdb",
-    "dist/2022-05-20/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "446bf5b91e4a8cfa88b788dedb273d9f315603c6db635df35c137a860406709c",
-    "dist/2022-05-20/rust-std-beta-i586-pc-windows-msvc.tar.gz": "b800024142e8239741e6ae2ed2ce04221699e4c688ed57cdddad4e71acc7f70b",
-    "dist/2022-05-20/rust-std-beta-i586-pc-windows-msvc.tar.xz": "de369ed404dc314d13ee852330718fa0a5166a255cccc7475636d5568e39398f",
-    "dist/2022-05-20/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "bda798e76de2751674b02c5621d077bc0d6988d97be6943e348ad69eaedf5626",
-    "dist/2022-05-20/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "990e63391addba79972b5cfcc8fb3a9a5ddaa6bde69816e3f55844d1923306f8",
-    "dist/2022-05-20/rust-std-beta-i586-unknown-linux-musl.tar.gz": "2400768ca0b4324d1a4fff2c9333296729b62beae4ea818ab63994e8850c6a7e",
-    "dist/2022-05-20/rust-std-beta-i586-unknown-linux-musl.tar.xz": "6ccfc6fff1738d3622f6395205dc3665f604bf91812683cdba51f72df0a81c01",
-    "dist/2022-05-20/rust-std-beta-i686-linux-android.tar.gz": "4511c2edf4df83a10b5953737f5e048072b0c1419a49bddd8518a5866026c3cd",
-    "dist/2022-05-20/rust-std-beta-i686-linux-android.tar.xz": "d22d2cb39b861dcec63d3c0f0a46367e0c4a3dee03fae2fad8f8311ce38b72dd",
-    "dist/2022-05-20/rust-std-beta-i686-pc-windows-gnu.tar.gz": "df4abe458226a5812bfcc382e82d1c1432bbbf4c14501121397eb26b2f1b37d8",
-    "dist/2022-05-20/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4416d4704bdfa42213434f8b1272a4ca20ea461be0f15de581e2e79af8837ec4",
-    "dist/2022-05-20/rust-std-beta-i686-pc-windows-msvc.tar.gz": "8ff11e61449c5a4e7395f9caa803057ac630259532efb666921a279bd32e09ed",
-    "dist/2022-05-20/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d31c0cfec27086ffb2f257b204eb6fb2d8950c73383137be5590ad39e3473d5e",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-freebsd.tar.gz": "0461fda259436063bbb4605c6c933bf07650091e745e0e435f0033f315177a70",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-freebsd.tar.xz": "7c781c344b2d11a46fbfa5166645b8d851d7d7d1a8552b53cea8ee0c09098a9a",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "2cb9052d6a9e5cadde06c45dc97e2fac06f6aaa92a04cf83599944d8f8eb2d63",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "3a17856fd2c95553e0cb38619dac7417d9aa09d2062ed20aa230425e41351126",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-linux-musl.tar.gz": "cff1e6bf0f2d959d7ae18975e0f453b801eba70a9f1e28929628e57e5fbe3c98",
-    "dist/2022-05-20/rust-std-beta-i686-unknown-linux-musl.tar.xz": "27507f85b579e2cf6f405d45b5efd91719d4d13cfb2244b81a198b6fe1eca9a9",
-    "dist/2022-05-20/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "b5f0992efce6efda759f2a05c2f87218c3831d26ef1a30629bfc047be07a252a",
-    "dist/2022-05-20/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "125ada363a57b69def167673791877213128fac96ca07c48b812922c8032797b",
-    "dist/2022-05-20/rust-std-beta-mips-unknown-linux-musl.tar.gz": "d0ecdf9b14faeaaa1260bcabe76c4b0f6e7b6b81d5efb920fa7d0ff4c2ca3320",
-    "dist/2022-05-20/rust-std-beta-mips-unknown-linux-musl.tar.xz": "5b5b4df31260e89ad4e3f927c1999e716b6b47a6cccb9e4e9cc8728afabe8af8",
-    "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "03c9e0df29ac2dc87ad5f10f1e4ca8e1faca86e9db1e14dc111ec6466c18e3d9",
-    "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "71e3e3f092c20a782873f0ccab896c825985dd37382d431b19be104356772a1b",
-    "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "a3d5b7d50d3df53072de703a86e45f7d933449eaaba1da5d99ec62432746d4fe",
-    "dist/2022-05-20/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "0281d7f8325ada1b46ce077dd1466a0dc60e3ed2fdbc187d3e3d709fe1971fba",
-    "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6a88c79fd895450425f110346c9edea479602179d743b52870e5de63d136fe5a",
-    "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "57648390e7a58188cf53578733ae7e6b56171457e1f733ab53f2b33817201a90",
-    "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "1367e998ddfe049f0c7127076c934000aae07739af264b7a42932b216c968a79",
-    "dist/2022-05-20/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "08eea3c826005e9c0f3017c71200e25c360dc72906e14a1460692230557b40d0",
-    "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "1c39e3d2296a35c9ffe50cdacc804ae6c8f2cfa07b1fcb62bd054fa6b5ed8d79",
-    "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "0390c75c7e685ba962698a1499cdd4f4bdaa5557a3e1c18f978d9741906841b2",
-    "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "913baebce845df4e6f31904be1bd983a677fefdcab37b60e1dd3dd2ae8e8154c",
-    "dist/2022-05-20/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "327d3fbe131028aee1c29ea3372e0cf38a4eb8ef34d536efc7f804c6d5f40ab6",
-    "dist/2022-05-20/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "38800fe3874563ca61643fb3782c54e369d6731454520e1245f24daf60f6acbd",
-    "dist/2022-05-20/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "23a497126301502347dc35a75cef01f31fe994879b04862b571432e1549be85b",
-    "dist/2022-05-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "2bb6b51cbd83f3cc14e00bdc2133a14e0abe735cad30f7e1b001535784f98dd5",
-    "dist/2022-05-20/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "02894b90eaed0ae7712c3818498800a0da089969c3f9ff21d309aab6e47e857f",
-    "dist/2022-05-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "d889d93be28ee0b28832543691a15c2849726ec87dc3fccaea9465f7447f176f",
-    "dist/2022-05-20/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c980f3a1d45cca85fe32123dd142776d4b6684ca1625f6e1d249ac5d8ea27d6d",
-    "dist/2022-05-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d3e8359eb9a35ac442a613f6fd82e8d5c9d681e8af7063798227eaab3e72604d",
-    "dist/2022-05-20/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "eea426cb15d15a0eb06e9c3b0e2e96cd2626c9f50d2b185c0c99d5aebc9bd3a5",
-    "dist/2022-05-20/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "d0974d9b70b464ae3172c15e8fb304424b591d7f06dbbf49137a80819ae7334f",
-    "dist/2022-05-20/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "30bc0890da242ea54cfd498cd45c0616d3c1c812b92a149ac10881e53d976295",
-    "dist/2022-05-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "6c33e98b2bc61aedd5eda2a321f4e7e94709709c450fe0958197cdc82b2810ae",
-    "dist/2022-05-20/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "43cabe1ab3c37c4d62286c0e9ed34eb736c63d9fb4c36199965b10b20ca80b85",
-    "dist/2022-05-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "59ff30ca51024a6e1bba2171ec48af591acb03359200a0c1affe7834e02052aa",
-    "dist/2022-05-20/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "5d1ae0d7fac3f2b0e5192faddbd7c78a1a8c08faa056750625043513bc6235fe",
-    "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "86a083dd8ac10659b70db9fdf6d26b4d4c17a170582ae42d58d88840e75baf17",
-    "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "284144e4c8bb3dcfbbc67274b78db1a9bd0945bac757b99b2bcd1c365d7fb020",
-    "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "0f3c7ee9df5a967f1cee60a41c5f0e6e52f47c30b47f2e0b55efb0c05c0817fe",
-    "dist/2022-05-20/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "4ca5336d556f9b925731f1f39bc644f7393faeedf6abedce2ed0cd30736051d0",
-    "dist/2022-05-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "37e9f9dae9ef0fea6bb223d62cb4090549a8f0ea8e316729204de87e120a46f9",
-    "dist/2022-05-20/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "295bd6649e36489b14851002f082621cb5f2eaa7a1ab99dc7553413f50ff9e48",
-    "dist/2022-05-20/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "e0eb8ed3f1e078a2b0061f3f73add38a7a5d977d2c1545d1d1c6b7432efccbfb",
-    "dist/2022-05-20/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "3e119885f8d9d72e3cfeacca1c0bcd734000a61d0b3336d3010ee306650f78c9",
-    "dist/2022-05-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "ecd2046ead142d3629a5a0316e56dc03df3cc9e995fb1ab9e347d0dd2f563ee7",
-    "dist/2022-05-20/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "4288ee173cf81a72b4f9a45360734bdb8c880de7899cbe0c990ff3ec1cb2ec5a",
-    "dist/2022-05-20/rust-std-beta-sparcv9-sun-solaris.tar.gz": "4a7090a8d82f1f2c46437ad38c2659deac691c2fd179bd47ecdecdfac57a72ea",
-    "dist/2022-05-20/rust-std-beta-sparcv9-sun-solaris.tar.xz": "17daaaf6e17a237a8d4effc1ba09e50feeebbe21dced1f89249dc116abc141ff",
-    "dist/2022-05-20/rust-std-beta-thumbv6m-none-eabi.tar.gz": "7a7bf1342c8ab564ea29f7745515c0272435704ba1f9bc56875fbdb957286231",
-    "dist/2022-05-20/rust-std-beta-thumbv6m-none-eabi.tar.xz": "5ec32ef9e0633f78c5f4f74c7e572749c523c8e294fd0c3b012925ee871a2cff",
-    "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabi.tar.gz": "36ff832f4c190ceb2f5d241ca45dc3137fe0dc1c111fa70d310908e1ecfcad86",
-    "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabi.tar.xz": "dcbf2a0e4da89ef8fd60b9e334c3d6964e795a949cdcdbe90bf5624124979076",
-    "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "299b6c26d623babb5720962b5b08a7495514373646bfcfe25f32f1118a149d05",
-    "dist/2022-05-20/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "dcd19b9b8d52acaf36281d1927aea01b581c62d6575ed8913b01822cb36f73b1",
-    "dist/2022-05-20/rust-std-beta-thumbv7m-none-eabi.tar.gz": "0f81c759b3843994f01e00e86f0fb17f203be11d085e6e118e0032215cad0366",
-    "dist/2022-05-20/rust-std-beta-thumbv7m-none-eabi.tar.xz": "ef240ba96fc9c1cfc87e49d562d34e323bbd2b703ad72416189d588800993798",
-    "dist/2022-05-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "9e6f2fbd877f3549caf65a7bee05dc338939775b9df3e55b3261aa56ebb783be",
-    "dist/2022-05-20/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "23e81f67930983344401785226c5e52f02986b8d2cefc580cbe3a39727e8c190",
-    "dist/2022-05-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "1a34d653ada70fa611e159d4ceec689884ba1a5f4c44822d0175c7a7a37a7de3",
-    "dist/2022-05-20/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "eee5b5c5a686f8de92535cd291c0ecd7ec861033460ae2f2dd047025acb10f27",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "56cfde72d635c72648d6bac79a7a9dbd1621474804df82b23cd6e4b3df327f6d",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "105a3991cd8d9013b22d5bb6bd9d8bb1a95597341c042985a589390219a1cb22",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "0ae3c43289f939fc8d0fe365bc1bd17e3adaa05942c4e6f65e989de925bff5e5",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "be973d27b5a73ea40b60a8e1b281323ac557d35d0f20b69eceecd89c98b6a8a7",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "8630bf9e2082512441961ba0e970dcf1a2cec2b957938be3e671cabbd98fc5e3",
-    "dist/2022-05-20/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ff33377187bdafd55ef8eae0a10255a306e7e0ad06f8326c26495169e7099a6c",
-    "dist/2022-05-20/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "a6b50581a4269fb83accc468f5f6fc697ecb0060852f3c1aca347465bd9631f4",
-    "dist/2022-05-20/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "1a9b35e8270048be5e44ec318669acff1c1348d5086f43d67d230be7089db920",
-    "dist/2022-05-20/rust-std-beta-wasm32-unknown-unknown.tar.gz": "bb01aef0726534fd606456e38fc999c6683555bf8fadf1a5f390491a8a288b22",
-    "dist/2022-05-20/rust-std-beta-wasm32-unknown-unknown.tar.xz": "36b0f7c5bd3ba18e1a32dead937fe0bb3d28c864e2aa3d4bab4bee61ea6730a8",
-    "dist/2022-05-20/rust-std-beta-wasm32-wasi.tar.gz": "188265a7ef61ce9c3676ff28edce226196945b681f6ad333837759a82a2a608c",
-    "dist/2022-05-20/rust-std-beta-wasm32-wasi.tar.xz": "5abb86cfe2be1d1b631f33b7601dd66d9a0f7aa01a37c88b3eafabf49bab84a5",
-    "dist/2022-05-20/rust-std-beta-x86_64-apple-darwin.tar.gz": "b605e10547a5a82375030606986f8ca69c4c03e87526a6eb4ef967ed173d36b0",
-    "dist/2022-05-20/rust-std-beta-x86_64-apple-darwin.tar.xz": "70274d4a46996db65c40cf2391d162fe09426b1c1aeaa988f48bdcc39740cad3",
-    "dist/2022-05-20/rust-std-beta-x86_64-apple-ios.tar.gz": "494b20caa398346eddd66a3df6f10601d96dac4204c7a235823e4627534111d4",
-    "dist/2022-05-20/rust-std-beta-x86_64-apple-ios.tar.xz": "1c62f0df4b9b7661c4dab30f501bf01956934480d0d47bc9d0be591e2c73c8be",
-    "dist/2022-05-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "4083489fecd16a34541670a2df9e5182fc0a15b6204d0a9af973676e691e49a6",
-    "dist/2022-05-20/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5a65b9d25d04e7d0fbbadd188fbb013fb1034fe273e2b85cebaeb6aaebe06ec6",
-    "dist/2022-05-20/rust-std-beta-x86_64-fuchsia.tar.gz": "447eff000d01bff74a4da75b12317979adb07e21a6a81c35170f5d9e7dda8419",
-    "dist/2022-05-20/rust-std-beta-x86_64-fuchsia.tar.xz": "34e6f5225985d454d55f9c22828ab46cd560c7108e259a6aac0e9932d079c7b2",
-    "dist/2022-05-20/rust-std-beta-x86_64-linux-android.tar.gz": "67478f922ba588f4f0e0fcff23e254115898266bcb8868ccec8494ee680af6f5",
-    "dist/2022-05-20/rust-std-beta-x86_64-linux-android.tar.xz": "08c3330a0b25365e8c7404119def5ca630a370e832a0dd62c54fd2409be96650",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-solaris.tar.gz": "e293bed46bf31439f8a87eff36046a12c439b1f6f8c7a67030b44523999b39b2",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-solaris.tar.xz": "0e03e0c918cdaf94a33ad8225b483e4174085239ebe406d906a4cb95b44d227d",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "73d66833913d4606453b89b7f72b5b4c417c9baaa09b854c6217441b5d8893f8",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "6500d80a332e27d235d562dee7d48a0baf05876595d813818f46de61ef75f60a",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "80459e06662ca8789ec35793832b0df912b51ede0a62c46f52a3fd2a94bc6488",
-    "dist/2022-05-20/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "14a073ddedcfa34ecca58e53467ef874fbed4eb10003f3b2663f49c77890418c",
-    "dist/2022-05-20/rust-std-beta-x86_64-sun-solaris.tar.gz": "f3939d1e526f9cd8e1114ce9f4521c563d4e4b43f2f6889c292b2e02bba79c0b",
-    "dist/2022-05-20/rust-std-beta-x86_64-sun-solaris.tar.xz": "65ec686465eb4d2b3013da46cc83f1f80cddcdb70d8449d423464368c024881b",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "878f6de25e6934c91138a2257b81338a0da4a83dd8233d2ceff2e26e9bad8bad",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "ffab6364f6af477b074774a9e1915636f07b0659231c61bb7c75cbde31277986",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-illumos.tar.gz": "52b0580aa5a036526100b6032e104f1f790c1b7346494ca44f017cd8957aff07",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-illumos.tar.xz": "58da0d760adc61b63d72851ae602927ac9c71795df103a6b6342f210425eb5dc",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53e3312b8f96723319f791d54a3215d427fefaa353485bd7940e1ffd875bdeb2",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "0194620a7501c555d157b37759b1d97c35a78a5561cb3859688ceb12184e0636",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "17939ba3d5aaed0e79246378bdb2694e830b02b4c56941f7cca30400d3213d09",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1acd94d6881951001ace4bf76c46775199097710064d3a0da03cd5979d23bcc8",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "bdcd08dc5dff810b28ca466e4984f1ef2e8f079d233d1b9933ac719b9a2e5a14",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d7629d65c4908a7a74aedac7f7fa52c2308dcfcd6c8e541a0fa418dff3304152",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "02c2e64930f37200125415e7212577cf25dbd5c76929bc629313e856960beb68",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "2fecb5336a79c62cf1e17df7d65604c3df19b8cc9c490a2fc918dac1ab843989",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-none.tar.gz": "b37f013037673d8f405900170d3c5c94476946df6c6eaea9e3f98354e05ffb22",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-none.tar.xz": "53d4a5aaebc4a8fa39ac5157a90dc80ee168df51b70f21e01c26b20d00df94dd",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-redox.tar.gz": "d7e8ef1e4655bcfed48081cd59b78d08585b9c9141601128efb8081ec908f2f8",
-    "dist/2022-05-20/rust-std-beta-x86_64-unknown-redox.tar.xz": "8117ed18c3742af2c9f193458540b700d2eaeb98c7774b52942fca3a605e98f9",
-    "dist/2022-05-20/rustc-beta-aarch64-apple-darwin.tar.gz": "5da43198c82b323534fd7163e202daa6256dcd2ce1c6001f07f1746c43738216",
-    "dist/2022-05-20/rustc-beta-aarch64-apple-darwin.tar.xz": "35fe159afe40b969f948590313be24f3c626e6dfe53211dcc57ca63d930903b9",
-    "dist/2022-05-20/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "878aecc6259747dbdb64b62eb741ab4c77215475b5ba2ab707be772f33c65370",
-    "dist/2022-05-20/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "e43637e5ec68302e6d652b1296fa86b5dd0d3163298ad7db298b2185d2faebad",
-    "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "496ff30ba1820bbb27d62307e1e74352dfe39fdce5be1abe96370df059507131",
-    "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ff679573cac7cc417ee90773e378453a41f5a67ee422957d03293e90c7ccd0b7",
-    "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8440a56c20b9f999e577c30c04bf57500b1faa5f4d6794cdf94682202d072f41",
-    "dist/2022-05-20/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "318569c2e30ec047f870727f849d07e21133f04ce9d9f6ef71b6db91745102db",
-    "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "ef226baa0d484a8a4426570f8556e50ea0d6cebe4cd8662b78cdaa6b32645712",
-    "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7aeb63e2390fe4043a047bf1309f9e39dcbe7745540fbdff4572b24d5e084ea8",
-    "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "30f65131a29bb094eba2d8d7171fa6da8159d4d8f33af6f930b605119e393563",
-    "dist/2022-05-20/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "70555b5fe9ef11d6aeda526832a187be3e37cbffe9757b2d0690f2c0673057ba",
-    "dist/2022-05-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "55d7031a9e47b9b782c4ab2c8c4b2c4fe98c44eab6b0c059236a1d1c8dcfd0b8",
-    "dist/2022-05-20/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cef673c540259008168a8f23bb8a6574196f4ba8b802c07f5474f6fe733667bd",
-    "dist/2022-05-20/rustc-beta-i686-pc-windows-gnu.tar.gz": "8598a985340414f8176728d79d6ef602fb3283668b2bc3f1e8b3933e8cb25030",
-    "dist/2022-05-20/rustc-beta-i686-pc-windows-gnu.tar.xz": "2df61a11a8f688a4f3bdb7298f3a7e929a2c737295414c033405e5bf55522729",
-    "dist/2022-05-20/rustc-beta-i686-pc-windows-msvc.tar.gz": "280894eb39a07ef35c2eb76fab8e77b25b54bbcf4a03a49e21edc528a14912a4",
-    "dist/2022-05-20/rustc-beta-i686-pc-windows-msvc.tar.xz": "01260ef26a28c21a76187cd84a7d1195137d3f871d51e559422dd017f8cc6920",
-    "dist/2022-05-20/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ce35952f8a49a4f2706e8fbb62e21d5419f90058b66b057e669f69c522bfbca8",
-    "dist/2022-05-20/rustc-beta-i686-unknown-linux-gnu.tar.xz": "32dc234a4dacdddd80cd23c9e64d2f45b1854651493958f0789b3ea58800d9b8",
-    "dist/2022-05-20/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e5b1f27084d8082840fa76222e48b1a55c28209f100cf55769375e72ee5f7298",
-    "dist/2022-05-20/rustc-beta-mips-unknown-linux-gnu.tar.xz": "8a56067a0c6910ccc822f87b7eb0f12834d00c9840e9a937928a519093ed5041",
-    "dist/2022-05-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "fc51757845b46433ff6a53a2a783df1810072a456c9611c7eb24ccd97a99845c",
-    "dist/2022-05-20/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "1c29e7f1519275a88a48ad2687e9368e4633f9bbc6b1467dd064000a6315163d",
-    "dist/2022-05-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "29cab4f76a3b2c916280eefd8a72b9b9014174b2de8cd62f18add7207f387821",
-    "dist/2022-05-20/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "eb234b6bc941757ad31f5f4ae08083846101697dd8ff2ccb6f62a728eeb0a4b1",
-    "dist/2022-05-20/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "107d59c38607e0b0c4853d08b5a05e1e7dfa01a1ea42eae88180b27d0cade79e",
-    "dist/2022-05-20/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "248a58d873bf4aa9872ebd7b1d903f84f713266abfa40c2f24b2a2125247f2b1",
-    "dist/2022-05-20/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "1b91a2ccae1eaf8654d5338aff78c630bed772b6960349dd54b71a769e1fb7da",
-    "dist/2022-05-20/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "4cd2421996965d58cd1318761301b2a5b9ae852f5518091a27eb64818f5b6982",
-    "dist/2022-05-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "c892a97b55f6f67803f23f1a59fe084a06f31973cb8ee244836c00210a323095",
-    "dist/2022-05-20/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "774aec0f0543255e948ce3aac921b7d1eff054aabe5478c285e08312b4fb0023",
-    "dist/2022-05-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "deb42e8f3e18206fc4795829e13f68be17ef7074196fe4880addce40adbb2825",
-    "dist/2022-05-20/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "502b33478bdc56ff705ef4001c59017f6a7057f370d388b42ca697aeef696b3e",
-    "dist/2022-05-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "4bd2e1d502b9f0b6bb1672c94c54650e63b3b28845be4a7148f6a15e062a4c95",
-    "dist/2022-05-20/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "51fd5c0841d6f9881a6f1fdc3b261a085eac64a5521546f2b18756cae4472e15",
-    "dist/2022-05-20/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "209fe3fbf4632517921723e67857c1697e6cb0c8b56ecd8678205909b586c156",
-    "dist/2022-05-20/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "27c66acc0c71d232d0c43ad15a8953b34dfadb87073727eb1b574b1debabb9f8",
-    "dist/2022-05-20/rustc-beta-x86_64-apple-darwin.tar.gz": "bfb46c4a6864fde3b4edf3500713d423404ef39ba8849b229e823adda5a638a0",
-    "dist/2022-05-20/rustc-beta-x86_64-apple-darwin.tar.xz": "bce0d4dcd41b8a4d79718238355b0fe682b83620ebaf4a134fe5b7e7c2620c32",
-    "dist/2022-05-20/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "6c281db4eaa67c74bd07e56efff6fe63e750aa9a5dbd92edbc86c68f69964381",
-    "dist/2022-05-20/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5c4f1bd38095e9c34c5357a76fa5090bf82a030fcc1b18a2935b9fabf02f9f57",
-    "dist/2022-05-20/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "0e4e6b6c236cf3ed4c5de5ad909f060bba6ba9fc41aa3d5bbe72d90a7a3c8976",
-    "dist/2022-05-20/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "a526b05166251ddc646961388e24827c05b86e7d61d8cbd0015f6a98b742f9ea",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1cd1d3a1a37bca47f7a00182e5c0a08275091a8d36771504a84052c1a72dec4a",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-freebsd.tar.xz": "460aa68d922df97fac6d6052a8680d514fd4ce32fca7c44ae22d7c05e0c5b51f",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-illumos.tar.gz": "d992c3d0b088d359dafce1ce143e698b81c5bd49c9537e035ad8734fae7ba671",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-illumos.tar.xz": "28234a4d0417b1d7bb112775fc3827115777d288a6c40628d234f2724c94a8ba",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "169a34b8288c5cb9d79c225a6b890d936942ceda046823b50ffc8c0ba6dc9d1f",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "9a4963614650e4f3d7a24f4e89f100aeb96d8faca3ab9e912fc66d92364c50db",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "493ac76b6e2324a4c0ffc7136f22a6b5c651bd464b240814e4de42d2d52db737",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "f430f5eb951d367543f65ed9fdb7de2bca8e8f06b6f7c10c8a97a35f9787ca39",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-netbsd.tar.gz": "ae878bc9dc0d7788d2098cdbf5b564a624b1bc1419f8c0d574f5fc3a0cb13511",
-    "dist/2022-05-20/rustc-beta-x86_64-unknown-netbsd.tar.xz": "de65cd47cb84cc446121cf85af77e8f50e8e3ce82db1fc66c88686334b8541a8",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "016ff92402d8095a9a58e82dbe435fe5b8f64ff63ecdbc8b48968f10f8c94947",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "7c2c2d3a6cae8633d0013312a1dcf24e583261ff88f582760df81c298d848cb0",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "e27dde14fd9bf882e8714628de56e9877c56d31d889c7d2ea03713cc8158a4ff",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "b58836984c2fd54054fe436fc49cbd7570bf6b1534ef030acf29e3cc4c70d58e",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "33dacee51735139ace6af54c853304ef2d9f3917eaf5c84ebb69ca3555d23c42",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "2ea9b4e7a0fc641b1fe54b21c415277e43df9d7a958b0c3b02f60b38a06c8ebe",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "829ca9581d19adbaad12a77d1e318bd5d08daefc928c6c6a48f3b5276039b518",
-    "dist/2022-05-20/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "e9a8030c2a065da4e0ba61b57747cd8dd40cd3d4bfcf8ab5873618620dcdd07c",
-    "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "e2e389076858a5fdf02c85d036b07c3fbdeddf1b526de8d8e72223241cf2f5c7",
-    "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "21df340cc4741e1b6265f67e8068e81e255fab82f1c18070b24245e52022753d",
-    "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "681b47f3e5cdead36f12ca8af4b996d4aa90e4ca471c604de13faa70ca22258b",
-    "dist/2022-05-20/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "e842733f877c401f55924fa1c5c608087aef9901c79664afd4bbb53e6af9e46e",
-    "dist/2022-05-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "7c43e97e824fcb2595b416f50cf3bfd6930f3fd066e8d27673db478ec87667d1",
-    "dist/2022-05-20/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fa13900df7709c8258d7e2ecfd5d9d4a620af957604d2544f5114ce9333961b7",
-    "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "7378857f9d524eff3fa81f7724b687e7b53f686c22bc40825bb9df06e5fc2652",
-    "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "6c4cc08f7474e3415b78dd5f3c7554b6af7af3e9c0143cef24dd2803b19bfa24",
-    "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "b75b7226c3601d6e3c701ebe4e53f042754d9bf37ed933548093a2de782b4e7e",
-    "dist/2022-05-20/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "628ee041610c8f70a7e033cf5f997cee0974dfebefbd2867a4b55aad0e72ecad",
-    "dist/2022-05-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "62e1293032535dd706efea3ed395da3756ab2db74b1eb1aa12333f9d3cdcbe20",
-    "dist/2022-05-20/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "0b4bb25aabe8915ef3e3ef5822dea1ce55ea3f07e2196552abe058df91600722",
-    "dist/2022-05-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "aa80e17777a3b5eeb94bb14fd42df24dc0a7fd01d5b497c8ea904e2f8990ab20",
-    "dist/2022-05-20/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "a18cd7d9bfc9b51ea3cf722a4b6da3897bbf29710bb837bce2a493601210c749",
-    "dist/2022-05-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "5b50d88dcede9527a133352a0af57609f5ab035e5080298bc6e4472dd8def994",
-    "dist/2022-05-20/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "5f7c9544eb83dedce2c0f34fa4492b68453a49ce69dcae6d20b23e4f5658b674",
-    "dist/2022-05-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "d8282c23352c4a84da032af5286e7d4dd478c721efab1a87a0c6d78d5b810cb3",
-    "dist/2022-05-20/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "8b6137beebe10ada8c152edd6d2e59c8e348b79cddd72d55704e65375bfc1363",
-    "dist/2022-05-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "5ee13136a127ede81125cfbf3cb5a5e01f4c628f6905964253555ba93abd7d68",
-    "dist/2022-05-20/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "44732a16066b78ff12c87d09bd4e409630c16e89f6666e4d0feb4fac7291610c",
-    "dist/2022-05-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "c5c4246bda76e04f9f6e0d2bd6b9d0697da91a5714b5bbcd20f005f51c2133ba",
-    "dist/2022-05-20/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "62aed94d82667d952a5199549d92e10ef3b0fa0fca50cca1e1ef8148939de7a4",
-    "dist/2022-05-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "5cabed546a4e47408870815df117d1679eb55498d124d74ba59ce5d3a2365856",
-    "dist/2022-05-20/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "27eadfa90c307e32b7bde08935a3d3f6710fe2c134138f8972e73d52fd42f2dc",
-    "dist/2022-05-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "d0b9466a62f79e00000e53dd23889ce148b157b2450b9cdcf072fa1d0ef0d9c5",
-    "dist/2022-05-20/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "b18b418cdc40a46020ed4b4bdc001d1f53d564e31b2d7163c4b8d4c2b0858cda",
-    "dist/2022-05-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "b1ebacd2f47471dcbb2d4503de85cb89f30182842ca985aad152ca7d58ed990f",
-    "dist/2022-05-20/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "caad69f3c84bab683907252a9c50b7d54ac61062282e3eb5c5033f2bb8611cac",
-    "dist/2022-05-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "afd79b45aaebafaeb4de5a8e018549e5d21f37e1aa025943103264ac011296c6",
-    "dist/2022-05-20/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a7c5e50b4423800f489386f1c049190a79a34e472aee932193f32577321d94e",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "7d85e16802a0c38ce2beac5ca01f9921e9ca1df5bc413bfc8d129143228bdda9",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "7ebb79d71ed525e6324ea7e1840fa88c76a37e8082ada2a02532aff696b2623a",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "823bba430cd01425c207e1ad58689b1c79143d4365dce40322c59462d658f3ab",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "13b92baa7393f6f2a2e6743366189a6518f2233de98a09c3d7a1f4e3159214e7",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "ee9407a567b12a4fa6b0c596d1a775d45d016badec8f9e73ef66ff324aba0d87",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "7cd8f5b0a256574c04b4a4b79e19a53899f89884c3f34b11ee6352be89ced09a",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "9a40bee5b8ef9305de4075595ccb9b698574cd8ca4d355b7474ea7009f7e924e",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "80a5d830e5e2750aa9b1c5e46cc1f97910473cca0ff20a93a5b81d5c664431d0",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "b3e45e2b6b984838dd156bc00d0d9178793d1c7a895fa016bd18f1c15fb65111",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "dfbba7787c57cf47b75033b81523de52c1be3072a1f68564e9bf5f93378d18a1",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "913000f2bd4787ebf301d7d0b80cd480d4afd362f3728c9886ef898b0286575f",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "7ebc5f8f6fccb5eab1eeffb724baf320ffebb653bce813841115b7e67144b2c1",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "6a4550b5a5dd7d91f9767954c8a7fab31e3a782d34d524823f1add8679b19a26",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "b3e9ab1bd65ca0957235f1ce946c7893a5c1ff4276193ccb1763819ae1e053b0",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "b52a56a4195e41496b9a96ea41a05f9fa27b3c47851ae3aafffbd37711a522f2",
-    "dist/2022-05-20/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "accd31a4772443dfa87121f30f501a53cf8f2be5553b1d7fcdf0405d2baf2149"
+    "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.gz": "8e50ef7a6fbc0e7212621e124de66d123b9c772a04cdb04b5528cb68543f89d0",
+    "dist/2022-06-29/cargo-beta-aarch64-apple-darwin.tar.xz": "f74e110c8740321406acde67c37fc3dbb47e9d98e25bf20f5ad19790b89b9b9c",
+    "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "14067f4013c5e112531ee4f76e7ba61149b46a67d1d8bf0256dc2ee1410f44c9",
+    "dist/2022-06-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "9252a221a244308228a16f5e9729755d9f09421e2e316ea82f64da1d9a8c4725",
+    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "38c0b9186fb251a6ac15ced667d3cd719e81acc0eb7a92303c6422c92b701842",
+    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "b328753578ecb5ca9578f9ac89107804249eb4f802ca0f07c9bdd063aab931b5",
+    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "747d836695e7a385e6af22911966f72410abafe8b400b33690804e4290e750ee",
+    "dist/2022-06-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "94cb8c5e70ba4da6de86777c3c2092ab0616da9d12fbff6928e901fd6c48c099",
+    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d3fa253a3a470d65f726dd59201c3b6e90e8d2343d3b5a1d27ba395d16ebe025",
+    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "84f4684cb6e86e58279b768e8cc00c55da09a0ee8cdad77dfe4153748eaa3b60",
+    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "58c3faea04e4a21425555afa5486e2f7704c8e5d5773cda73d618b1049e0575d",
+    "dist/2022-06-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "6b16b89b4e7b3ca9ba6ca7b0ae881aeb7c81a450ff4f32eca3d0907aadf10fd1",
+    "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "eb504aea2b96402b371e7b7bba7cbc5fdeb9f470be70927b11a340b5937513be",
+    "dist/2022-06-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c78dba1f0c58a7e8817ee9d5ddeb377e087432a1375ea3d99ee27b4a9f7d0ba2",
+    "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "4d29aed70bd5df7525c8c8e8d88cdabee235c229821a9adba08c38a3a7e3b967",
+    "dist/2022-06-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "2fdb9c3c42a3c97d3f8eec7b0e4bcd7a6db24abdf928d51a3c645f24aa7e41a4",
+    "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "afdb95f020eb318ea66b3150593787ead14f1e8590ab950bec5516d1641c39da",
+    "dist/2022-06-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "f1156f6f02262d12c777cee11d02b9c5cf9b4f28a27f4f9de9c154a8843d3d4b",
+    "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "aa972fcd1411e69464233fc54f34ac09aa04eb593410c7345718495e2ba684f9",
+    "dist/2022-06-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "ffa60e4ef87e7bb7229be6cd14f562d652e30e5badaa5892c0a7bc9563c56fbe",
+    "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.gz": "cb827715805de35449a17b190e1cb978bcd7d8b0a5501fe06d8f4313dce5b06d",
+    "dist/2022-06-29/cargo-beta-mips-unknown-linux-gnu.tar.xz": "63bc1122b296a89371d4a3560c06e1ce2f3a00482879d0ded87bd52f87fdec9e",
+    "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "b4d4222040865e4aa1d034f85511f436e08a1502c5213b6eacaf103d417755c6",
+    "dist/2022-06-29/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e1d19f8de4278c01914d3999038c49001c214ab9ec5286beab327322d30fb564",
+    "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "b82d0a96510ca9933540bd8fc1534a1f91f92f92512a018b10cc007240ea13f1",
+    "dist/2022-06-29/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "e4805b270f9763adef25a0f970d28d2d69a92ddd9ab6d7f14fa746ad61b4e635",
+    "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "f3f9ed7f57299511610bf0d44abc79d9a0cf994c979546895b9a42b72b17734f",
+    "dist/2022-06-29/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "08c1c3cef4f257841f9600bfe2f67312cd76fbeca1e4326963715ca77668a0eb",
+    "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "1a1bba0cb974217cbff68001c83270c631f13193b5e3227f22a8b32613f7d570",
+    "dist/2022-06-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "cb32c1d4addc20433b15751db0da67cef5bcc576c17319bd79566596c153af80",
+    "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "7b6713071c93bdbb68f80f4045deaa8078382abe3179c60c92e0de5a0d93f161",
+    "dist/2022-06-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "313e6b05c3178b7e481ab09b71c1491b7136a47a9577649506823bdc698b279d",
+    "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d7d4dc600ff03857b60767c50a79c0de8a0a6a78ef3f309121b8338583526c5",
+    "dist/2022-06-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "4b7d7da12ffe1ee279db21f6ef5b6124330ccee03711f3801561f68b303e15c0",
+    "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "154938148945148682bd165836e503064c248752cb24f1437d20a3ad128d6c91",
+    "dist/2022-06-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "be4c8a5b14fa9db00ad2f8efac052bbd6f7981610baf692b1d01f3bfb3be96f4",
+    "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "9ed70575f47e5a6bec063ed19eff165e35efbf6941403def15e48bf6560b949a",
+    "dist/2022-06-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "ad90bd85638cf26ecd72ffc0b09d1384c64fb990b4aa62f69e39d205609ba06f",
+    "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.gz": "54f71eff8e1ad3d22f49106b2c7b04713e7927a3f54cfc452c61e810e2b57129",
+    "dist/2022-06-29/cargo-beta-x86_64-apple-darwin.tar.xz": "b3f136e3d2bd5776887fb0071bc6434a1eb2cd42fccfe95eb8a32ca1bd36de29",
+    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e57239d7d3b889ec4dad8db20bbaa0140a2f0a471ab62e4a1c48558490f33d36",
+    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "4f14c69c15e3038508df42e254027f0b59ed798cc26f0952fcaa8068341fb55b",
+    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "2898e0a9dc793fe85835b8167b8e4e4cd4d0b044fff37a85034624a92a8e8f76",
+    "dist/2022-06-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "667a8a268fda0c44878498b2c68239bfe7387d9d8f9d39ec4445a79409e65a1a",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "da4ab4baae0f241653591c0f69091724ac8949b18e261c69069ff368f86e76b3",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "333295a07edac2f7aa9acec4284c3f2417ec764a9c09e8735ebbb69621d80aa5",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "3b0899c1cdeebe01d8dabf5d0cd4f9762c07012e874111c77909840f917295d0",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "ad698922172524912ecba24c966df6bdf18a21e530c2467d835c297709f1f413",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "f9efa10a31e31857644ecd8877b08ae96f80962bc96efbb374128220d659c2c5",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "5392a4bc11097ac95e208c9cea7b0773b966f713f3b1e0ba42f1323484b1d27c",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "a6177b8b69eb5d4bd3507d50054009734854775f8821b74b6ad603cda1e0b351",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "33a00ce744789c49438fe8accf40a17c99282339ca69adc7a3e8a810cad9f1f0",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "4b042e30402804c20abd84b39384b0b7d88743d27a9f0a34f90d7626f07a4f47",
+    "dist/2022-06-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2e9fe2e92129a3952f1ae32760fd818a637b829a575194b84ab6d793d74c2c04",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "031b3c2134e2c54aeb29ba2e46a5b6db11c65ff3a364cedd14c79d741a1f9ddc",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "55f82ac681d5c8b6f0777939e747e8856707822e34b3060e9a85ec5935c8a406",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "53cc84de66c0c70b988b6136aa55c4051e51d27952e67db066ea409d56166fbb",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "6e9fa64aa157eb32e3ea4deb8d42256e5bbfee5fd4dae111f107033d792d28ad",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.gz": "d0e27984f1a2133af4e2fe9fd79a22f3e8a792a81111a496f80cfd9f3019b5e0",
+    "dist/2022-06-29/rust-std-beta-aarch64-apple-ios.tar.xz": "404780fc534501fbdd6fb34aeb3f338086feadebfef420a9530c6c4b48b803bb",
+    "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.gz": "bdafb54b1798812a0144029c421cc784a441ee82fc433f5788712f2c05fe4391",
+    "dist/2022-06-29/rust-std-beta-aarch64-fuchsia.tar.xz": "198be344c4a1c4247d8fb21efd9c84787272c0ae6208b341cae508adb8ba0ca4",
+    "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.gz": "9c51ebdba4c211050cc8c6733e21faec7d7fb2591abb38226b0593f449d7e8b2",
+    "dist/2022-06-29/rust-std-beta-aarch64-linux-android.tar.xz": "f97595685703d22b0689b3f2822b3f69780eefc74a3169fdd1cf1d9a4538342d",
+    "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "2c32867f2e8ef81d1a8b0b3af14055be79f1da6dfe514155c9f9fd1eb98a99bb",
+    "dist/2022-06-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "bfc34e4077ece9675ed044a0e518bf8c38d0f351b62b6ea0d674f0c77c7af671",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "547505e533d6654d33df44e362cb421ea8fc69458efe51a357afc3665e19c826",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "f14478bd5bc6fea393111cd6f2dbbd1bc5a8d50adf0faa95b6d804c882d30415",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "ed17ac700cb1e4e773fd832c59aec036cebad714009786fec422077af35336e8",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "32b670e1e29d50c8af4ec0647b34855a07f9ab7a0142305a6a629cd4124c067e",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "225d33281ca9c69c3cdea76714e0383ae543c4f778859dd63cdd37dac09fa9d4",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d55f5260e2c50a608f760d50e7fa653284f2a8b8a64588a80dfb13419061b014",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.gz": "3719244c77c4d5870accfe562f30a9dc3290a14dc3da399e64909402d116c482",
+    "dist/2022-06-29/rust-std-beta-aarch64-unknown-none.tar.xz": "78bb343bb519070c0761ea7ed3c4e56b6d821095ac931ad7f812743600dffb64",
+    "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.gz": "452973239e8c0995a8b9522417e020b883f2f4052764b18b8cd50c9d08cb4f14",
+    "dist/2022-06-29/rust-std-beta-arm-linux-androideabi.tar.xz": "b1952ef69d1c4c32bc0aad4b4beddc6e6bd56155eafce1ffcaafceff8cb6d77d",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "c1ad87f6a2f4e1bc1eb2f732285546fb062faad9b27c4dc248ff174e4a2ec60e",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "ef6611b0ee43efdfc0a27dc3a7b65eeb8cba0d10624233fb473d521392c7d3f4",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "4efd4c3e06a3bc3c2f873901a956827e69cecfd38ed62ba1d8cfaf979d6a67e6",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "2c99a7541c6ca5b1c1fad00e76736e74d7ae50af3cd891aeed8f4f8747d4292d",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "3d5c2be1e0e5b4ce33e2aa4765e869872b247709db1b194512d12146be439c80",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e0b7e25f78e29a62d05eec6220000bcee815bcda24d857225ae47fcf3612fcf9",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0639d8e52de274f02f34ca547a2c692defb329bae290a4ee977b05e9a3deca52",
+    "dist/2022-06-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "256a4ddafddacad0024be539cb038e7742b37f34038a774a06e9a43b29558d5a",
+    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "468113b22041adf0b7746838643ee316063f6049c20d499aa52ac2d9241091ce",
+    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "5b614aa0b7a360a8ee79bb0dca0b2adc3cc0b8f4f2266806bfb0d07b811c11d0",
+    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "d13f0a0abcc35bf6ccd035ba9bdd5b0760b995c885902bae73cf8a22cddc847e",
+    "dist/2022-06-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "c7ffd2f6df10e754480bb1cb84b823084cf95cb6bbae2017437d5b9ffcd90b77",
+    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "ad94a6356dbee95031bd943212eedc441d596cb11da1206010cef611e436975f",
+    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "b8c78492bb88d317580d01e96a70d9eb42d2f9f8396806bd810e348706924d25",
+    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cd09bcb2d9d9fa25ddbcc81d9bf2ed2e68a177a1d61e1f9611516c95ca4f5e3e",
+    "dist/2022-06-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "efd2795a1484cd7331cbd849757a3b6cdbd50ae466bff760d9ec8e7ff965536f",
+    "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "10ac8daf897263a1c51f0ed9df13f707261048c6d11e7a024470ba71c3d3ef34",
+    "dist/2022-06-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "3968db993db3c861856dfa0974207b0709fba871cc17bc857c29f59063af15e5",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "33d19cbc173f71771b7a00a009789eef8f0b2cf65072642e0689bb86b191df4c",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "e896810ee1322ed011d662678839161e7c39faa27f1a8af963bc0a1e3b40a88f",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "d6b81169c6b77b7b93e03ac2d8289539e7ce6436106709f63b79a195b98d6fe8",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "6db5dfcdb0bba850db005a11e76cb3750befde0b6ef03b600c3c0e67a4c5d46a",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "5a729bb3471ccd07de54ca8fbc570fb617d4ba059a620754becc7aa48620f092",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "deb76d6f0bb0e4c9931df9976e869dcfc2548a851a06db89d656856bcab4fa8a",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "464bcf3a881d107747e241f88e71361dc5cabe7c27fe0e0f370c7ef90f8b77ad",
+    "dist/2022-06-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0b66291a56ea5b7aa6b194fcf08d844a067940a3ec4cac11a377c87947a5cf4e",
+    "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.gz": "583e0b2e03386dcc0397dec2802659937e73dad04a52263218128ee2bab8c412",
+    "dist/2022-06-29/rust-std-beta-armv7a-none-eabi.tar.xz": "b9ebb07f4b461cef81b5fbbb38ac89245f4df13215fc64ad04e6972c1c2d405a",
+    "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.gz": "12a5b49d776cbdb26a1a6c1e2c38d62f562cf9f99fd4868da317b08d4df1bb84",
+    "dist/2022-06-29/rust-std-beta-armv7r-none-eabi.tar.xz": "a1b7b2c27236e36893056dccfd9d15db906db53e8c0f931d1dfc9daa147642a0",
+    "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "9d1f6a6694e82528a6dc98d94f63aa253c0f2eac2cf1e9db97fb1fd9d9e68f46",
+    "dist/2022-06-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "179e6d158a2f27bca2be54059414526de20de76a9eaf26c99e01ef9b1c7743be",
+    "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "eda6db1398471b8cda7b7449ba86db47587398c7b322e995039f59caabe8c815",
+    "dist/2022-06-29/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "9a079f124309edf9a187a0980b59085f5a1cb9c94236154a9f53cd7ca67a71e9",
+    "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "af4a7d3da748a9f2ff867fb7e6b87e0b4696904bab60a2e38df21cf41c658ee3",
+    "dist/2022-06-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "420801efc6deddaaee5a7e17672e0ff520d965ece9a2b8aa1534d86ce839777b",
+    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "82d3b6bbc71b5e138f8715bfcba5107f0d1cde6aee8fe6bddaf85fa646ddf1d1",
+    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1eba8240509d6d5d0650f7e8e42cce89246aa1d416b859db496013d83983d4bd",
+    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "d846e2ea559ad467945369d8230321734cca6634b8d1a4088475f8cafc9854d8",
+    "dist/2022-06-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "d5d8df8255a252af0c3eb66596d42a6d6cb9fcf3036fa8ab3f85ca1f344394c0",
+    "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.gz": "55bca00de9caed1f5443592373b8a2581b1bc1ade24bd062a8f2ba396c82e520",
+    "dist/2022-06-29/rust-std-beta-i686-linux-android.tar.xz": "4db58c08b4e58584bf1a38205f100e0bfe79a74a4ff00280d5a29a3367302ca3",
+    "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "76c72088f1d77d84270b8ad00ee87a79cc8607c852291c5d2b82f59e6efd96cd",
+    "dist/2022-06-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "17eb428984599dd696554d9710cec60fcb01c8d341c0e59a0c1c00370c0d9c72",
+    "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "9dd0184f99be287f318952ace8190af2cd7accc47a7b3f388d34c77cff60c5ae",
+    "dist/2022-06-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "d76d255d3db0b9a5b5e8b1670b3eff4feaed8dc938187a6783a3323fb4998b8a",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "8f8d60ba72543402b0c62bd68192891ee290fc7daff104e9ff8b10c9d109d791",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "030629f57e1f05c7a1e96a147f7a2086c0968a6abfecbd375f9093c4a2859fbb",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a5d01dba11d59ac1a11404905c54425594bc69f40cad8814d3ffd00d1b38c52a",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "5f2ea9f7e62fb429f4f0575a267eb46a014b9ae727939f909ec5e3777e32e65b",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "6e76c8616ee86d1b51c9b055b324f715c1a9cbb1c1564982d1f7e6fd623cd292",
+    "dist/2022-06-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "54641f169e424a73cb386e41563af5ed9ba833379edc148579f67bdcdab281ba",
+    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "64303412deb9264dfd15a16341203df39af2e9206ce1d22ca5eaa83762e1f62a",
+    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "4c4cb3fb0ee51f9294cb805c7263f716a921e7d76503cbbd24f8600c485c58aa",
+    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e197dab9c9b11cf98404aed094d1d8bc03a6755ebf4046423c11baeb0143f254",
+    "dist/2022-06-29/rust-std-beta-mips-unknown-linux-musl.tar.xz": "81a80fa315dc3da8111f487b9dd6dbe56991276fac138de4469c0e0b688bae07",
+    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9cc065dd7fe550716efa403c910d9eaf8c18d90d7d3e316772fac72f7f16c45f",
+    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "6bde95f6c57f6ce4de4f1ce9837b386e374eb291d8778956bee0956b150c3917",
+    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "1262105c31f7ec6248b24b71f0003014a8558220444cfc88c611ad2aa94efebd",
+    "dist/2022-06-29/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "cb35ba7184ba5a74f5d6c8592e67e08faed205e091784f85137872e02541ae99",
+    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "31d7af84b431c9185b2ef98c18eaadb957e22e427b331a8ed4ab8b2b6ae364ae",
+    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "674b1c886ae4a2273edd6e49539d45a2a02e73874f6a65ba820dbea75d8ca8c6",
+    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "cc620438e90fbd086b4f237454b099a81e4cc3dae9582e7526b2a10648663e4c",
+    "dist/2022-06-29/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "425ce38ad1bb048756a37e8642ab6b43f8189bee244e4ee011e95fd45f3a3747",
+    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "40b0df32d5df53fe8774000804738d56e7c8768cba1baaf52721a9956d62c557",
+    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "7df34f8ddb1b14698c6473eaaeffd5d6da23ddcde23a74a3482194e01fa5ace7",
+    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "65b3db3bac29c8aad57c8cabe7fbe622acfdcd9221c11af4419d74c24452a939",
+    "dist/2022-06-29/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "9a4a382945631425fc8227d6b42d0f97988dc39c8e79646280e080595d82aa31",
+    "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "30fc151ae3a6423e027aacd70bcd45d13243aa5394ff2d6cf285c55d3c5c6e23",
+    "dist/2022-06-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "28cef1191d2181004b8e5032bc3f7b548996149dac8ffb5b8a5431b32d396683",
+    "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "a6b79a07cdd6cd6d0e468132ab504464e3d6c41f28111cf15c6053d7d560b8b7",
+    "dist/2022-06-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "67aa93c917f234b0b61dbd3fac21a1d6d4ef20cc8dd7fdc6a8bb8e688e3920ca",
+    "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "e4dd3483a85060d75a7dff95dda7a121943f1121983e5d33eff166f4c3e97e6c",
+    "dist/2022-06-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "36f2b7305e8ed58666c206c26e28cc5e8708fdf104f1d67dd0c692f9e36a1482",
+    "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "f232913783443410614af3e27a832740b06d392563f5d0aa6d0ac0558d7bbb6f",
+    "dist/2022-06-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "f54f1f0c7fe7b31ff97bde512573225f7380bd1c35876862ea798fc2b38cd4fc",
+    "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "728135a1f7c89a129c78c2adf360ab06feb79f28b10f993797d498a9effab9e9",
+    "dist/2022-06-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "ba91db121409dc9414377759fd27e8947e46dbb9f3788521d82a67b063c2a9d6",
+    "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "c092940c2eaea9c9168061b8f5b87f1b735c1d0ffe05bc834252719c42f3ff33",
+    "dist/2022-06-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "2906008d17bb17bc84709d8e47c8c065b2749355240e630cdb1f0c173721a05a",
+    "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7815f8bf5838e2f497e2d42cad55c3e738f64957e031af90f82d80fa7ce78f1a",
+    "dist/2022-06-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "16bbac000585cc3985582698b42635d1e3af68445e2ef4340600087e1fc38e26",
+    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "2fdb717d0fa4f3e162ab8603d2b5233c6ec20a587af874d0987b1b040ea95dfa",
+    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f4f2445d1e9f8cd0af34ce0063a44041465df0b6d5b73546595d0d37f0342087",
+    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "a2df1578a4ec47fb925102fd6604add216ed7d27bdf323176328afef48f2faca",
+    "dist/2022-06-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e3839aa18e35d7d050ce00210774a63b84b3070bc28be1d70ffd4c939b6d8cc0",
+    "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "4ad1c23982c5d5b45935e52fc1a0e36e08e853a993a0adb5c9fb9e703ee2cb7f",
+    "dist/2022-06-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "1308041c43eca228f265cd1cdb3d419bb7e4e1461e117536b719cc3ec8527798",
+    "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "0fdbbe00f9b655e657d93e97bd1b625afd1531249cd32d013c0a1d62e48fdbad",
+    "dist/2022-06-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "cd9120d576a533106721b11e4e457c317be7ff484613d2c7592606a379c0fb3f",
+    "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "c570c55584f9d725c69bf092e0187dd7830839b6badc6fba62b5fbaa19b75548",
+    "dist/2022-06-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "d3e63b5f8f139e32a40ccbc7d877714e88d68a31e1644cf4d1cc91771d5459c9",
+    "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "61169fbfdab7d66712f04a53d6ab8766766158a566bf606075132002a67bda0f",
+    "dist/2022-06-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "f137dbdf000903de091c076fd3800466097caf2f9c48e4ebae9c3072fc2aaca4",
+    "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b81429647fa2fd42fa7a5b4c15d15b1595023e81a7e4289e06bd214c6666127b",
+    "dist/2022-06-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4a741ba60918138ab24cac1d6fda432d38d02bbf0a22103270df13e0d40c8a86",
+    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "ac20977687a1831ea2883568eac148821ad9f1ad199a9b728447f7d15f518e1e",
+    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "57262c3ddf2351b80ff8dcc03fe8e16b441e1b0014c0e4534e2e493902928ea7",
+    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "be9111bfcd464b5f107642b18fc375eeea16a1d758de71cfb6258e0302c9ae7a",
+    "dist/2022-06-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "63f84a900c52caac4eed1c58bbfc604e591c56e0fc1afcebe7ae832a9610c060",
+    "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "51f5266d9790f4e691493e403edcd664541afd448123fea3fbd1de2d50c87f1e",
+    "dist/2022-06-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "12f7be43c58de67c761ed17bb555509e639c31c5cc0783d9ca55e78c4586317a",
+    "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "37f3baa3a2db1b15315915910447332bcf5b9f36666f4cc08868b551d27022cb",
+    "dist/2022-06-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e1f457d3da72a9989b90395692310c78c5e5fdcea35fc1bc2f450eba62b7d21d",
+    "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "77a461b06eff56bc00361e9f771e0a81087fed2999e5d1f2f53632a61e90829b",
+    "dist/2022-06-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "29a4f3a426e380b886bc7a468b08d2dad38ff704d74ec2f243ba5ba7720c7e9a",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "cd0285f0254f4042ee70f02ea576ec713e34ec00e2fc0309cd7c891ca26674ca",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "43dd490c8068897a5f45ee0da36ea8854496cfb54faff9f759e2795f22d46cb7",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "cea8f1a52c3829f4781c321bb43486e44ee8fc94602249d1084e8a6e9269e2ce",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "9a6b827b4958d412d4f413219458582142d1536f313d14ded54cf666a43946bf",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "a032c778052e77eb32eef136ca431ce2bfbd6e43ba5a82e90b2ef3dd414b2cd0",
+    "dist/2022-06-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "cb560e7b3c62bd2598e701360b11a6edb16e730700c4aa5e5d284dd1ceb570c3",
+    "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "c8e3309f94e8187e41d5de922c7988d610439be3a90e06c9eab76b4a3850343d",
+    "dist/2022-06-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "f1388800ff04b85fa549191a5cae8e4964baff89ddadd57fccdef85a1da99e4a",
+    "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c0a18d66485400b692011d72af2226fc609eddd19fd1e95f370ed6a864f6dd8a",
+    "dist/2022-06-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "f3772ae732dcc6a63c2143d3530d8253b35c7412b2266ed9583d14f6000b214a",
+    "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.gz": "aa204e3377e1c4272c18231bcdaa439678fbb1158d794ee8b2699fbad382c828",
+    "dist/2022-06-29/rust-std-beta-wasm32-wasi.tar.xz": "25c90365da9be1307e4aa80f699ed14eec03bd48b8271570d9e9e9d4dd0f701d",
+    "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "24754ac282a434638de5bd2a548b3960149b811f03422cf875a5018dfb229441",
+    "dist/2022-06-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "0806c72137fd994acfb304039af85e028999ab941d3d95cd037f298a66377aa5",
+    "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.gz": "588bd3b637531ae3399a91e805d52481c927477d15822636714091d2371e95cf",
+    "dist/2022-06-29/rust-std-beta-x86_64-apple-ios.tar.xz": "27d75a39fec3ead30dca470f0f6c96561a48bffa8d22c283001f7543b0d62f0b",
+    "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "b7b32388857ecd8f1f16fdd5354a9411c84c463b8b40a1ec2982d5dee11e2318",
+    "dist/2022-06-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "5ea72074aedac44961823a6a8788bb7aecb905dffe2c25d52c417275be39676d",
+    "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.gz": "5f53ff113fa233161183bd1c79a946aa13770f52f08ab3d8a62a080ee2682163",
+    "dist/2022-06-29/rust-std-beta-x86_64-fuchsia.tar.xz": "5541a85df4ac431a14830b09bcda0d030236ea31419b1ccfdf2e761638a1c484",
+    "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.gz": "d17d49d6e416941c1aeed7d145b47d2d61a7bcb563720ed5dd9b867cd0522f05",
+    "dist/2022-06-29/rust-std-beta-x86_64-linux-android.tar.xz": "41aa64b361c17afd7466b621923a44e80d61edefd7052e06df1eb96ee0cad3b1",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "2527ecd6465989f54570e7ed61b51c8a00bc5e1c613e972c93b028df0ad60ec5",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "91f243a73494de90c5250a663f111b3a999925a923cb92220d1853428e2b1aea",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "e41010c4f7bec5b06205085fba4e538cec40222c18c5d560c2a1a2f5c2d4b859",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "af8185b065f2ab37f92ec671eae1652368b26b6917e34c24f2a15779f1e447c7",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1fc3c51f18174e07ba21bd8bb4da495540273ac3f89d2e106172bd6cbfd08ae3",
+    "dist/2022-06-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "b5ffbbda960fd38bc11bf56e154990b385940fa6fd95563feed0a403317aeca4",
+    "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.gz": "8bc7de9a99c3eb1954a1dfd17a39629449e41d743ee85437dcc67f37ccfa9cfa",
+    "dist/2022-06-29/rust-std-beta-x86_64-sun-solaris.tar.xz": "919ffd2e0221c6e6125cecf5f1c21c4b03d3e98c4e1322e5ec664e4079d37fce",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "fbcdbf0d7a8dc6970fadc835455a6fce455ecbdb16ec435957e19477efe94af6",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "09bb9ef104f7eeaf6fae591d908a0f8cbaaf98f1a14e788f468cf99dcbecd8ce",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9b0176f89bbff3c2fef94ca3731dbf9e3c079288aee88827efb42a6296ff8168",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "d84e40868ce185b39a0ad9a6dfc118b31cc0742b9e4e80b59944572043088f24",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "69cb1a75f109f1bc3ef55eacb2bf8f3ad4e4f74fbe7fd2b92ee448082b15292f",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "de2bff6b876d38a20c944b9ef1ca296061e6882080316cb6ad4f346b3f25543d",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "1e7803d70fd4965da58e0949f1de2ed9624852b48a6afc43fa7f007940e1ad61",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "cff451b8636469879061f9d0a2e2403d3bece99ea61e4ce8992095dcc5d57429",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "42654d72fc9816827ee0e0fba553f672eeacf7af2f828dcced42b3603ea7b244",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "d8b40b941b95d888af07649aece54b51fe419f129957a3c1ea00bb707092fba9",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9e168ccc151b0320feac61a46f69e5287ebe61d5cda4fd096c2a6e4c1bc4630e",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "1fa18c0e9d352188505f1dcf21b132863cf531f3a5d1cec512baaa135dae071b",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.gz": "221da3b26cafafb2f1db1bcb69529424df021e149983ddd07cae15f9e7bd3b05",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-none.tar.xz": "401b277ab48e8b5dd30da993a68b2318b9f5c3f6a1cd69c244dfa62212b77dc1",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0a67ac955769e71b677af6647233bea61f2bc61db0eda5b3a2d70fe52c094806",
+    "dist/2022-06-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "96d52cf2a502adbb3cc37f1c46fba79ec7dc2ffdfaa369e58ba60a2e9b7a6efb",
+    "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.gz": "13c5bf14af21282b302efc63285b2c683f24853d510319aa43d150fd127255d1",
+    "dist/2022-06-29/rustc-beta-aarch64-apple-darwin.tar.xz": "3afc8778d32d04b8137552ca651237b5573149bfb7c4b3797e73746af8636612",
+    "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "84f95488f8540020efc1f59d3112805b7b16517fcf0e991fac45757f7f88d09b",
+    "dist/2022-06-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "818479235bdc06809c89728ba7c449f2187c159aeb45ffce62250a1e40202921",
+    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "1a8acf7bd5d81b0cce741669aa76170c595525bfd981f327199a014d8f96cf29",
+    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "eaecede917a4994772b1043c42c1a0a88bbf0efe5b9830e5be4fa039c13152a6",
+    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "f38e0aefff50338ec442a8a915aef83bb89a445c2535840a74cc1cd3ccd0ec1a",
+    "dist/2022-06-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f4c7ff3f19303bf82b0a7e3adff2f1d76be75487b78a53a23b5a564567c418b8",
+    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "473936c8d1c6fb7de9da593185d6d3dcf32b3cd833e9a7b96a721ce6ad587628",
+    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "72787fe6ae27c684c166acf178556ff570a923db89b5e4576b97b528b991b6db",
+    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "f641842f5b298ba11d7143d4e24f03b8adf20363e25c459a9b98e9903fd48a16",
+    "dist/2022-06-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "3ef2c162e55a62024e4cbb079f03a38d40529d864ce4f8d28c12843b38568802",
+    "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "e3e714078092863a7cd3a6d9c8b8d8a8c05da97debff0545f45593163bd51e4e",
+    "dist/2022-06-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "dc9ae664ffa5b61d576182ddb79234331e1227302fe9cd6db0926011522582c8",
+    "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "9bc6578d355c1fee74e8104331cdad4f3c9c94bf1713e989de5d52c1f5291528",
+    "dist/2022-06-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "412a2ee2a94ecec20c1c54934b72d84b46e29f35f6520b8e654ef518b9a7e511",
+    "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "f8fc7fbcd82398964ec562f0750f33fa1af55268e053d416d0729b466fc7fb3f",
+    "dist/2022-06-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "eaa66c5680987aaea99d7cd38a5245c832698f4a53443eeeb06880a8ec915497",
+    "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "8748755c8c72ede71310f998c38ea0ba80e2065da5f53f8ac61bfe8e4c94ea1a",
+    "dist/2022-06-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "fac18aa72b3c801230dd3a653bab76521618be5fe48de2f79dc1890dacbc7a9c",
+    "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.gz": "e22c7209d77b1fdce3439225c2e7d659a61cdaced9387fccaef5370cb25baef1",
+    "dist/2022-06-29/rustc-beta-mips-unknown-linux-gnu.tar.xz": "cea1aa2447e02cc6a4be215f0bb4b658560f641389e314c0cc6814c2e1cb5c18",
+    "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e57c23dd8981d77b81b27af2879c4a2bf9e6619b5a638d8ba9dac790bf9316a0",
+    "dist/2022-06-29/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "0dafb1d812358f5275ff272d247573ac0799dac64a446f7ad08543d6f4334088",
+    "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "bf6be111afb4ea7ecdbc611e94aedce8e5ebf255f1e52cc61da65913a6963471",
+    "dist/2022-06-29/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "7d169795f5ef7c09b7e3a9b40d8669c0b2fc6449247551b426286ebe3f6e258f",
+    "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "0e76f229b0dbeb14497cfda0f4d717c369b8bc59c7bce1fbad059220562c0814",
+    "dist/2022-06-29/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "d6870a46ab49264498b18a4cd2d2400f0df8b02514e92c1bd6396c732f869035",
+    "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "547269aa65cbfe33ef5457ac969399fcf90384f57523a91e9c61306fb9e464da",
+    "dist/2022-06-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "fe75b0ae3a9338f1e48e72e6d6f51edba25f5fd7ab0544d3feae6b69105f160c",
+    "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "b445b6ec414be5c580a19717125858ed4c8e0c90828e085f2ab47a3b44a0863e",
+    "dist/2022-06-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "a915c1da4a45cd286c0b8978999d5ef2ab96b24185793ee1dc043e094cf6c51c",
+    "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "72b6014c14f12f5e5848924e20342d993903d16e883ea8473ca8cf9d188f68d5",
+    "dist/2022-06-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "ee707cf657c9991eca8a9b722fb58b420b2c9fe9bc9e32c4042a4af2bc37e8cb",
+    "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "8e1fc4091115f93f13d88dd7a9b05492ffbcf72f12fc8bdeac28dd6f3c78c3ac",
+    "dist/2022-06-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "ae52c2a0c43871c658d63c101a192dd5fea65931e0d45855bd8dd40a58a7e688",
+    "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "fe45b4d1d509a7a0c317888b575d3dcf1dfb7c0b8306ec54e2d09245c906e276",
+    "dist/2022-06-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "0c06412d27669429ff1c0e5855c3a3ac923b40a93b2fdcb8fbccb4033476b5d1",
+    "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.gz": "a3c33e87a6b12049fcd7cbb0f53ea74c8411c91c262b6f352a1024221d3457c4",
+    "dist/2022-06-29/rustc-beta-x86_64-apple-darwin.tar.xz": "3256ad9fdca2506b06962b4e88c9a41daa8f094a5c1c80530fbce4dbdd6e1c32",
+    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "e2881ef537ec43fc012307cdac5291e4733b322e92a3b056a6f2820c883653b8",
+    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "5a8a36ca5f01ffc8a2dff21c6fbf99652444c6d3731c650fb91cce1fe79c3ebc",
+    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "6ee9a6511fc5342b4f07102f874822553c928ed75f09c4e34952db1c248604f1",
+    "dist/2022-06-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "830d24aff7aac91a61143878969632a47eb8392c539fabdd25826792c7125509",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "1fb6dc34083e95e193c39bfb4edca99f42713f5cfe3bda8e368e977f61c82110",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "c3b9ba1586bb6152596aeb01997b40ab65ab7140525b1b0bc22f2a84baf5c44b",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "584b8ee47755982a6b0f0d0d5a12af35ad740e2df8b1ec1d3084509ea940c2b6",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "a4532b97743b8a90f4f492513c7cd51600426c08454be2e24a49cf867ca0e30b",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "f3fb7f949724bf9b8b77cc562d9d53eb067872bc312ceeb2b5541c6667f70da2",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "10912b2783699d9e155b4f59dd762fe012e4ea4410b56d83b36d1df769a8cd49",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f548bad660bce1513081be0767305a523fd129a0b13aa368e8c86a36d1ec3b23",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "fd52405c614d6932d9e5948e851be7315f1f9d21bbfc3e6d142d6d3196464fe7",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "1b816d0bf6d4138bd557094f922e7aa9b2e7d0ea27464cadbb117eac8a42f3fc",
+    "dist/2022-06-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "b869ba4ab920cd08bd063cedba08614d5c6199f643d277d59f44af513925c16b",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3ac81b63371115875eec194eb4d0c3e9aeb624c7f7ce3ee85b197b8e3f1cd599",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "8eda09837e39a0847b79803645f810d87be7208465deb7f5b0952fa7e39c2113",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "353d2f523a3a1bc2ca478b6facea40363d2d18ca6b48d8f4be18626c7cdb3142",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "ade013031c8c72eae5717c248cb20f36107d326c497b4f3c8e90dc2912d11975",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "64b5f8f97781bd4eca5554f28688a58831162fafaebac31b0f04610e16f09a48",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "feb458ae9a30773519b8be69557d0bd4c3d924aa22eb4a4fdf331e0d620f1e90",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cb2698b870f2c56554996f2e651ae53b11241c06da6ebab4b40a460f6826d91f",
+    "dist/2022-06-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "b0be127f8c04dc4ac2d77b2f9ec7e74a793b65bcd591c0c6a7208b1f4b445df3",
+    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "596b02cf564a03c69a29f61ca6bba4758152d64775eff62b767bf77cce3b00bf",
+    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "f819a48640599ea06bcc4a3f3630bd0a12c9e698cf8f62f61b36813830a54d55",
+    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "19df36c566a4cf5d440011a1c0e94a4cc70e5b66e29b36a268872d4e2def8e78",
+    "dist/2022-06-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "dade13d688c6ba9b291b403d4d61bfd8973d3284b9bc7a92ed6de47665411f07",
+    "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "5ba3a696872e02cb2a4b2e191262d61ecbe6f289345373ee06c542a2d2580527",
+    "dist/2022-06-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "8ff08027f040bdf0de0496d6a408796fcca44540b097414255f776704e6f4966",
+    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "15a36d3a798d2fa027d05229ab42baa4cadb6faa8edfd8c13260ea4756031194",
+    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "438ea44472607752d205d9d2f14056a4c66fd9a84f728110792aadd22929b9fd",
+    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "734aa5ce2105134c34301e44f7d8f0ea3bc94587df3e27793530f3a722eb9b26",
+    "dist/2022-06-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "02a7401369a03caec796deb2d3a0b3c1a46bad79bbe6e654d9e721cd95bfcb0a",
+    "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "17a8c573eaaf5033b15ef14ff221848e3100332b6f01b30b249c9e854bcc21d9",
+    "dist/2022-06-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "bca6959f1e6977cccd0571bc61a37928f559eee8e10395d7eb033cec9a8e0dae",
+    "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "6a4cd4b13e877b7f8ba712cab0e804edefd432d78cd46970bd44384ce94e7faa",
+    "dist/2022-06-29/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "43adf44181bee2b295584c36c35041ff97465fa3fe46b358e142a1d10c224a40",
+    "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "376abf3aa462c0e1271044761af0c9f3c63442731c6d04accd32a0ca0221eee6",
+    "dist/2022-06-29/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "f8a5f3d01e06f46a6d85fa7f74b1a494fcb55a6d5dc8113eb96d6a46d0d37050",
+    "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "158573b8e9da4e8a464bd3c692e54084cd0b9097596d41c21646091883d15b48",
+    "dist/2022-06-29/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "bdae49f025be97fbf37c9ca7ef1f4331ec4ebf8a5fb429a4c20f09619069e655",
+    "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "6ed1ea2364c8b645c6d899cada76cf161222fae9b4693ee71fb98721409f73a8",
+    "dist/2022-06-29/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "beaa6383696385769cd885b3314ccb6f69a7a5557bb1af7214c2c8b2d03d64c7",
+    "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "0f0ad140d47b4477e9ff0a925468b36aaaca0063eed018022624ee15cd0fcd7e",
+    "dist/2022-06-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "23d3bcf9d9a22bd869b3857c7c8bbf25c168ab60677a958c8b48d8b04319beae",
+    "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "fbd1655d0399a3e8728710dc0c234ebca2ce8669fc42eadbbb075baabaee740f",
+    "dist/2022-06-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "1d0c70f5ec38542f2d5b125d59d93ffa1a984a7a2e2353503f8b8554604daa8a",
+    "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "34acce36d8aecd8f4414fae766c2ad7c7942eaa8b422075017ce28e84f08fb08",
+    "dist/2022-06-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "8984ea923bf93c394ca50b41f58df0d750bc522c481de2a0468afafef052f343",
+    "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a9064c4ecfe40a2b3cdbabe12b6063f13680f2a6eb36d58f02fa6207af988a13",
+    "dist/2022-06-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "3576cfd24cb1b53d96145651810c532a5b1c424dfcc39b2c78d5688d7f0791ca",
+    "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "2b921dbf7f8c2931bc531665087ffa05efe8bb4270902a311789409994844cd0",
+    "dist/2022-06-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "f6a4134ffb2c4616606b5d9d3ba63b9dda1ec49c2c0af2290a915c08d80ef301",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "468bc3d0d587b37993cda14fbaf07ab4edc05627126d96d9ccaf58b1df55178f",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "e6262f053b2e456d09ce6617e8209e229d2b9ced144a9eff12de830b6f0cbcfe",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "34a9cf74d9076c49c6266d718fad9a78ea1ede268f9b7978b508b76a4c6e3f8c",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "3d0e544dbb280e4cafebc05dcc68b3cda8a742f9909f59de93c8791721c3f2c8",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "d7119b250b1b31fcba6b3d34cb8deafa32fe20f547ad1bc1e931c58e7059f65f",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "ebc31e9118112e64fced1ad94e4e903e7ac0ff8dd771d85a55c1589a6b838c38",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "a940ea208faa9882808cc56a8e96cadf79f954844ede160b2b8971238bc84f4a",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e699ef1a7a7f5e4bd40cbb3daff754e9214cbe71c28b1436a893a5edbca8c876",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "2a53b4b5e57fd9e1d9014d46576e6b47b51d0dbaaf55c4e84964390c2b2065cf",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "e4491027e20ac563ea8a0906d8941f80274890d4d1b4b3728e26e5926f2c77cf",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "b7ba70b0ca5ece6b14cb1034e7226a83435f8b71c77a864b4ad949db11ab75b1",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "ce07cc2010a424e83672095d89b4592485a7c94a3f450e609ed62237c86909ca",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "bd653ae8f104872e5a2f937fabdff09d41691c28d512fb7f08562fb21ab64e89",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d374ef3fcfaf21c13813cab8953c42c9c965c02549d18e95fca903b923ef5e6b",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "f0fe5175ea73034b1b789db8d31214ca561af0f4be21c52895b47baf103e5952",
+    "dist/2022-06-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "6bc6231ebba38ec47fc1de646aa7d8a9855d2dbfb61595fad299656e39acd0d5"
   }
 }
diff --git a/src/test/assembly/dwarf5.rs b/src/test/assembly/dwarf5.rs
new file mode 100644
index 00000000000..f41e6bd55be
--- /dev/null
+++ b/src/test/assembly/dwarf5.rs
@@ -0,0 +1,20 @@
+// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5.
+// assembly-output: emit-asm
+// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5
+// needs-llvm-components: x86
+
+#![feature(no_core, lang_items)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+pub fn wibble() {}
+
+// CHECK: .section .debug_info
+// CHECK-NOT: .short 2
+// CHECK-NOT: .short 4
+// CHECK: .short 5
diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs
index c97223879ca..260d9de8670 100644
--- a/src/test/codegen/consts.rs
+++ b/src/test/codegen/consts.rs
@@ -10,7 +10,7 @@
 // CHECK: @STATIC = {{.*}}, align 4
 
 // This checks the constants from inline_enum_const
-// CHECK: @alloc14 = {{.*}}, align 2
+// CHECK: @alloc12 = {{.*}}, align 2
 
 // This checks the constants from {low,high}_align_const, they share the same
 // constant, but the alignment differs, so the higher one should be used
diff --git a/src/test/codegen/enum-bounds-check-derived-idx.rs b/src/test/codegen/enum-bounds-check-derived-idx.rs
index aa66c2ed08e..fe02aeb5f62 100644
--- a/src/test/codegen/enum-bounds-check-derived-idx.rs
+++ b/src/test/codegen/enum-bounds-check-derived-idx.rs
@@ -12,13 +12,15 @@ pub enum Bar {
 // CHECK-LABEL: @lookup_inc
 #[no_mangle]
 pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 {
-    // CHECK-NOT: panic_bounds_check
+    // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
+    // CHECK: panic_bounds_check
     buf[f as usize + 1]
 }
 
 // CHECK-LABEL: @lookup_dec
 #[no_mangle]
 pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 {
-    // CHECK-NOT: panic_bounds_check
+    // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
+    // CHECK: panic_bounds_check
     buf[f as usize - 1]
 }
diff --git a/src/test/codegen/enum-bounds-check-issue-13926.rs b/src/test/codegen/enum-bounds-check-issue-13926.rs
index b26945bc549..1aec41d5441 100644
--- a/src/test/codegen/enum-bounds-check-issue-13926.rs
+++ b/src/test/codegen/enum-bounds-check-issue-13926.rs
@@ -13,6 +13,7 @@ pub enum Exception {
 // CHECK-LABEL: @access
 #[no_mangle]
 pub fn access(array: &[usize; 12], exc: Exception) -> usize {
-    // CHECK-NOT: panic_bounds_check
+    // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
+    // CHECK: panic_bounds_check
     array[(exc as u8 - 4) as usize]
 }
diff --git a/src/test/codegen/enum-bounds-check-issue-82871.rs b/src/test/codegen/enum-bounds-check-issue-82871.rs
index a1fa1387d94..32fdc4a5f4f 100644
--- a/src/test/codegen/enum-bounds-check-issue-82871.rs
+++ b/src/test/codegen/enum-bounds-check-issue-82871.rs
@@ -1,4 +1,4 @@
-// compile-flags: -O
+// compile-flags: -C opt-level=0
 
 #![crate_type = "lib"]
 
@@ -9,7 +9,10 @@ pub enum E {
 
 // CHECK-LABEL: @index
 #[no_mangle]
-pub fn index(x: &[u32; 3], ind: E) -> u32{
-    // CHECK-NOT: panic_bounds_check
+pub fn index(x: &[u32; 3], ind: E) -> u32 {
+    // Canary: we should be able to optimize out the bounds check, but we need
+    // to track the range of the discriminant result in order to be able to do that.
+    // oli-obk tried to add that, but that caused miscompilations all over the place.
+    // CHECK: panic_bounds_check
     x[ind as usize]
 }
diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs
index 17322d5911b..f85c6817ded 100644
--- a/src/test/codegen/enum-bounds-check.rs
+++ b/src/test/codegen/enum-bounds-check.rs
@@ -21,6 +21,7 @@ pub enum Bar {
 // CHECK-LABEL: @lookup_unmodified
 #[no_mangle]
 pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 {
-    // CHECK-NOT: panic_bounds_check
+    // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
+    // CHECK: panic_bounds_check
     buf[f as usize]
 }
diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs
index 74b1eb948b0..033da80be16 100644
--- a/src/test/codegen/generator-debug-msvc.rs
+++ b/src/test/codegen/generator-debug-msvc.rs
@@ -27,11 +27,11 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
-// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
-// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
diff --git a/src/test/codegen/generator-debug.rs b/src/test/codegen/generator-debug.rs
index 3ec860f2cbc..9c9f5518b66 100644
--- a/src/test/codegen/generator-debug.rs
+++ b/src/test/codegen/generator-debug.rs
@@ -33,11 +33,11 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "1", scope: [[VARIANT]],
-// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "2", scope: [[VARIANT]],
-// CHECK-SAME: file: [[FILE]], line: 18,
+// CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "3", scope: [[VARIANT]],
diff --git a/src/test/codegen/issue-37945.rs b/src/test/codegen/issue-37945.rs
index ee63a783f52..12fa1e9e56b 100644
--- a/src/test/codegen/issue-37945.rs
+++ b/src/test/codegen/issue-37945.rs
@@ -17,7 +17,9 @@ pub fn is_empty_1(xs: Iter<f32>) -> bool {
 // CHECK-NEXT:  start:
 // CHECK-NEXT:    [[A:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[A]])
-// CHECK-NEXT:    [[B:%.*]] = icmp eq {{i32\*|ptr}} %xs.0, %xs.1
+// The order between %xs.0 and %xs.1 on the next line doesn't matter
+// and different LLVM versions produce different order.
+// CHECK-NEXT:    [[B:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}}
 // CHECK-NEXT:    ret i1 [[B:%.*]]
     {xs}.next().is_none()
 }
@@ -28,7 +30,9 @@ pub fn is_empty_2(xs: Iter<f32>) -> bool {
 // CHECK-NEXT:  start:
 // CHECK-NEXT:    [[C:%.*]] = icmp ne {{i32\*|ptr}} %xs.1, null
 // CHECK-NEXT:    tail call void @llvm.assume(i1 [[C]])
-// CHECK-NEXT:    [[D:%.*]] = icmp eq {{i32\*|ptr}} %xs.0, %xs.1
+// The order between %xs.0 and %xs.1 on the next line doesn't matter
+// and different LLVM versions produce different order.
+// CHECK-NEXT:    [[D:%.*]] = icmp eq {{i32\*|ptr}} {{%xs.0, %xs.1|%xs.1, %xs.0}}
 // CHECK-NEXT:    ret i1 [[D:%.*]]
     xs.map(|&x| x).next().is_none()
 }
diff --git a/src/test/codegen/issue-75659.rs b/src/test/codegen/issue-75659.rs
index d093c841d68..6bcb59affe3 100644
--- a/src/test/codegen/issue-75659.rs
+++ b/src/test/codegen/issue-75659.rs
@@ -1,7 +1,7 @@
 // This test checks that the call to memchr/slice_contains is optimized away
 // when searching in small slices.
 
-// compile-flags: -O
+// compile-flags: -O -Zinline-mir=no
 // only-x86_64
 
 #![crate_type = "lib"]
diff --git a/src/test/codegen/mem-replace-direct-memcpy.rs b/src/test/codegen/mem-replace-direct-memcpy.rs
index d1c4c56dbe4..b41ef538d71 100644
--- a/src/test/codegen/mem-replace-direct-memcpy.rs
+++ b/src/test/codegen/mem-replace-direct-memcpy.rs
@@ -3,7 +3,7 @@
 // may e.g. multiply `size_of::<T>()` with a variable "count" (which is only
 // known to be `1` after inlining).
 
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: -C no-prepopulate-passes -Zinline-mir=no
 
 #![crate_type = "lib"]
 
@@ -12,14 +12,12 @@ pub fn replace_byte(dst: &mut u8, src: u8) -> u8 {
 }
 
 // NOTE(eddyb) the `CHECK-NOT`s ensure that the only calls of `@llvm.memcpy` in
-// the entire output, are the two direct calls we want, from `ptr::{read,write}`.
+// the entire output, are the two direct calls we want, from `ptr::replace`.
 
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: ; core::ptr::read
+// CHECK: ; core::mem::replace
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %src, i{{.*}} 1, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %{{.*}}, {{i8\*|ptr}} align 1 %dest, i{{.*}} 1, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
-// CHECK: ; core::ptr::write
-// CHECK-NOT: call void @llvm.memcpy
-// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %dst, {{i8\*|ptr}} align 1 %src, i{{.*}} 1, i1 false)
+// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 1 %dest, {{i8\*|ptr}} align 1 %src{{.*}}, i{{.*}} 1, i1 false)
 // CHECK-NOT: call void @llvm.memcpy
diff --git a/src/test/codegen/remap_path_prefix/main.rs b/src/test/codegen/remap_path_prefix/main.rs
index 381f11ff1ef..9bef743ddcb 100644
--- a/src/test/codegen/remap_path_prefix/main.rs
+++ b/src/test/codegen/remap_path_prefix/main.rs
@@ -1,7 +1,7 @@
 // ignore-windows
 //
 
-// compile-flags: -g  -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src
+// compile-flags: -g  -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src -Zinline-mir=no
 // aux-build:remap_path_prefix_aux.rs
 
 extern crate remap_path_prefix_aux;
diff --git a/src/test/codegen/simd-wide-sum.rs b/src/test/codegen/simd-wide-sum.rs
index fde9b0fcd8a..015ac4fe4d1 100644
--- a/src/test/codegen/simd-wide-sum.rs
+++ b/src/test/codegen/simd-wide-sum.rs
@@ -47,8 +47,9 @@ pub fn wider_reduce_iter(x: Simd<u8, N>) -> u16 {
 #[no_mangle]
 // CHECK-LABEL: @wider_reduce_into_iter
 pub fn wider_reduce_into_iter(x: Simd<u8, N>) -> u16 {
-    // CHECK: zext <8 x i8>
-    // CHECK-SAME: to <8 x i16>
-    // CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
+    // FIXME MIR inlining messes up LLVM optimizations.
+    // WOULD-CHECK: zext <8 x i8>
+    // WOULD-CHECK-SAME: to <8 x i16>
+    // WOULD-CHECK: call i16 @llvm.vector.reduce.add.v8i16(<8 x i16>
     x.to_array().into_iter().map(u16::from).sum()
 }
diff --git a/src/test/codegen/slice-ref-equality.rs b/src/test/codegen/slice-ref-equality.rs
index e5cde5e9e74..47fde12bf30 100644
--- a/src/test/codegen/slice-ref-equality.rs
+++ b/src/test/codegen/slice-ref-equality.rs
@@ -1,4 +1,4 @@
-// compile-flags: -C opt-level=3
+// compile-flags: -C opt-level=3 -Zmerge-functions=disabled
 
 #![crate_type = "lib"]
 
diff --git a/src/test/codegen/swap-small-types.rs b/src/test/codegen/swap-small-types.rs
index 2f375844cc7..03e2a2327fc 100644
--- a/src/test/codegen/swap-small-types.rs
+++ b/src/test/codegen/swap-small-types.rs
@@ -11,9 +11,10 @@ type RGB48 = [u16; 3];
 // CHECK-LABEL: @swap_rgb48
 #[no_mangle]
 pub fn swap_rgb48(x: &mut RGB48, y: &mut RGB48) {
-// CHECK-NOT: alloca
-// CHECK: load i48
-// CHECK: store i48
+    // FIXME MIR inlining messes up LLVM optimizations.
+// WOULD-CHECK-NOT: alloca
+// WOULD-CHECK: load i48
+// WOULD-CHECK: store i48
     swap(x, y)
 }
 
diff --git a/src/test/codegen/vec-in-place.rs b/src/test/codegen/vec-in-place.rs
index 13c41f7d4a9..62139aa9beb 100644
--- a/src/test/codegen/vec-in-place.rs
+++ b/src/test/codegen/vec-in-place.rs
@@ -53,16 +53,18 @@ pub fn vec_iterator_cast_unwrap(vec: Vec<Wrapper<u8>>) -> Vec<u8> {
 // CHECK-LABEL: @vec_iterator_cast_aggregate
 #[no_mangle]
 pub fn vec_iterator_cast_aggregate(vec: Vec<[u64; 4]>) -> Vec<Foo> {
-    // CHECK-NOT: loop
-    // CHECK-NOT: call
+    // FIXME These checks should be the same as other functions.
+    // CHECK-NOT: @__rust_alloc
+    // CHECK-NOT: @__rust_alloc
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
 }
 
 // CHECK-LABEL: @vec_iterator_cast_deaggregate
 #[no_mangle]
 pub fn vec_iterator_cast_deaggregate(vec: Vec<Bar>) -> Vec<[u64; 4]> {
-    // CHECK-NOT: loop
-    // CHECK-NOT: call
+    // FIXME These checks should be the same as other functions.
+    // CHECK-NOT: @__rust_alloc
+    // CHECK-NOT: @__rust_alloc
 
     // Safety: For the purpose of this test we assume that Bar layout matches [u64; 4].
     // This currently is not guaranteed for repr(Rust) types, but it happens to work here and
diff --git a/src/test/incremental/async-lifetimes.rs b/src/test/incremental/async-lifetimes.rs
new file mode 100644
index 00000000000..90a0b93b99a
--- /dev/null
+++ b/src/test/incremental/async-lifetimes.rs
@@ -0,0 +1,19 @@
+// revisions: rpass1 rpass2
+// edition:2021
+
+// See https://github.com/rust-lang/rust/issues/98890
+
+#![allow(unused)]
+
+struct Foo;
+
+impl Foo {
+    async fn f(&self, _: &&()) -> &() {
+        &()
+    }
+}
+
+#[cfg(rpass2)]
+enum Bar {}
+
+fn main() {}
diff --git a/src/test/incremental/split_debuginfo_cached.rs b/src/test/incremental/split_debuginfo_cached.rs
new file mode 100644
index 00000000000..25c802d5a1d
--- /dev/null
+++ b/src/test/incremental/split_debuginfo_cached.rs
@@ -0,0 +1,25 @@
+// Check that compiling with packed Split DWARF twice succeeds. This should confirm that DWARF
+// objects are cached as work products and available to the incremental compilation for `thorin` to
+// pack into a DWARF package.
+
+// ignore-tidy-linelength
+// only-x86_64-unknown-linux-gnu
+// revisions:rpass1 rpass2
+
+// [rpass1]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
+// [rpass2]compile-flags: -g -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split
+
+#![feature(rustc_attrs)]
+// For `rpass2`, nothing has changed so everything should re-used.
+#![rustc_partition_reused(module = "split_debuginfo_cached", cfg = "rpass2")]
+#![rustc_partition_reused(module = "split_debuginfo_cached-another_module", cfg = "rpass2")]
+
+mod another_module {
+    pub fn foo() -> &'static str {
+        "hello world"
+    }
+}
+
+pub fn main() {
+    println!("{}", another_module::foo());
+}
diff --git a/src/test/incremental/split_debuginfo_mode.rs b/src/test/incremental/split_debuginfo_mode.rs
new file mode 100644
index 00000000000..f2533e4146a
--- /dev/null
+++ b/src/test/incremental/split_debuginfo_mode.rs
@@ -0,0 +1,33 @@
+// This test case makes sure that changing split-debuginfo commandline options triggers a full re-compilation.
+// We only test on x86_64-unknown-linux-gnu because there all combinations split-debuginfo settings are valid
+// and the test is platform-independent otherwise.
+
+// ignore-tidy-linelength
+// only-x86_64-unknown-linux-gnu
+// revisions:rpass1 rpass2 rpass3 rpass4
+
+// [rpass1]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=unpacked -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
+// [rpass2]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=single -Zsplit-dwarf-inlining=on
+// [rpass3]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=on
+// [rpass4]compile-flags: -Zquery-dep-graph -Zunstable-options -Csplit-debuginfo=packed -Zsplit-dwarf-kind=split -Zsplit-dwarf-inlining=off
+
+#![feature(rustc_attrs)]
+// For rpass2 we change -Csplit-debuginfo and thus expect every CGU to be recompiled
+#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass2")]
+#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass2")]
+// For rpass3 we change -Zsplit-dwarf-kind and thus also expect every CGU to be recompiled
+#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass3")]
+#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass3")]
+// For rpass4 we change -Zsplit-dwarf-inlining and thus also expect every CGU to be recompiled
+#![rustc_partition_codegened(module = "split_debuginfo_mode", cfg = "rpass4")]
+#![rustc_partition_codegened(module = "split_debuginfo_mode-another_module", cfg = "rpass4")]
+
+mod another_module {
+    pub fn foo() -> &'static str {
+        "hello world"
+    }
+}
+
+pub fn main() {
+    println!("{}", another_module::foo());
+}
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
index deb5dbad7de..c8848caa027 100644
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
+++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir
@@ -39,7 +39,7 @@ fn main() -> () {
         _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27
                                          // mir::Constant
                                          // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
-                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
index deb5dbad7de..c8848caa027 100644
--- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
+++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir
@@ -39,7 +39,7 @@ fn main() -> () {
         _5 = foo(move _6) -> bb1;        // scope 4 at $DIR/array-index-is-temporary.rs:16:21: 16:27
                                          // mir::Constant
                                          // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
-                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
index 5b1ffc76fe5..9b35beccbcc 100644
--- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
@@ -22,7 +22,7 @@ fn main() -> () {
         _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:7:13: 7:25
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -31,7 +31,7 @@ fn main() -> () {
         (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:7:17: 7:23
-                                         // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> S {S::new}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -47,7 +47,7 @@ fn main() -> () {
         _6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:8:5: 8:9
-                                         // + literal: Const { ty: fn(Box<S>) {std::mem::drop::<Box<S>>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Box<S>) {std::mem::drop::<Box<S>>}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
index fdc016a95d5..7ecd67d7c67 100644
--- a/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
+++ b/src/test/mir-opt/combine_clone_of_primitives.{impl#0}-clone.InstCombine.diff
@@ -4,98 +4,78 @@
   fn <impl at $DIR/combine_clone_of_primitives.rs:6:10: 6:15>::clone(_1: &MyThing<T>) -> MyThing<T> {
       debug self => _1;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
       let mut _0: MyThing<T>;              // return place in scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
-      let _2: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-      let _3: &u64;                        // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-      let _4: &[f32; 3];                   // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-      let mut _5: T;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-      let mut _6: &T;                      // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-      let _7: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-      let mut _8: u64;                     // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-      let mut _9: &u64;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-      let _10: &u64;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-      let mut _11: [f32; 3];               // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-      let mut _12: &[f32; 3];              // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-      let _13: &[f32; 3];                  // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-      scope 1 {
-          debug __self_0_0 => _2;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          debug __self_0_1 => _3;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-          debug __self_0_2 => _4;          // in scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-      }
+      let mut _2: T;                       // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _3: &T;                      // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let _4: &T;                          // in scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+      let mut _5: u64;                     // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _6: &u64;                    // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let _7: &u64;                        // in scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+      let mut _8: [f32; 3];                // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let mut _9: &[f32; 3];               // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+      let _10: &[f32; 3];                  // in scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          _2 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          StorageLive(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-          _3 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-          StorageLive(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-          _4 = &((*_1).2: [f32; 3]);       // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-          StorageLive(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          StorageLive(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          StorageLive(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
--         _7 = &(*_2);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
--         _6 = &(*_7);                     // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-+         _7 = _2;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-+         _6 = _7;                         // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-          _5 = <T as Clone>::clone(move _6) -> bb1; // scope 1 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          StorageLive(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _4 = &((*_1).0: T);              // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+-         _3 = &(*_4);                     // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
++         _3 = _4;                         // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
+          _2 = <T as Clone>::clone(move _3) -> bb1; // scope 0 at $DIR/combine_clone_of_primitives.rs:8:5: 8:9
                                            // mir::Constant
                                            // + span: $DIR/combine_clone_of_primitives.rs:8:5: 8:9
-                                           // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
       }
   
       bb1: {
-          StorageDead(_6);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9
-          StorageLive(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-          StorageLive(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-          StorageLive(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
--         _10 = &(*_3);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
--         _9 = &(*_10);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
--         _8 = <u64 as Clone>::clone(move _9) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageDead(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:8:8: 8:9
+          StorageLive(_5);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_6);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          StorageLive(_7);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+          _7 = &((*_1).1: u64);            // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _6 = &(*_7);                     // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-         _5 = <u64 as Clone>::clone(move _6) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
 -                                          // mir::Constant
 -                                          // + span: $DIR/combine_clone_of_primitives.rs:9:5: 9:11
--                                          // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(Scalar(<ZST>)) }
-+         _10 = _3;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-+         _9 = _10;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-+         _8 = (*_9);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
-+         goto -> bb2;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
+-                                          // + literal: Const { ty: for<'r> fn(&'r u64) -> u64 {<u64 as Clone>::clone}, val: Value(<ZST>) }
++         _6 = _7;                         // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         _5 = (*_6);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
++         goto -> bb2;                     // scope 0 at $DIR/combine_clone_of_primitives.rs:9:5: 9:11
       }
   
       bb2: {
-          StorageDead(_9);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11
-          StorageLive(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-          StorageLive(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-          StorageLive(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
--         _13 = &(*_4);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
--         _12 = &(*_13);                   // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
--         _11 = <[f32; 3] as Clone>::clone(move _12) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageDead(_6);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:9:10: 9:11
+          StorageLive(_8);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_9);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          StorageLive(_10);                // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+          _10 = &((*_1).2: [f32; 3]);      // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _9 = &(*_10);                    // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-         _8 = <[f32; 3] as Clone>::clone(move _9) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
 -                                          // mir::Constant
 -                                          // + span: $DIR/combine_clone_of_primitives.rs:10:5: 10:16
--                                          // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(Scalar(<ZST>)) }
-+         _13 = _4;                        // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-+         _12 = _13;                       // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-+         _11 = (*_12);                    // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
-+         goto -> bb3;                     // scope 1 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
+-                                          // + literal: Const { ty: for<'r> fn(&'r [f32; 3]) -> [f32; 3] {<[f32; 3] as Clone>::clone}, val: Value(<ZST>) }
++         _9 = _10;                        // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         _8 = (*_9);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
++         goto -> bb3;                     // scope 0 at $DIR/combine_clone_of_primitives.rs:10:5: 10:16
       }
   
       bb3: {
-          StorageDead(_12);                // scope 1 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
-          Deinit(_0);                      // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
-          (_0.0: T) = move _5;             // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
-          (_0.1: u64) = move _8;           // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
-          (_0.2: [f32; 3]) = move _11;     // scope 1 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
-          StorageDead(_13);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_11);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_10);                // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_8);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_7);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_5);                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
-          StorageDead(_3);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_9);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:10:15: 10:16
+          Deinit(_0);                      // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.0: T) = move _2;             // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.1: u64) = move _5;           // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          (_0.2: [f32; 3]) = move _8;      // scope 0 at $DIR/combine_clone_of_primitives.rs:6:10: 6:15
+          StorageDead(_8);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_5);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
           StorageDead(_2);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_10);                // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_7);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          StorageDead(_4);                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
           return;                          // scope 0 at $DIR/combine_clone_of_primitives.rs:6:15: 6:15
       }
   
       bb4 (cleanup): {
-          drop(_5) -> bb5;                 // scope 1 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
+          drop(_2) -> bb5;                 // scope 0 at $DIR/combine_clone_of_primitives.rs:6:14: 6:15
       }
   
       bb5 (cleanup): {
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index 268d8f46464..bc82222d118 100644
--- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -33,7 +33,7 @@
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42
-                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 322a1b206f9..39dcf2f10c6 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -35,7 +35,7 @@
           _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
                                            // mir::Constant
                                            // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53
-                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
index 87302424914..919b9094351 100644
--- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
@@ -32,7 +32,7 @@
 +         _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22
                                            // mir::Constant
                                            // + span: $DIR/boxes.rs:12:14: 12:22
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index 84d72202d52..852a2419f55 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -30,7 +30,7 @@
           _4 = read(move _5) -> bb1;       // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12
                                            // mir::Constant
                                            // + span: $DIR/const_prop_fails_gracefully.rs:8:5: 8:9
-                                           // + literal: Const { ty: fn(usize) {read}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(usize) {read}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
index d7636c81709..d0287cc2b2b 100644
--- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff
@@ -19,7 +19,7 @@
           _2 = begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/panic.rs:LL:COL
-                                           // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/std/src/panic.rs:LL:COL
                                            // + literal: Const { ty: &str, val: Value(Slice(..)) }
diff --git a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
index e874adebbe0..5991d7637f5 100644
--- a/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_66971.main.ConstProp.diff
@@ -20,7 +20,7 @@
           _1 = encode(move _2) -> bb1;     // scope 0 at $DIR/issue-66971.rs:16:5: 16:23
                                            // mir::Constant
                                            // + span: $DIR/issue-66971.rs:16:5: 16:11
-                                           // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
index 69d31b681b4..149a60c0bbb 100644
--- a/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/issue_67019.main.ConstProp.diff
@@ -21,7 +21,7 @@
           _1 = test(move _2) -> bb1;       // scope 0 at $DIR/issue-67019.rs:11:5: 11:20
                                            // mir::Constant
                                            // + span: $DIR/issue-67019.rs:11:5: 11:9
-                                           // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
index 86fac1270d0..724cf096f59 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_partial_read.main.ConstProp.diff
@@ -17,7 +17,7 @@
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:34
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_aggregate_partial_read.rs:5:29: 5:32
-                                           // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> (i32, i32) {foo}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
index 247d8f32432..a22efa7eaf5 100644
--- a/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/mutable_variable_unprop_assign.main.ConstProp.diff
@@ -26,7 +26,7 @@
           _1 = foo() -> bb1;               // scope 0 at $DIR/mutable_variable_unprop_assign.rs:5:13: 5:18
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_unprop_assign.rs:5:13: 5:16
-                                           // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
index 037febdf3a5..80f461a4c02 100644
--- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff
@@ -16,7 +16,7 @@
           _3 = main as fn() (Pointer(ReifyFnPointer)); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:17
                                            // mir::Constant
                                            // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17
-                                           // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
           _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26
           StorageDead(_3);                 // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26
           _1 = move _2 as *const fn() (PointerFromExposedAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41
diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
index af48ff0b098..6343ee80a25 100644
--- a/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/scalar_literal_propagation.main.ConstProp.diff
@@ -21,7 +21,7 @@
 +         _2 = consume(const 1_u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15
                                            // mir::Constant
                                            // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12
-                                           // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(u32) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff
index f031a703a9d..5dfa05a46d3 100644
--- a/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/switch_int.main.ConstProp.diff
@@ -16,14 +16,14 @@
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:9:14: 9:21
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:9:14: 9:17
-                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:8:14: 8:20
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:8:14: 8:17
-                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
index f2b02551146..704b4bbe018 100644
--- a/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
+++ b/src/test/mir-opt/const_prop/switch_int.main.SimplifyConstCondition-after-const-prop.diff
@@ -16,14 +16,14 @@
           _0 = foo(const -1_i32) -> bb3;   // scope 0 at $DIR/switch_int.rs:9:14: 9:21
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:9:14: 9:17
-                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
           _0 = foo(const 0_i32) -> bb3;    // scope 0 at $DIR/switch_int.rs:8:14: 8:20
                                            // mir::Constant
                                            // + span: $DIR/switch_int.rs:8:14: 8:17
-                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(i32) {foo}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
index 2bcd10f160b..adb182314ac 100644
--- a/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/tuple_literal_propagation.main.ConstProp.diff
@@ -22,7 +22,7 @@
           _2 = consume(move _3) -> bb1;    // scope 1 at $DIR/tuple_literal_propagation.rs:5:5: 5:15
                                            // mir::Constant
                                            // + span: $DIR/tuple_literal_propagation.rs:5:5: 5:12
-                                           // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn((u32, u32)) {consume}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
index 6037f89086d..5f8019ac975 100644
--- a/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
+++ b/src/test/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination.diff
@@ -28,7 +28,7 @@
           _5 = cond() -> bb2;              // scope 0 at $DIR/cycle.rs:12:11: 12:17
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:12:11: 12:15
-                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
index 372b14eb7c9..688015f68d3 100644
--- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
+++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
@@ -27,7 +27,7 @@
 +         _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
index f5eabf86967..571efc91171 100644
--- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
@@ -36,7 +36,7 @@
           _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:4:17: 4:26
                                            // mir::Constant
                                            // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
-                                           // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -56,7 +56,7 @@
           _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:4:17: 4:26
                                            // mir::Constant
                                            // + span: $DIR/derefer_complex_case.rs:4:17: 4:26
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
       bb3: {
@@ -77,7 +77,7 @@
           _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:4:29: 4:38
                                            // mir::Constant
                                            // + span: $DIR/derefer_complex_case.rs:4:29: 4:33
-                                           // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
       }
   
       bb5: {
diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
index e131adae2b6..09cce1c1654 100644
--- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
@@ -19,7 +19,7 @@
           _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:10:5: 10:12
                                            // mir::Constant
                                            // + span: $DIR/derefer_inline_test.rs:10:5: 10:12
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -28,7 +28,7 @@
           (*_5) = f() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/derefer_inline_test.rs:10:9: 10:12
                                            // mir::Constant
                                            // + span: $DIR/derefer_inline_test.rs:10:9: 10:10
-                                           // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) }
       }
   
       bb2: {
@@ -59,7 +59,7 @@
           _6 = alloc::alloc::box_free::<Box<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::boxed::Box<u32>>), move (_5.1: std::alloc::Global)) -> bb6; // scope 0 at $DIR/derefer_inline_test.rs:10:11: 10:12
                                            // mir::Constant
                                            // + span: $DIR/derefer_inline_test.rs:10:11: 10:12
-                                           // + literal: Const { ty: unsafe fn(Unique<Box<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Box<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(Unique<Box<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Box<u32>, std::alloc::Global>}, val: Value(<ZST>) }
       }
   
       bb8 (cleanup): {
diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
index 8b91a65bf3d..cb110afe019 100644
--- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
@@ -33,7 +33,7 @@
           _1 = foo() -> bb1;               // scope 0 at $DIR/derefer_terminator_test.rs:3:13: 3:18
                                            // mir::Constant
                                            // + span: $DIR/derefer_terminator_test.rs:3:13: 3:16
-                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -41,7 +41,7 @@
           _2 = foo() -> bb2;               // scope 1 at $DIR/derefer_terminator_test.rs:4:13: 4:18
                                            // mir::Constant
                                            // + span: $DIR/derefer_terminator_test.rs:4:13: 4:16
-                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff
index c3aa19e6c5f..97fb7fce14e 100644
--- a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff
@@ -19,7 +19,7 @@
           _1 = val() -> bb1;               // scope 0 at $DIR/branch.rs:13:13: 13:18
                                            // mir::Constant
                                            // + span: $DIR/branch.rs:13:13: 13:16
-                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -28,7 +28,7 @@
           _3 = cond() -> bb2;              // scope 1 at $DIR/branch.rs:15:16: 15:22
                                            // mir::Constant
                                            // + span: $DIR/branch.rs:15:16: 15:20
-                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
       }
   
       bb2: {
@@ -45,7 +45,7 @@
           _4 = val() -> bb5;               // scope 1 at $DIR/branch.rs:18:9: 18:14
                                            // mir::Constant
                                            // + span: $DIR/branch.rs:18:9: 18:12
-                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
       }
   
       bb5: {
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
index 3f9ba4ad4f0..11a0d1f609f 100644
--- a/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff
@@ -14,7 +14,7 @@
           _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
                                            // mir::Constant
                                            // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
-                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
index 963881d7ae0..1346a04938a 100644
--- a/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff
@@ -14,7 +14,7 @@
           _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
                                            // mir::Constant
                                            // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
-                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
index 8e44d68d934..516180fbec6 100644
--- a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff
@@ -27,7 +27,7 @@
           _1 = val() -> bb1;               // scope 0 at $DIR/cycle.rs:9:17: 9:22
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:9:17: 9:20
-                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> i32 {val}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
index 582a1738cbf..acfd3c18fc9 100644
--- a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
+++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff
@@ -22,7 +22,7 @@
           _2 = val() -> bb1;               // scope 0 at $DIR/union.rs:13:23: 13:28
                                            // mir::Constant
                                            // + span: $DIR/union.rs:13:23: 13:26
-                                           // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> u32 {val}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/enum_cast.bar.mir_map.0.mir b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir
new file mode 100644
index 00000000000..1b4a469135c
--- /dev/null
+++ b/src/test/mir-opt/enum_cast.bar.mir_map.0.mir
@@ -0,0 +1,13 @@
+// MIR for `bar` 0 mir_map
+
+fn bar(_1: Bar) -> usize {
+    debug bar => _1;                     // in scope 0 at $DIR/enum_cast.rs:22:8: 22:11
+    let mut _0: usize;                   // return place in scope 0 at $DIR/enum_cast.rs:22:21: 22:26
+    let mut _2: isize;                   // in scope 0 at $DIR/enum_cast.rs:23:5: 23:8
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $DIR/enum_cast.rs:23:5: 23:17
+        _0 = move _2 as usize (Misc);    // scope 0 at $DIR/enum_cast.rs:23:5: 23:17
+        return;                          // scope 0 at $DIR/enum_cast.rs:24:2: 24:2
+    }
+}
diff --git a/src/test/mir-opt/enum_cast.boo.mir_map.0.mir b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir
new file mode 100644
index 00000000000..7724e89a228
--- /dev/null
+++ b/src/test/mir-opt/enum_cast.boo.mir_map.0.mir
@@ -0,0 +1,13 @@
+// MIR for `boo` 0 mir_map
+
+fn boo(_1: Boo) -> usize {
+    debug boo => _1;                     // in scope 0 at $DIR/enum_cast.rs:26:8: 26:11
+    let mut _0: usize;                   // return place in scope 0 at $DIR/enum_cast.rs:26:21: 26:26
+    let mut _2: u8;                      // in scope 0 at $DIR/enum_cast.rs:27:5: 27:8
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $DIR/enum_cast.rs:27:5: 27:17
+        _0 = move _2 as usize (Misc);    // scope 0 at $DIR/enum_cast.rs:27:5: 27:17
+        return;                          // scope 0 at $DIR/enum_cast.rs:28:2: 28:2
+    }
+}
diff --git a/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir
new file mode 100644
index 00000000000..a9dcfadae75
--- /dev/null
+++ b/src/test/mir-opt/enum_cast.droppy.mir_map.0.mir
@@ -0,0 +1,54 @@
+// MIR for `droppy` 0 mir_map
+
+fn droppy() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/enum_cast.rs:39:13: 39:13
+    let _1: ();                          // in scope 0 at $DIR/enum_cast.rs:40:5: 45:6
+    let _2: Droppy;                      // in scope 0 at $DIR/enum_cast.rs:41:13: 41:14
+    let mut _4: isize;                   // in scope 0 at $DIR/enum_cast.rs:44:17: 44:18
+    let _5: Droppy;                      // in scope 0 at $DIR/enum_cast.rs:46:9: 46:10
+    scope 1 {
+        debug x => _2;                   // in scope 1 at $DIR/enum_cast.rs:41:13: 41:14
+        scope 2 {
+            debug y => _3;               // in scope 2 at $DIR/enum_cast.rs:44:13: 44:14
+        }
+        scope 3 {
+            let _3: usize;               // in scope 3 at $DIR/enum_cast.rs:44:13: 44:14
+        }
+    }
+    scope 4 {
+        debug z => _5;                   // in scope 4 at $DIR/enum_cast.rs:46:9: 46:10
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/enum_cast.rs:40:5: 45:6
+        StorageLive(_2);                 // scope 0 at $DIR/enum_cast.rs:41:13: 41:14
+        _2 = Droppy::C;                  // scope 0 at $DIR/enum_cast.rs:41:17: 41:26
+        FakeRead(ForLet(None), _2);      // scope 0 at $DIR/enum_cast.rs:41:13: 41:14
+        StorageLive(_3);                 // scope 3 at $DIR/enum_cast.rs:44:13: 44:14
+        _4 = discriminant(_2);           // scope 3 at $DIR/enum_cast.rs:44:17: 44:27
+        _3 = move _4 as usize (Misc);    // scope 3 at $DIR/enum_cast.rs:44:17: 44:27
+        FakeRead(ForLet(None), _3);      // scope 3 at $DIR/enum_cast.rs:44:13: 44:14
+        _1 = const ();                   // scope 0 at $DIR/enum_cast.rs:40:5: 45:6
+        StorageDead(_3);                 // scope 1 at $DIR/enum_cast.rs:45:5: 45:6
+        drop(_2) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:45:5: 45:6
+    }
+
+    bb1: {
+        StorageDead(_2);                 // scope 0 at $DIR/enum_cast.rs:45:5: 45:6
+        StorageDead(_1);                 // scope 0 at $DIR/enum_cast.rs:45:5: 45:6
+        StorageLive(_5);                 // scope 0 at $DIR/enum_cast.rs:46:9: 46:10
+        _5 = Droppy::B;                  // scope 0 at $DIR/enum_cast.rs:46:13: 46:22
+        FakeRead(ForLet(None), _5);      // scope 0 at $DIR/enum_cast.rs:46:9: 46:10
+        _0 = const ();                   // scope 0 at $DIR/enum_cast.rs:39:13: 47:2
+        drop(_5) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/enum_cast.rs:47:1: 47:2
+    }
+
+    bb2: {
+        StorageDead(_5);                 // scope 0 at $DIR/enum_cast.rs:47:1: 47:2
+        return;                          // scope 0 at $DIR/enum_cast.rs:47:2: 47:2
+    }
+
+    bb3 (cleanup): {
+        resume;                          // scope 0 at $DIR/enum_cast.rs:39:1: 47:2
+    }
+}
diff --git a/src/test/mir-opt/enum_cast.foo.mir_map.0.mir b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir
new file mode 100644
index 00000000000..d89dc951923
--- /dev/null
+++ b/src/test/mir-opt/enum_cast.foo.mir_map.0.mir
@@ -0,0 +1,13 @@
+// MIR for `foo` 0 mir_map
+
+fn foo(_1: Foo) -> usize {
+    debug foo => _1;                     // in scope 0 at $DIR/enum_cast.rs:18:8: 18:11
+    let mut _0: usize;                   // return place in scope 0 at $DIR/enum_cast.rs:18:21: 18:26
+    let mut _2: isize;                   // in scope 0 at $DIR/enum_cast.rs:19:5: 19:8
+
+    bb0: {
+        _2 = discriminant(_1);           // scope 0 at $DIR/enum_cast.rs:19:5: 19:17
+        _0 = move _2 as usize (Misc);    // scope 0 at $DIR/enum_cast.rs:19:5: 19:17
+        return;                          // scope 0 at $DIR/enum_cast.rs:20:2: 20:2
+    }
+}
diff --git a/src/test/mir-opt/enum_cast.rs b/src/test/mir-opt/enum_cast.rs
new file mode 100644
index 00000000000..090142aaf35
--- /dev/null
+++ b/src/test/mir-opt/enum_cast.rs
@@ -0,0 +1,50 @@
+// EMIT_MIR enum_cast.foo.mir_map.0.mir
+// EMIT_MIR enum_cast.bar.mir_map.0.mir
+// EMIT_MIR enum_cast.boo.mir_map.0.mir
+
+enum Foo {
+    A
+}
+
+enum Bar {
+    A, B
+}
+
+#[repr(u8)]
+enum Boo {
+    A, B
+}
+
+fn foo(foo: Foo) -> usize {
+    foo as usize
+}
+
+fn bar(bar: Bar) -> usize {
+    bar as usize
+}
+
+fn boo(boo: Boo) -> usize {
+    boo as usize
+}
+
+// EMIT_MIR enum_cast.droppy.mir_map.0.mir
+enum Droppy {
+    A, B, C
+}
+
+impl Drop for Droppy {
+    fn drop(&mut self) {}
+}
+
+fn droppy() {
+    {
+        let x = Droppy::C;
+        // remove this entire test once `cenum_impl_drop_cast` becomes a hard error
+        #[allow(cenum_impl_drop_cast)]
+        let y = x as usize;
+    }
+    let z = Droppy::B;
+}
+
+fn main() {
+}
diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
index 15409fa0dd2..a930d83b9e7 100644
--- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
+++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff
@@ -41,7 +41,7 @@
           _4 = Formatter::sign_plus(move _5) -> bb1; // scope 0 at $DIR/funky_arms.rs:15:22: 15:37
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:15:26: 15:35
-                                           // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r Formatter) -> bool {Formatter::sign_plus}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -69,7 +69,7 @@
           _7 = Formatter::precision(move _8) -> bb5; // scope 3 at $DIR/funky_arms.rs:24:30: 24:45
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:24:34: 24:43
-                                           // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option<usize> {Formatter::precision}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r Formatter) -> Option<usize> {Formatter::precision}, val: Value(<ZST>) }
       }
   
       bb5: {
@@ -100,7 +100,7 @@
           _0 = float_to_exponential_common_exact::<T>(move _11, move _12, move _13, move _14, move _17) -> bb7; // scope 3 at $DIR/funky_arms.rs:26:9: 26:87
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:26:9: 26:42
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, u32, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_exact::<T>}, val: Value(<ZST>) }
       }
   
       bb7: {
@@ -125,7 +125,7 @@
           _0 = float_to_exponential_common_shortest::<T>(move _18, move _19, move _20, move _21) -> bb9; // scope 2 at $DIR/funky_arms.rs:28:9: 28:68
                                            // mir::Constant
                                            // + span: $DIR/funky_arms.rs:28:9: 28:45
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(&'r mut Formatter<'s>, &'t0 T, Sign, bool) -> Result<(), std::fmt::Error> {float_to_exponential_common_shortest::<T>}, val: Value(<ZST>) }
       }
   
       bb9: {
diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
index 84ccf25ef75..c78c345dec2 100644
--- a/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
+++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
@@ -14,22 +14,22 @@
     },
 } */
 
-fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6]) -> () {
-    let mut _0: ();                      // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-    let mut _2: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 10:17]) -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
+    let mut _2: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     let _3: std::string::String;         // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
     let _4: ();                          // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
     let mut _5: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:12:9: 12:14
     let mut _6: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:18: 10:18
-    let mut _7: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-    let mut _8: u32;                     // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+    let mut _7: ();                      // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
+    let mut _8: u32;                     // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     scope 1 {
         debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:11:13: 11:15
     }
 
     bb0: {
-        _8 = discriminant((*_1));        // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        _8 = discriminant((*_1));        // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
+        switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb1: {
@@ -44,11 +44,11 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1
     }
 
     bb3: {
-        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb4 (cleanup): {
-        resume;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        resume;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb5 (cleanup): {
@@ -57,11 +57,11 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1
     }
 
     bb6: {
-        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb7: {
-        goto -> bb9;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        goto -> bb9;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb8: {
@@ -69,16 +69,16 @@ fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 1
     }
 
     bb9: {
-        goto -> bb6;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        goto -> bb6;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb10: {
-        StorageLive(_4);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        StorageLive(_5);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
-        goto -> bb1;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        StorageLive(_4);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
+        StorageLive(_5);                 // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
+        goto -> bb1;                     // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 
     bb11: {
-        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6
+        return;                          // scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 10:17
     }
 }
diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
index 739492d7d24..af4ed32c508 100644
--- a/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
+++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}` before StateTransform
 
-fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6], _2: ()) -> ()
+fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 22:18], _2: ()) -> ()
 yields ()
  {
     let mut _0: ();                      // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19
@@ -41,7 +41,7 @@ yields ()
         _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:26:9: 26:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13
-                                         // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -53,7 +53,7 @@ yields ()
         _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:27:9: 27:16
                                          // mir::Constant
                                          // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13
-                                         // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(<ZST>) }
     }
 
     bb3: {
@@ -66,7 +66,7 @@ yields ()
     }
 
     bb4: {
-        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:28:6: 28:6
+        return;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:18: 22:18
     }
 
     bb5: {
@@ -82,7 +82,7 @@ yields ()
     }
 
     bb7: {
-        generator_drop;                  // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
+        generator_drop;                  // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18
     }
 
     bb8 (cleanup): {
@@ -104,7 +104,7 @@ yields ()
     }
 
     bb11 (cleanup): {
-        resume;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 28:6
+        resume;                          // scope 0 at $DIR/generator-storage-dead-unwind.rs:22:16: 22:18
     }
 
     bb12 (cleanup): {
diff --git a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
index 7f5ebe2a59b..16fa432dc3a 100644
--- a/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
+++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir
@@ -14,31 +14,31 @@
     },
 } */
 
-fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]>, _2: u8) -> GeneratorState<(), ()> {
+fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]>, _2: u8) -> GeneratorState<(), ()> {
     debug _x => _10;                     // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
-    let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+    let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     let _3: HasDrop;                     // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
     let mut _4: !;                       // in scope 0 at $DIR/generator-tiny.rs:21:9: 24:10
-    let mut _5: ();                      // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+    let mut _5: ();                      // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     let _6: u8;                          // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18
     let mut _7: ();                      // in scope 0 at $DIR/generator-tiny.rs:22:13: 22:18
     let _8: ();                          // in scope 0 at $DIR/generator-tiny.rs:23:13: 23:21
     let mut _9: ();                      // in scope 0 at $DIR/generator-tiny.rs:19:25: 19:25
     let _10: u8;                         // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19
-    let mut _11: u32;                    // in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+    let mut _11: u32;                    // in scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     scope 1 {
-        debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
+        debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:20:13: 20:15
     }
 
     bb0: {
-        _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
+        switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     }
 
     bb1: {
-        _10 = move _2;                   // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        _10 = move _2;                   // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
         nop;                             // scope 0 at $DIR/generator-tiny.rs:20:13: 20:15
-        Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
+        Deinit((((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop)); // scope 0 at $DIR/generator-tiny.rs:20:18: 20:25
         StorageLive(_4);                 // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
         goto -> bb2;                     // scope 1 at $DIR/generator-tiny.rs:21:9: 24:10
     }
@@ -50,7 +50,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
         Deinit(_0);                      // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         discriminant(_0) = 0;            // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
-        discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
+        discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
         return;                          // scope 1 at $DIR/generator-tiny.rs:22:13: 22:18
     }
 
@@ -61,7 +61,7 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
         _8 = callee() -> bb4;            // scope 1 at $DIR/generator-tiny.rs:23:13: 23:21
                                          // mir::Constant
                                          // + span: $DIR/generator-tiny.rs:23:13: 23:19
-                                         // + literal: Const { ty: fn() {callee}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {callee}, val: Value(<ZST>) }
     }
 
     bb4: {
@@ -71,14 +71,14 @@ fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6]
     }
 
     bb5: {
-        StorageLive(_4);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        StorageLive(_6);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        StorageLive(_7);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        _6 = move _2;                    // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
-        goto -> bb3;                     // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        StorageLive(_4);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
+        StorageLive(_6);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
+        StorageLive(_7);                 // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
+        _6 = move _2;                    // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
+        goto -> bb3;                     // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     }
 
     bb6: {
-        unreachable;                     // scope 0 at $DIR/generator-tiny.rs:19:16: 25:6
+        unreachable;                     // scope 0 at $DIR/generator-tiny.rs:19:16: 19:24
     }
 }
diff --git a/src/test/mir-opt/inline/caller-with-trivial-bound.rs b/src/test/mir-opt/inline/caller-with-trivial-bound.rs
new file mode 100644
index 00000000000..8545db89414
--- /dev/null
+++ b/src/test/mir-opt/inline/caller-with-trivial-bound.rs
@@ -0,0 +1,26 @@
+// ignore-wasm32 compiled with panic=abort by default
+// needs-unwind
+
+#![crate_type = "lib"]
+pub trait Factory<T> {
+    type Item;
+}
+
+pub struct IntFactory;
+
+impl<T> Factory<T> for IntFactory {
+    type Item = usize;
+}
+
+// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff
+pub fn foo<T>()
+where
+    IntFactory: Factory<T>,
+{
+    let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
+}
+
+#[inline(always)]
+pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
+    0usize
+}
diff --git a/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff
new file mode 100644
index 00000000000..d30c74897b3
--- /dev/null
+++ b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff
@@ -0,0 +1,33 @@
+- // MIR for `foo` before Inline
++ // MIR for `foo` after Inline
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:17:1: 17:1
+      let mut _1: <IntFactory as Factory<T>>::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14
+      scope 1 {
+          debug x => _1;                   // in scope 1 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/caller-with-trivial-bound.rs:20:9: 20:14
+          _1 = bar::<T>() -> bb1;          // scope 0 at $DIR/caller-with-trivial-bound.rs:20:51: 20:61
+                                           // mir::Constant
+                                           // + span: $DIR/caller-with-trivial-bound.rs:20:51: 20:59
+                                           // + literal: Const { ty: fn() -> <IntFactory as Factory<T>>::Item {bar::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _0 = const ();                   // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 21:2
+          drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2
+      }
+  
+      bb2: {
+          StorageDead(_1);                 // scope 0 at $DIR/caller-with-trivial-bound.rs:21:1: 21:2
+          return;                          // scope 0 at $DIR/caller-with-trivial-bound.rs:21:2: 21:2
+      }
+  
+      bb3 (cleanup): {
+          resume;                          // scope 0 at $DIR/caller-with-trivial-bound.rs:16:1: 21:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/cycle.f.Inline.diff b/src/test/mir-opt/inline/cycle.f.Inline.diff
index d42b8397c50..1376ba99d99 100644
--- a/src/test/mir-opt/inline/cycle.f.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.f.Inline.diff
@@ -17,7 +17,7 @@
           _2 = <impl Fn() as Fn<()>>::call(move _3, move _4) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/cycle.rs:6:5: 6:8
                                            // mir::Constant
                                            // + span: $DIR/cycle.rs:6:5: 6:6
-                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/cycle.g.Inline.diff b/src/test/mir-opt/inline/cycle.g.Inline.diff
index 450157e6428..5a8c147a327 100644
--- a/src/test/mir-opt/inline/cycle.g.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.g.Inline.diff
@@ -5,11 +5,11 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:11:8: 11:8
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:12:5: 12:12
 +     let mut _2: fn() {main};             // in scope 0 at $DIR/cycle.rs:12:5: 12:12
-+     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {main}>) { // at $DIR/cycle.rs:12:5: 12:12
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {main};        // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {main} as Fn<()>>::call - shim(fn() {main})) { // at $DIR/cycle.rs:6:5: 6:8
 +         }
 +     }
@@ -21,15 +21,14 @@
 +         _2 = main;                       // scope 0 at $DIR/cycle.rs:12:5: 12:12
                                            // mir::Constant
 -                                          // + span: $DIR/cycle.rs:12:5: 12:6
--                                          // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(fn() {main}) {f::<fn() {main}>}, val: Value(<ZST>) }
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:12:7: 12:11
-                                           // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {main}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         _3 = move (*_4)() -> [return: bb4, unwind: bb2]; // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
@@ -49,7 +48,7 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
diff --git a/src/test/mir-opt/inline/cycle.main.Inline.diff b/src/test/mir-opt/inline/cycle.main.Inline.diff
index 5e2f70799e4..e102c650905 100644
--- a/src/test/mir-opt/inline/cycle.main.Inline.diff
+++ b/src/test/mir-opt/inline/cycle.main.Inline.diff
@@ -5,11 +5,11 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/cycle.rs:16:11: 16:11
       let _1: ();                          // in scope 0 at $DIR/cycle.rs:17:5: 17:9
 +     let mut _2: fn() {g};                // in scope 0 at $DIR/cycle.rs:17:5: 17:9
-+     let mut _5: ();                      // in scope 0 at $DIR/cycle.rs:6:5: 6:8
 +     scope 1 (inlined f::<fn() {g}>) {    // at $DIR/cycle.rs:17:5: 17:9
 +         debug g => _2;                   // in scope 1 at $DIR/cycle.rs:5:6: 5:7
 +         let _3: ();                      // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         let mut _4: &fn() {g};           // in scope 1 at $DIR/cycle.rs:6:5: 6:6
++         let mut _5: ();                  // in scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         scope 2 (inlined <fn() {g} as Fn<()>>::call - shim(fn() {g})) { // at $DIR/cycle.rs:6:5: 6:8
 +             scope 3 (inlined g) {        // at $SRC_DIR/core/src/ops/function.rs:LL:COL
 +                 let mut _6: fn() {main}; // in scope 3 at $DIR/cycle.rs:12:5: 12:12
@@ -31,15 +31,14 @@
 +         _2 = g;                          // scope 0 at $DIR/cycle.rs:17:5: 17:9
                                            // mir::Constant
 -                                          // + span: $DIR/cycle.rs:17:5: 17:6
--                                          // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(fn() {g}) {f::<fn() {g}>}, val: Value(<ZST>) }
 -                                          // mir::Constant
                                            // + span: $DIR/cycle.rs:17:7: 17:8
-                                           // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         StorageLive(_4);                 // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         _4 = &_2;                        // scope 1 at $DIR/cycle.rs:6:5: 6:6
 +         StorageLive(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
-+         _5 = const ();                   // scope 1 at $DIR/cycle.rs:6:5: 6:8
 +         StorageLive(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
 +         StorageLive(_7);                 // scope 4 at $DIR/cycle.rs:6:5: 6:8
 +         StorageLive(_8);                 // scope 4 at $DIR/cycle.rs:6:5: 6:6
@@ -66,7 +65,7 @@
 +         StorageDead(_8);                 // scope 4 at $DIR/cycle.rs:6:7: 6:8
 +         StorageDead(_7);                 // scope 4 at $DIR/cycle.rs:6:8: 6:9
 +         StorageDead(_6);                 // scope 3 at $DIR/cycle.rs:12:5: 12:12
-+         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:5: 6:8
++         StorageDead(_5);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         StorageDead(_4);                 // scope 1 at $DIR/cycle.rs:6:7: 6:8
 +         StorageDead(_3);                 // scope 1 at $DIR/cycle.rs:6:8: 6:9
 +         drop(_2) -> bb1;                 // scope 1 at $DIR/cycle.rs:7:1: 7:2
diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
index d1ab29b8a21..7b306dd9482 100644
--- a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
@@ -28,7 +28,7 @@
                                            // mir::Constant
                                            // + span: $DIR/dyn-trait.rs:33:13: 33:21
                                            // + user_ty: UserType(0)
-                                           // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r T) -> &'r <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -46,9 +46,9 @@
 +         _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn-trait.rs:34:5: 34:22
--                                          // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(&'r <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
 +                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
-+                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
++                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
index 27309328052..2a909702a6d 100644
--- a/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.mk_cycle.Inline.diff
@@ -12,7 +12,7 @@
           _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:21:5: 21:22
                                            // mir::Constant
                                            // + span: $DIR/dyn-trait.rs:21:7: 21:20
-                                           // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
index 0c44c3ada0f..01ebc999cb3 100644
--- a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
@@ -23,9 +23,9 @@
 +         _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
                                            // mir::Constant
 -                                          // + span: $DIR/dyn-trait.rs:27:5: 27:13
--                                          // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(&'r (dyn Cache<V = <C as Cache>::V> + 'r)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
 +                                          // + span: $DIR/dyn-trait.rs:21:7: 21:20
-+                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(Scalar(<ZST>)) }
++                                          // + literal: Const { ty: for<'r> fn(&'r dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
index ade6ccfc7f1..ff338ae58cd 100644
--- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
@@ -21,7 +21,7 @@ fn bar() -> bool {
         _1 = foo;                        // scope 0 at $DIR/inline-any-operand.rs:11:13: 11:16
                                          // mir::Constant
                                          // + span: $DIR/inline-any-operand.rs:11:13: 11:16
-                                         // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(<ZST>) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
         _2 = _1;                         // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
         StorageLive(_3);                 // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index c6b49b66dc5..fc8118d475a 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -19,8 +19,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
             debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18
             let mut _10: i32;            // in scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
             let mut _11: T;              // in scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23
-            let mut _12: &i32;           // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
-            let mut _13: &T;             // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:24
+            let mut _12: &i32;           // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17
+            let mut _13: &T;             // in scope 2 at $DIR/inline-closure-captures.rs:11:13: 11:17
         }
     }
 
@@ -33,8 +33,8 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         Deinit(_3);                      // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         (_3.0: &i32) = move _4;          // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
         (_3.1: &T) = move _5;            // scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24
-        StorageDead(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24
-        StorageDead(_4);                 // scope 0 at $DIR/inline-closure-captures.rs:11:23: 11:24
+        StorageDead(_5);                 // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17
+        StorageDead(_4);                 // scope 0 at $DIR/inline-closure-captures.rs:11:16: 11:17
         StorageLive(_6);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6
         _6 = &_3;                        // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:6
         StorageLive(_7);                 // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
index fd9a540ca16..34762b97c3b 100644
--- a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
@@ -12,7 +12,7 @@
 -         _1 = no_sanitize() -> bb1;       // scope 0 at $DIR/inline-compatibility.rs:24:5: 24:18
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-compatibility.rs:24:5: 24:16
--                                          // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
index e7db7aa382f..fd1e1983d1e 100644
--- a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
@@ -12,7 +12,7 @@
 -         _1 = target_feature() -> bb1;    // scope 0 at $DIR/inline-compatibility.rs:13:5: 13:21
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-compatibility.rs:13:5: 13:19
--                                          // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
index 09bca903c80..bced3f6fe56 100644
--- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_c_variadic.Inline.diff
@@ -13,7 +13,7 @@
           _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline-compatibility.rs:42:13: 42:52
                                            // mir::Constant
                                            // + span: $DIR/inline-compatibility.rs:42:13: 42:16
-                                           // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
index 5af3946f2e5..a4989cbfa09 100644
--- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff
@@ -10,7 +10,7 @@
           _1 = no_sanitize() -> bb1;       // scope 0 at $DIR/inline-compatibility.rs:29:5: 29:18
                                            // mir::Constant
                                            // + span: $DIR/inline-compatibility.rs:29:5: 29:16
-                                           // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
index 8c9fa573ce2..49dd90c971c 100644
--- a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff
@@ -10,7 +10,7 @@
           _1 = target_feature() -> bb1;    // scope 0 at $DIR/inline-compatibility.rs:18:5: 18:21
                                            // mir::Constant
                                            // + span: $DIR/inline-compatibility.rs:18:5: 18:19
-                                           // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
index b732e7cdb9b..8128797d27e 100644
--- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
@@ -5,17 +5,20 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle.rs:13:10: 13:10
       let _1: ();                          // in scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
 +     scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle.rs:14:5: 14:24
++         scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline-cycle.rs:43:9: 43:23
++             scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle.rs:28:9: 28:31
++             }
++         }
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
 -         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
-+         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline-cycle.rs:43:9: 43:23
++         _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:36:9: 36:28
                                            // mir::Constant
 -                                          // + span: $DIR/inline-cycle.rs:14:5: 14:22
--                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
-+                                          // + span: $DIR/inline-cycle.rs:43:9: 43:21
-+                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/inline-cycle.rs:36:9: 36:26
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
index eac5bf8edec..29c793d7bd8 100644
--- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -5,12 +5,15 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle.rs:48:10: 48:10
       let _1: ();                          // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
 +     let mut _2: fn() {f};                // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
-+     let mut _5: ();                      // in scope 0 at $DIR/inline-cycle.rs:54:5: 54:8
 +     scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline-cycle.rs:49:5: 49:12
 +         debug f => _2;                   // in scope 1 at $DIR/inline-cycle.rs:53:22: 53:23
 +         let _3: ();                      // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
 +         let mut _4: fn() {f};            // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
++         let mut _5: ();                  // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
 +         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline-cycle.rs:54:5: 54:8
++             scope 3 (inlined f) {        // at $SRC_DIR/core/src/ops/function.rs:LL:COL
++                 let _6: ();              // in scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
++             }
 +         }
 +     }
   
@@ -21,20 +24,26 @@
 +         _2 = f;                          // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
                                            // mir::Constant
 -                                          // + span: $DIR/inline-cycle.rs:49:5: 49:9
--                                          // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(Scalar(<ZST>)) }
--                                          // mir::Constant
-                                           // + span: $DIR/inline-cycle.rs:49:10: 49:11
-                                           // + literal: Const { ty: fn() {f}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/inline-cycle.rs:49:10: 49:11
++                                          // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
 +         StorageLive(_4);                 // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
 +         _4 = move _2;                    // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
 +         StorageLive(_5);                 // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+         _5 = const ();                   // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+         _3 = move _4() -> bb1;           // scope 2 at $SRC_DIR/core/src/ops/function.rs:LL:COL
++         StorageLive(_6);                 // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
++         _6 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
++                                          // mir::Constant
++                                          // + span: $DIR/inline-cycle.rs:59:5: 59:9
+                                           // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-cycle.rs:49:10: 49:11
++                                          // + span: $DIR/inline-cycle.rs:59:10: 59:11
+                                           // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
       }
   
       bb1: {
-+         StorageDead(_5);                 // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
++         StorageDead(_6);                 // scope 3 at $DIR/inline-cycle.rs:59:12: 59:13
++         StorageDead(_5);                 // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8
 +         StorageDead(_4);                 // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8
 +         StorageDead(_3);                 // scope 1 at $DIR/inline-cycle.rs:54:8: 54:9
 +         StorageDead(_2);                 // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
index 267f53a8dfe..2ccd39e7931 100644
--- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
@@ -4,19 +4,33 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle-generic.rs:8:11: 8:11
       let _1: ();                          // in scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
++     scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24
++         scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31
++             scope 3 (inlined <A as Call>::call) { // at $DIR/inline-cycle-generic.rs:31:9: 31:28
++                 scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle-generic.rs:23:9: 23:31
++                 }
++             }
++         }
++     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
-          _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
+-         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:9:5: 9:24
++         _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline-cycle-generic.rs:31:9: 31:28
                                            // mir::Constant
-                                           // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
-                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
++                                          // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26
+                                           // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
       }
   
       bb1: {
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:9:24: 9:25
           _0 = const ();                   // scope 0 at $DIR/inline-cycle-generic.rs:8:11: 10:2
           return;                          // scope 0 at $DIR/inline-cycle-generic.rs:10:2: 10:2
++     }
++ 
++     bb2 (cleanup): {
++         resume;                          // scope 0 at $DIR/inline-cycle-generic.rs:8:1: 10:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
index ff25c5b4bc3..7cdc1a6b546 100644
--- a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
@@ -13,7 +13,7 @@
 -         _2 = sleep();                    // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-diverging.rs:8:5: 8:10
--                                          // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
 +         goto -> bb1;                     // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
 +     }
 + 
diff --git a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
index da55260e284..595df0aed5f 100644
--- a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
@@ -38,9 +38,9 @@
 +         _7 = begin_panic::<&str>(const "explicit panic"); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-diverging.rs:16:9: 16:14
--                                          // + literal: Const { ty: fn() -> ! {panic}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> ! {panic}, val: Value(<ZST>) }
 +                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
-+                                          // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
++                                          // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
 +                                          // mir::Constant
 +                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
 +                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
index 0a19daa5045..32066cf2e3e 100644
--- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -5,20 +5,20 @@
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
       let _1: (!, !);                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
 +     let mut _2: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
-+     let mut _9: ();                      // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
-+     let mut _10: ();                     // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
 +     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
 +         debug f => _2;                   // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
 +         let _3: !;                       // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
 +         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         let mut _6: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+         let mut _7: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+         let mut _8: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
++         let mut _5: ();                  // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         let mut _7: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
++         let mut _8: ();                  // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:16
++         let mut _9: !;                   // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
++         let mut _10: !;                  // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
 +         scope 2 {
 +             debug a => _3;               // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+             let _5: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++             let _6: !;                   // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
 +             scope 3 {
-+                 debug b => _5;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++                 debug b => _6;           // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
 +             }
 +             scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
 +                 scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
@@ -38,15 +38,14 @@
 +         _2 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
                                            // mir::Constant
 -                                          // + span: $DIR/inline-diverging.rs:22:5: 22:15
--                                          // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(<ZST>) }
 -                                          // mir::Constant
                                            // + span: $DIR/inline-diverging.rs:22:16: 22:21
-                                           // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
 +         StorageLive(_3);                 // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
 +         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
 +         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+         StorageLive(_9);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+         _9 = const ();                   // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
++         StorageLive(_5);                 // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
 +     }
 + 
diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
index 3e1c4a46701..bb093c5bc09 100644
--- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff
@@ -4,22 +4,22 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11
       let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
-      let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
-      let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
-      let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+      let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+      let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
+      let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
 +     let mut _7: bool;                    // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46
       scope 1 {
           debug _r => _1;                  // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11
       }
 +     scope 2 (inlined g) {                // at $DIR/inline-generator.rs:9:28: 9:31
 +     }
-+     scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
++     scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
 +         debug pointer => _3;             // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
-+         let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
++         let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         scope 4 {
-+             scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL
++             scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL
 +                 debug pointer => _5;     // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+                 let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++                 let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +             }
 +         }
 +     }
@@ -29,10 +29,10 @@
 +         let mut _9: bool;                // in scope 6 at $DIR/inline-generator.rs:15:20: 15:21
 +         let mut _10: bool;               // in scope 6 at $DIR/inline-generator.rs:15:9: 15:9
 +         let _11: bool;                   // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7
-+         let mut _12: u32;                // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         let mut _12: u32;                // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:8
 +     }
   
       bb0: {
@@ -43,18 +43,18 @@
 -         _4 = g() -> bb1;                 // scope 0 at $DIR/inline-generator.rs:9:28: 9:31
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:28: 9:29
--                                          // + literal: Const { ty: fn() -> impl Generator<bool> {g}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> impl Generator<bool> {g}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
 +         Deinit(_4);                      // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
 +         discriminant(_4) = 0;            // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
           _3 = &mut _4;                    // scope 0 at $DIR/inline-generator.rs:9:23: 9:31
--         _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+-         _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:32
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:14: 9:22
 -                                          // + user_ty: UserType(0)
--                                          // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>::new}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new}, val: Value(<ZST>) }
 -     }
 - 
 -     bb2: {
@@ -63,24 +63,24 @@
 +         StorageLive(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         _6 = move _5;                    // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         Deinit(_2);                      // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+         (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++         (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_6);                 // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
 +         StorageDead(_5);                 // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
           StorageDead(_3);                 // scope 0 at $DIR/inline-generator.rs:9:31: 9:32
--         _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
+-         _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-generator.rs:9:33: 9:39
--                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:41] as Generator<bool>>::resume}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(Pin<&'r mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
 +         StorageLive(_7);                 // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         _7 = const false;                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_10);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_11);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
 +         StorageLive(_12);                // scope 0 at $DIR/inline-generator.rs:9:14: 9:46
-+         StorageLive(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         _13 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         _12 = discriminant((*_13));      // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         StorageDead(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         StorageLive(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         _13 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         _12 = discriminant((*_13));      // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         StorageDead(_13);                // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
       }
   
 -     bb3: {
@@ -102,7 +102,7 @@
 +     }
 + 
 +     bb3: {
-+         _11 = move _7;                   // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         _11 = move _7;                   // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
 +         StorageLive(_8);                 // scope 6 at $DIR/inline-generator.rs:15:17: 15:39
 +         StorageLive(_9);                 // scope 6 at $DIR/inline-generator.rs:15:20: 15:21
 +         _9 = _11;                        // scope 6 at $DIR/inline-generator.rs:15:20: 15:21
@@ -125,32 +125,32 @@
 +         ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant(_1) = 0;            // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         StorageLive(_14);                // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+         _14 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
++         _14 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         discriminant((*_14)) = 3;        // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         StorageDead(_14);                // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
 +         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:11: 15:39
 +     }
 + 
 +     bb7: {
-+         StorageLive(_8);                 // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+         _10 = move _7;                   // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         StorageLive(_8);                 // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
++         _10 = move _7;                   // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
 +         StorageDead(_8);                 // scope 6 at $DIR/inline-generator.rs:15:38: 15:39
-+         Deinit(_1);                      // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         discriminant(_1) = 1;            // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         StorageLive(_15);                // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         _15 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         discriminant((*_15)) = 1;        // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         StorageDead(_15);                // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:41: 15:41
++         Deinit(_1);                      // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         discriminant(_1) = 1;            // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         StorageLive(_15);                // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         _15 = move (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         discriminant((*_15)) = 1;        // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         StorageDead(_15);                // scope 6 at $DIR/inline-generator.rs:15:8: 15:8
++         goto -> bb1;                     // scope 0 at $DIR/inline-generator.rs:15:8: 15:8
 +     }
 + 
 +     bb8: {
-+         assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
 +     }
 + 
 +     bb9: {
-+         unreachable;                     // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++         unreachable;                     // scope 6 at $DIR/inline-generator.rs:15:5: 15:8
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
index 65891cbb660..05bd99b62cd 100644
--- a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
+++ b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
@@ -14,7 +14,7 @@
           _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:51:5: 51:26
                                            // mir::Constant
                                            // + span: $DIR/inline-instruction-set.rs:51:5: 51:24
-                                           // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -23,7 +23,7 @@
           _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:52:5: 52:26
                                            // mir::Constant
                                            // + span: $DIR/inline-instruction-set.rs:52:5: 52:24
-                                           // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
       }
   
       bb2: {
@@ -32,7 +32,7 @@
 -         _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:53:5: 53:30
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-instruction-set.rs:53:5: 53:28
--                                          // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
 -     }
 - 
 -     bb3: {
diff --git a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
index 20e1d0ae4d5..cb0d01428c9 100644
--- a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
+++ b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
@@ -14,7 +14,7 @@
           _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:42:5: 42:26
                                            // mir::Constant
                                            // + span: $DIR/inline-instruction-set.rs:42:5: 42:24
-                                           // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -23,7 +23,7 @@
 -         _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:43:5: 43:26
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-instruction-set.rs:43:5: 43:24
--                                          // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
 -     }
 - 
 -     bb2: {
@@ -33,7 +33,7 @@
 +         _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:46:5: 46:30
                                            // mir::Constant
                                            // + span: $DIR/inline-instruction-set.rs:46:5: 46:28
-                                           // + literal: Const { ty: fn() {instruction_set_default}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
       }
   
 -     bb3: {
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
index 89414574898..17050f184cb 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
@@ -28,7 +28,7 @@
           _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
                                            // mir::Constant
                                            // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -44,7 +44,7 @@
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
--                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
 -     }
 - 
 -     bb2: {
@@ -75,7 +75,7 @@
 -         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
--                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
 -     }
 - 
 -     bb5 (cleanup): {
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
index 89414574898..17050f184cb 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
@@ -28,7 +28,7 @@
           _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
                                            // mir::Constant
                                            // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
-                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -44,7 +44,7 @@
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
--                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
 -     }
 - 
 -     bb2: {
@@ -75,7 +75,7 @@
 -         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb5; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
--                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
 -     }
 - 
 -     bb5 (cleanup): {
diff --git a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
index eca76df576b..45023083be6 100644
--- a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
@@ -15,7 +15,7 @@ fn main() -> () {
         _1 = not_inlined() -> bb1;       // scope 0 at $DIR/inline-options.rs:9:5: 9:18
                                          // mir::Constant
                                          // + span: $DIR/inline-options.rs:9:5: 9:16
-                                         // + literal: Const { ty: fn() {not_inlined}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {not_inlined}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -25,7 +25,7 @@ fn main() -> () {
         _3 = g() -> bb2;                 // scope 1 at $DIR/inline-options.rs:16:23: 16:26
                                          // mir::Constant
                                          // + span: $DIR/inline-options.rs:16:23: 16:24
-                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -34,7 +34,7 @@ fn main() -> () {
         _4 = g() -> bb3;                 // scope 1 at $DIR/inline-options.rs:16:28: 16:31
                                          // mir::Constant
                                          // + span: $DIR/inline-options.rs:16:28: 16:29
-                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 
     bb3: {
@@ -43,7 +43,7 @@ fn main() -> () {
         _5 = g() -> bb4;                 // scope 1 at $DIR/inline-options.rs:16:33: 16:36
                                          // mir::Constant
                                          // + span: $DIR/inline-options.rs:16:33: 16:34
-                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
index 2d85ff9a0cb..fcc1767578e 100644
--- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
@@ -27,7 +27,7 @@ fn bar() -> bool {
         _1 = foo;                        // scope 0 at $DIR/inline-retag.rs:11:13: 11:16
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:11:13: 11:16
-                                         // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r, 's> fn(&'r i32, &'s i32) -> bool {foo}, val: Value(<ZST>) }
         StorageLive(_2);                 // scope 1 at $DIR/inline-retag.rs:12:5: 12:6
         _2 = _1;                         // scope 1 at $DIR/inline-retag.rs:12:5: 12:6
         StorageLive(_3);                 // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
index 7170cd40572..d67b07b0181 100644
--- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
+++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
@@ -14,7 +14,7 @@
 -         _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-shims.rs:6:7: 6:12
--                                          // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
diff --git a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
index aa55c90fcfb..5c7cbc9b419 100644
--- a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
+++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
@@ -24,7 +24,7 @@
           _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:11:14: 11:40
                                            // mir::Constant
                                            // + span: $DIR/inline-shims.rs:11:14: 11:37
-                                           // + literal: Const { ty: unsafe fn(*mut Vec<A>) {std::ptr::drop_in_place::<Vec<A>>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe fn(*mut Vec<A>) {std::ptr::drop_in_place::<Vec<A>>}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -35,7 +35,7 @@
 -         _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-shims.rs:12:14: 12:37
--                                          // + literal: Const { ty: unsafe fn(*mut Option<B>) {std::ptr::drop_in_place::<Option<B>>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe fn(*mut Option<B>) {std::ptr::drop_in_place::<Option<B>>}, val: Value(<ZST>) }
 +         StorageLive(_6);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
 +         StorageLive(_7);                 // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
 +         _6 = discriminant((*_5));        // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
index 8e93baf6a70..747eeb98450 100644
--- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
@@ -15,7 +15,7 @@
 -         _1 = <Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-specialization.rs:5:13: 5:36
--                                          // + literal: Const { ty: fn() -> u32 {<Vec<()> as Foo>::bar}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: fn() -> u32 {<Vec<()> as Foo>::bar}, val: Value(<ZST>) }
 -     }
 - 
 -     bb1: {
diff --git a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
index 0be979901ac..1646de9289a 100644
--- a/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method.test.Inline.after.mir
@@ -11,7 +11,7 @@ fn test(_1: &dyn X) -> u32 {
         _0 = <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:9:5: 9:10
                                          // mir::Constant
                                          // + span: $DIR/inline-trait-method.rs:9:7: 9:8
-                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> u32 {<dyn X as X>::y}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
index 64375b6edc9..eb6c09c1cd7 100644
--- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
@@ -21,7 +21,7 @@ fn test2(_1: &dyn X) -> bool {
         _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
                                          // mir::Constant
                                          // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8
-                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
index 7c3048a69af..242073574f2 100644
--- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
@@ -2,8 +2,8 @@
 
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:4:11: 4:11
-    let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10
-    let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:33]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6
+    let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:5:9: 5:10
+    let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:6
     let mut _3: ((),);                   // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
     let mut _4: ();                      // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:7: 6:9
     let mut _5: ();                      // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
index b44f9900d6c..f91d3526226 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff
@@ -19,7 +19,7 @@
 +         _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:13
-                                           // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -29,7 +29,7 @@
 -         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
 -                                          // mir::Constant
 -                                          // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
 +         _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
       }
   
diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
index 8a998fb5000..4446280e720 100644
--- a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
+++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff
@@ -18,7 +18,7 @@
           _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:13
-                                           // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -29,8 +29,8 @@
 +         _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
                                            // mir::Constant
                                            // + span: $DIR/issue-78442.rs:11:5: 11:15
--                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
-+                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
++                                          // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 34ba7dfdcc5..9384ce52cc8 100644
--- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -22,7 +22,7 @@
           _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17
                                            // mir::Constant
                                            // + span: /the/src/instrument_coverage.rs:12:12: 12:15
-                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
index 7113c42b9c7..19110894dc7 100644
--- a/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41110.main.ElaborateDrops.after.mir
@@ -23,7 +23,7 @@ fn main() -> () {
         _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:8:21: 8:27
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:8:23: 8:25
-                                         // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(S) -> S {S::id}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -32,7 +32,7 @@ fn main() -> () {
         _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:8:13: 8:28
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:8:15: 8:20
-                                         // + literal: Const { ty: fn(S, S) {S::other}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(S, S) {S::other}, val: Value(<ZST>) }
     }
 
     bb2: {
diff --git a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
index c4e852ca321..1901ea1747e 100644
--- a/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41110.test.ElaborateDrops.after.mir
@@ -28,7 +28,7 @@ fn test() -> () {
         _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:17:5: 17:12
                                          // mir::Constant
                                          // + span: $DIR/issue-41110.rs:17:5: 17:9
-                                         // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
index ce7ca20358e..a4ff718f422 100644
--- a/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
+++ b/src/test/mir-opt/issue_41888.main.ElaborateDrops.after.mir
@@ -29,7 +29,7 @@ fn main() -> () {
         _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:8:8: 8:14
                                          // mir::Constant
                                          // + span: $DIR/issue-41888.rs:8:8: 8:12
-                                         // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_49232.main.mir_map.0.mir b/src/test/mir-opt/issue_49232.main.mir_map.0.mir
index 2f8931382a6..6301763449b 100644
--- a/src/test/mir-opt/issue_49232.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_49232.main.mir_map.0.mir
@@ -59,7 +59,7 @@ fn main() -> () {
         _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:13:9: 13:22
                                          // mir::Constant
                                          // + span: $DIR/issue-49232.rs:13:9: 13:13
-                                         // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(<ZST>) }
     }
 
     bb9: {
diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
index 4d06b91e6dc..f21e9bbd270 100644
--- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
@@ -34,7 +34,7 @@ fn test() -> Option<Box<u32>> {
         _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:10: 9:21
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -46,7 +46,7 @@ fn test() -> Option<Box<u32>> {
         _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:15: 9:20
-                                         // + literal: Const { ty: fn(Option<u32>) -> ControlFlow<<Option<u32> as Try>::Residual, <Option<u32> as Try>::Output> {<Option<u32> as Try>::branch}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Option<u32>) -> ControlFlow<<Option<u32> as Try>::Residual, <Option<u32> as Try>::Output> {<Option<u32> as Try>::branch}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -76,7 +76,7 @@ fn test() -> Option<Box<u32>> {
         _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:19: 9:20
-                                         // + literal: Const { ty: fn(Option<Infallible>) -> Option<Box<u32>> {<Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Option<Infallible>) -> Option<Box<u32>> {<Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual}, val: Value(<ZST>) }
     }
 
     bb6: {
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
index 2e6783b7f3c..f4602d147c9 100644
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir
@@ -25,7 +25,7 @@ fn main() -> () {
         _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
                                          // mir::Constant
                                          // + span: $DIR/issue-72181.rs:24:13: 24:32
-                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
index 2e6783b7f3c..f4602d147c9 100644
--- a/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir
@@ -25,7 +25,7 @@ fn main() -> () {
         _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:24:13: 24:34
                                          // mir::Constant
                                          // + span: $DIR/issue-72181.rs:24:13: 24:32
-                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
index 899c8468789..9842e26ab69 100644
--- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
+++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
@@ -24,7 +24,7 @@ fn main() -> () {
         _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:17:9: 17:40
-                                         // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -37,7 +37,7 @@ fn main() -> () {
         _4 = f(move _5) -> bb4;          // scope 1 at $DIR/issue-72181-1.rs:20:5: 20:9
                                          // mir::Constant
                                          // + span: $DIR/issue-72181-1.rs:20:5: 20:6
-                                         // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(<ZST>) }
     }
 
     bb2: {
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index 8b0a73ec4ba..92952651544 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -98,7 +98,7 @@
           _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index 8b0a73ec4ba..92952651544 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -98,7 +98,7 @@
           _14 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _15, move _17, move _19); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index c96a6641bab..f52b1a953c1 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -135,7 +135,7 @@
           _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index c96a6641bab..f52b1a953c1 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -135,7 +135,7 @@
           _21 = core::panicking::assert_failed::<i32, i32>(const core::panicking::AssertKind::Eq, move _23, move _25, move _27); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r i32, &'s i32, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<i32, i32>}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // + literal: Const { ty: core::panicking::AssertKind, val: Value(Scalar(0x00)) }
diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
index 29bcef26518..14bb66910fe 100644
--- a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
+++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
@@ -70,7 +70,7 @@
           _22 = core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/panic.rs:LL:COL
-                                           // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) }
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/panic.rs:LL:COL
                                            // + literal: Const { ty: &str, val: Value(Slice(..)) }
diff --git a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
index 40e7b74453a..dd85434d879 100644
--- a/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
+++ b/src/test/mir-opt/issues/issue_59352.num_to_digit.PreCodegen.after.mir
@@ -39,7 +39,7 @@ fn num_to_digit(_1: char) -> u32 {
         _7 = char::methods::<impl char>::to_digit(move _8, const 8_u32) -> bb5; // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/char/methods.rs:LL:COL
-                                         // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -50,7 +50,7 @@ fn num_to_digit(_1: char) -> u32 {
         _3 = char::methods::<impl char>::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue-59352.rs:14:26: 14:41
                                          // mir::Constant
                                          // + span: $DIR/issue-59352.rs:14:30: 14:38
-                                         // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -90,7 +90,7 @@ fn num_to_digit(_1: char) -> u32 {
         _11 = core::panicking::panic(const "called `Option::unwrap()` on a `None` value"); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/option.rs:LL:COL
-                                         // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(<ZST>) }
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/option.rs:LL:COL
                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
index b8023a6a8e6..08ff3b67655 100644
--- a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
+++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff
@@ -27,7 +27,7 @@
           _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:7:37: 7:53
                                            // mir::Constant
                                            // + span: $DIR/issue-75439.rs:7:37: 7:46
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -50,7 +50,7 @@
           _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue-75439.rs:10:23: 10:36
                                            // mir::Constant
                                            // + span: $DIR/issue-75439.rs:10:23: 10:32
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
       }
   
       bb5: {
diff --git a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
index 3f5f71f8082..1b9e46c6a6d 100644
--- a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
@@ -8,7 +8,7 @@
 -         _0 = std::intrinsics::min_align_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:19:5: 19:40
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(<ZST>) }
 +         _0 = AlignOf(T);                 // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:19:5: 19:42
       }
diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index 88d2867fc42..9bda88ce2c7 100644
--- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -32,7 +32,7 @@
 -         _2 = discriminant_value::<T>(move _3) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:74:5: 74:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
 +         _2 = discriminant((*_3));        // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:74:5: 74:45
       }
@@ -53,7 +53,7 @@
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:75:5: 75:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
 +         _5 = discriminant((*_6));        // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
 +         goto -> bb2;                     // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
       }
@@ -74,7 +74,7 @@
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:76:5: 76:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
 +         _9 = discriminant((*_10));       // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
 +         goto -> bb3;                     // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
       }
@@ -95,7 +95,7 @@
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:77:5: 77:41
--                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> extern "rust-intrinsic" fn(&'r E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
 +         _13 = discriminant((*_14));      // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48
 +         goto -> bb4;                     // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48
       }
diff --git a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir
index 7750624db30..a12aa1d6686 100644
--- a/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir
+++ b/src/test/mir-opt/lower_intrinsics.f_u64.PreCodegen.before.mir
@@ -20,7 +20,7 @@ fn f_u64() -> () {
         _2 = f_non_zst::<u64>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:48:9: 48:21
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics.rs:48:9: 48:18
-                                         // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(u64) {f_non_zst::<u64>}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir
index 4d4e65d3114..49e3b9144a5 100644
--- a/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir
+++ b/src/test/mir-opt/lower_intrinsics.f_unit.PreCodegen.before.mir
@@ -6,6 +6,7 @@ fn f_unit() -> () {
     scope 1 (inlined f_dispatch::<()>) { // at $DIR/lower_intrinsics.rs:34:5: 34:19
         debug t => _1;                   // in scope 1 at $DIR/lower_intrinsics.rs:44:22: 44:23
         let _2: ();                      // in scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
+        let mut _3: ();                  // in scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
         scope 2 (inlined std::mem::size_of::<()>) { // at $DIR/lower_intrinsics.rs:45:8: 45:32
         }
     }
@@ -13,13 +14,15 @@ fn f_unit() -> () {
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:34:16: 34:18
         StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
-        _2 = f_zst::<()>(const ()) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
+        StorageLive(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:46:15: 46:16
+        _2 = f_zst::<()>(move _3) -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:46:9: 46:17
                                          // mir::Constant
                                          // + span: $DIR/lower_intrinsics.rs:46:9: 46:14
-                                         // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(()) {f_zst::<()>}, val: Value(<ZST>) }
     }
 
     bb1: {
+        StorageDead(_3);                 // scope 1 at $DIR/lower_intrinsics.rs:46:16: 46:17
         StorageDead(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:46:17: 46:18
         StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:34:18: 34:19
         return;                          // scope 0 at $DIR/lower_intrinsics.rs:35:2: 35:2
diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
index 7e1e066366c..6c99e1b7ca6 100644
--- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
@@ -12,7 +12,7 @@
 -         _0 = std::intrinsics::forget::<T>(move _2) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:24:5: 24:29
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(<ZST>) }
 +         _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:24:5: 24:32
       }
diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
index 276227d8c01..41dac17dcb6 100644
--- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
@@ -14,7 +14,7 @@
           _1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:62:21: 62:51
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:62:21: 62:51
-                                           // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
           StorageLive(_2);                 // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14
           _2 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:14
 -         _0 = move _2() -> bb1;           // scope 1 at $DIR/lower_intrinsics.rs:63:5: 63:16
diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
index b5a77702a8e..cd6da6f1dc7 100644
--- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
@@ -8,7 +8,7 @@
 -         _0 = std::intrinsics::size_of::<T>() -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:14:5: 14:35
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
 +         _0 = SizeOf(T);                  // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:14:5: 14:37
       }
diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
index eb463afbf77..0ce8d85070c 100644
--- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
@@ -15,7 +15,7 @@
 -         _3 = std::intrinsics::unreachable(); // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:29:14: 29:43
--                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
 +         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:29:14: 29:45
       }
   
diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
index 5a0286bad2f..ebe240121cc 100644
--- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -33,7 +33,7 @@
 -         _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:7:14: 7:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(<ZST>) }
 +         _3 = Add(move _4, move _5);      // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
       }
@@ -49,7 +49,7 @@
 -         _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:8:14: 8:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(<ZST>) }
 +         _6 = Sub(move _7, move _8);      // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 +         goto -> bb2;                     // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
       }
@@ -65,7 +65,7 @@
 -         _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(<ZST>) }
 +         _9 = Mul(move _10, move _11);    // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 +         goto -> bb3;                     // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
       }
diff --git a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
index 13241d882f2..96404f0506c 100644
--- a/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
+++ b/src/test/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.diff
@@ -23,7 +23,7 @@
 -         _5 = core::slice::<impl [u8]>::len(move _6) -> bb1; // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_slice_len.rs:5:22: 5:25
--                                          // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: for<'r> fn(&'r [u8]) -> usize {core::slice::<impl [u8]>::len}, val: Value(<ZST>) }
 +         _5 = Len((*_6));                 // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27
 +         goto -> bb1;                     // scope 0 at $DIR/lower_slice_len.rs:5:16: 5:27
       }
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
index 0d0204e126a..722097630f7 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
@@ -61,7 +61,7 @@ fn full_tested_match() -> () {
         _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:14:20: 14:27
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:14:20: 14:25
-                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
     }
 
     bb6: {
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
index 270cc85ce03..df052e32157 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir
@@ -62,7 +62,7 @@ fn full_tested_match2() -> () {
         _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:25:20: 25:27
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:25:20: 25:25
-                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
     }
 
     bb6: {
diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
index 2f76e0137bd..fc50db397fd 100644
--- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
+++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir
@@ -70,7 +70,7 @@ fn main() -> () {
         _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:34:21: 34:28
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:34:21: 34:26
-                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
     }
 
     bb6: {
@@ -113,7 +113,7 @@ fn main() -> () {
         _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:36:20: 36:29
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:36:20: 36:26
-                                         // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(<ZST>) }
     }
 
     bb11: {
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
index 7d9e012bb29..e1d870ef9a4 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir
@@ -70,30 +70,30 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
-                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
     }
 
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
-                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
     }
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
index c555e0441f4..2f9dff00b63 100644
--- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
+++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir
@@ -70,30 +70,30 @@ fn main() -> () {
         StorageLive(_8);                 // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
         StorageLive(_9);                 // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
         _9 = (*_6);                      // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:21:15: 21:17
-        _8 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
+        _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:21:9: 21:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
-                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
     }
 
     bb3: {
         StorageDead(_9);                 // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:21:17: 21:18
         StorageDead(_8);                 // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:21:18: 21:19
-        _0 = const ConstValue(Scalar(<ZST>): ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
+        _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:13: 22:6
         goto -> bb6;                     // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
     bb4: {
         StorageLive(_10);                // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
-        _10 = ConstValue(Scalar(<ZST>): fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
+        _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:23:9: 23:18
                                          // mir::Constant
                                          // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
-                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
     }
 
     bb5: {
         StorageDead(_10);                // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:23:18: 23:19
-        _0 = const ConstValue(Scalar(<ZST>): ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
+        _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:22:12: 24:6
         goto -> bb6;                     // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:20:5: 24:6
     }
 
diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
index 8a297cea2b9..fda6cd61207 100644
--- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
@@ -23,7 +23,7 @@ fn unwrap(_1: Option<T>) -> T {
         _4 = begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
-                                         // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
                                          // mir::Constant
                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
index bdab2d93222..0c814fd9d8d 100644
--- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir
@@ -20,7 +20,7 @@ fn main() -> () {
         _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34
                                          // mir::Constant
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32
-                                         // + literal: Const { ty: for<'r> fn(&'r str) -> String {<str as ToString>::to_string}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r str) -> String {<str as ToString>::to_string}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -28,7 +28,7 @@ fn main() -> () {
         _1 = std::mem::drop::<String>(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35
                                          // mir::Constant
                                          // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19
-                                         // + literal: Const { ty: fn(String) {std::mem::drop::<String>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(String) {std::mem::drop::<String>}, val: Value(<ZST>) }
     }
 
     bb2: {
diff --git a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir
index 5bf8655fcec..8ee81e679ec 100644
--- a/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir
+++ b/src/test/mir-opt/receiver_ptr_mutability.main.mir_map.0.mir
@@ -32,7 +32,7 @@ fn main() -> () {
         _1 = null_mut::<Test>() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver-ptr-mutability.rs:14:26: 14:46
                                          // mir::Constant
                                          // + span: $DIR/receiver-ptr-mutability.rs:14:26: 14:44
-                                         // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -47,7 +47,7 @@ fn main() -> () {
         _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:15:5: 15:12
                                          // mir::Constant
                                          // + span: $DIR/receiver-ptr-mutability.rs:15:9: 15:10
-                                         // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -75,7 +75,7 @@ fn main() -> () {
         _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:19:5: 19:16
                                          // mir::Constant
                                          // + span: $DIR/receiver-ptr-mutability.rs:19:13: 19:14
-                                         // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
     }
 
     bb3: {
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index 447fe654c0c..b2bfe4280b0 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -60,7 +60,7 @@
           _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
index c8c45da1913..05e83b13a50 100644
--- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
@@ -81,7 +81,7 @@ fn array_casts() -> () {
         _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:60:15: 60:23
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:60:17: 60:20
-                                         // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -112,7 +112,7 @@ fn array_casts() -> () {
         _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:64:26: 64:34
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:64:28: 64:31
-                                         // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -176,7 +176,7 @@ fn array_casts() -> () {
         _28 = core::panicking::assert_failed::<usize, usize>(move _29, move _30, move _32, move _34); // scope 8 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r usize, &'s usize, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r, 's, 't0> fn(core::panicking::AssertKind, &'r usize, &'s usize, Option<Arguments<'t0>>) -> ! {core::panicking::assert_failed::<usize, usize>}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
index 09cf06cacd9..8057aa13a9f 100644
--- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
+++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir
@@ -11,7 +11,7 @@ fn std::ptr::drop_in_place(_1: *mut Test) -> () {
         _3 = <Test as Drop>::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Test) {<Test as Drop>::drop}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r mut Test) {<Test as Drop>::drop}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
index 0b8c4d25d2d..5808c607752 100644
--- a/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir
@@ -9,14 +9,14 @@ fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 {
     }
 
     bb0: {
-        Retag([fn entry] _1);            // scope 0 at $DIR/retag.rs:40:31: 43:6
-        Retag([fn entry] _2);            // scope 0 at $DIR/retag.rs:40:31: 43:6
+        Retag([fn entry] _1);            // scope 0 at $DIR/retag.rs:40:31: 40:48
+        Retag([fn entry] _2);            // scope 0 at $DIR/retag.rs:40:31: 40:48
         StorageLive(_3);                 // scope 0 at $DIR/retag.rs:41:13: 41:15
         _3 = _2;                         // scope 0 at $DIR/retag.rs:41:18: 41:19
         Retag(_3);                       // scope 0 at $DIR/retag.rs:41:18: 41:19
         _0 = _2;                         // scope 1 at $DIR/retag.rs:42:9: 42:10
         Retag(_0);                       // scope 1 at $DIR/retag.rs:42:9: 42:10
         StorageDead(_3);                 // scope 0 at $DIR/retag.rs:43:5: 43:6
-        return;                          // scope 0 at $DIR/retag.rs:43:6: 43:6
+        return;                          // scope 0 at $DIR/retag.rs:40:48: 40:48
     }
 }
diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index 2fda8c949b0..a3490d460ec 100644
--- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -74,7 +74,7 @@ fn main() -> () {
         _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:32:17: 32:36
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:32:25: 32:28
-                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -121,7 +121,7 @@ fn main() -> () {
                                          // ]
         Retag(_14);                      // scope 1 at $DIR/retag.rs:40:31: 43:6
         _13 = move _14 as for<'r> fn(&'r i32) -> &'r i32 (Pointer(ClosureFnPointer(Normal))); // scope 1 at $DIR/retag.rs:40:31: 43:6
-        StorageDead(_14);                // scope 1 at $DIR/retag.rs:43:5: 43:6
+        StorageDead(_14);                // scope 1 at $DIR/retag.rs:40:47: 40:48
         StorageLive(_15);                // scope 6 at $DIR/retag.rs:44:9: 44:11
         StorageLive(_16);                // scope 6 at $DIR/retag.rs:44:14: 44:15
         _16 = _13;                       // scope 6 at $DIR/retag.rs:44:14: 44:15
@@ -159,7 +159,7 @@ fn main() -> () {
         _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:47:5: 47:24
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:13: 47:20
-                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
     }
 
     bb4: {
@@ -183,7 +183,7 @@ fn main() -> () {
         _27 = array_casts() -> bb6;      // scope 8 at $DIR/retag.rs:52:5: 52:18
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:52:5: 52:16
-                                         // + literal: Const { ty: fn() {array_casts}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) }
     }
 
     bb6: {
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
index 1c5a8900236..6d41d5b7437 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-early-opt.diff
@@ -21,7 +21,7 @@
 +         _2 = bar() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:9:12: 9:15
-                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
       }
   
 -     bb3: {
diff --git a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
index b079bd7b57c..78841d28b85 100644
--- a/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
+++ b/src/test/mir-opt/simplify_cfg.main.SimplifyCfg-initial.diff
@@ -22,7 +22,7 @@
 +         _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at $DIR/simplify_cfg.rs:9:12: 9:17
                                            // mir::Constant
                                            // + span: $DIR/simplify_cfg.rs:9:12: 9:15
-                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
index d11c70b1efe..f729b53b204 100644
--- a/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
+++ b/src/test/mir-opt/simplify_if.main.SimplifyConstCondition-after-const-prop.diff
@@ -18,7 +18,7 @@
           _2 = noop() -> bb2;              // scope 0 at $DIR/simplify_if.rs:7:9: 7:15
                                            // mir::Constant
                                            // + span: $DIR/simplify_if.rs:7:9: 7:13
-                                           // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {noop}, val: Value(<ZST>) }
       }
   
       bb2: {
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
index 1bba1e9e88a..f4f1b9d4eb8 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
@@ -15,7 +15,8 @@
 -     let mut _10: u8;                     // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30
 -     let mut _11: Temp;                   // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 +     let _1: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
-+     let _2: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++     let mut _2: ((), ());                // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
++     let _3: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
       scope 1 {
       }
   
@@ -32,12 +33,13 @@
 -         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20
 -         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21
 -         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21
--         _4 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
+-         _4 = use_zst(move _5) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
 +         StorageLive(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
-+         _1 = use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
++         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21
++         _1 = use_zst(move _2) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22
                                            // mir::Constant
                                            // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
-                                           // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -49,19 +51,20 @@
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28
 -         StorageDead(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34
 -         _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++         StorageDead(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22
 +         StorageDead(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23
-+         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
-+         _2 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++         StorageLive(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
++         _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35
                                            // mir::Constant
                                            // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11
-                                           // + literal: Const { ty: fn(u8) {use_u8}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
       }
   
       bb2: {
 -         StorageDead(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:34: 16:35
 -         StorageDead(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36
 -         StorageDead(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36
-+         StorageDead(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36
++         StorageDead(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36
           return;                          // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:17:2: 17:2
       }
   }
diff --git a/src/test/mir-opt/simplify_match.main.ConstProp.diff b/src/test/mir-opt/simplify_match.main.ConstProp.diff
index 1c8d043a603..6314abe6f39 100644
--- a/src/test/mir-opt/simplify_match.main.ConstProp.diff
+++ b/src/test/mir-opt/simplify_match.main.ConstProp.diff
@@ -29,7 +29,7 @@
           _0 = noop() -> bb3;              // scope 0 at $DIR/simplify_match.rs:7:17: 7:23
                                            // mir::Constant
                                            // + span: $DIR/simplify_match.rs:7:17: 7:21
-                                           // + literal: Const { ty: fn() {noop}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {noop}, val: Value(<ZST>) }
       }
   
       bb3: {
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
index d7d2cdf9b0c..d36d369003a 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
@@ -33,7 +33,7 @@ fn move_out_by_subslice() -> () {
         _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
                                          // mir::Constant
                                          // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -52,7 +52,7 @@ fn move_out_by_subslice() -> () {
         _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
                                          // mir::Constant
                                          // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb3: {
diff --git a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
index 18bc1a17c1b..e6c8b66c25a 100644
--- a/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
+++ b/src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
@@ -33,7 +33,7 @@ fn move_out_from_end() -> () {
         _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
                                          // mir::Constant
                                          // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb1: {
@@ -52,7 +52,7 @@ fn move_out_from_end() -> () {
         _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
                                          // mir::Constant
                                          // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26
-                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
     }
 
     bb3: {
diff --git a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
index 70486f546d7..5aa4f1b3432 100644
--- a/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
+++ b/src/test/mir-opt/unreachable.main.UnreachablePropagation.diff
@@ -22,7 +22,7 @@
           _1 = empty() -> bb1;             // scope 1 at $DIR/unreachable.rs:9:23: 9:30
                                            // mir::Constant
                                            // + span: $DIR/unreachable.rs:9:23: 9:28
-                                           // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(<ZST>) }
       }
   
       bb1: {
diff --git a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
index d9f2681d145..b95ab881ef0 100644
--- a/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
+++ b/src/test/mir-opt/unreachable_diverging.main.UnreachablePropagation.diff
@@ -24,7 +24,7 @@
           _2 = empty() -> bb1;             // scope 2 at $DIR/unreachable_diverging.rs:14:25: 14:32
                                            // mir::Constant
                                            // + span: $DIR/unreachable_diverging.rs:14:25: 14:30
-                                           // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() -> Option<Empty> {empty}, val: Value(<ZST>) }
       }
   
       bb1: {
@@ -48,7 +48,7 @@
 +         _5 = loop_forever() -> bb4;      // scope 2 at $DIR/unreachable_diverging.rs:16:13: 16:27
                                            // mir::Constant
                                            // + span: $DIR/unreachable_diverging.rs:16:13: 16:25
-                                           // + literal: Const { ty: fn() {loop_forever}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: fn() {loop_forever}, val: Value(<ZST>) }
       }
   
       bb4: {
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
index d106da84fc7..028281ba450 100644
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir
@@ -1,12 +1,12 @@
 // MIR for `Test::X` 0 mir_map
 
 fn Test::X(_1: usize) -> Test {
-    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
+    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
 
     bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
+        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
     }
 }
diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
index d106da84fc7..028281ba450 100644
--- a/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
+++ b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir
@@ -1,12 +1,12 @@
 // MIR for `Test::X` 0 mir_map
 
 fn Test::X(_1: usize) -> Test {
-    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
+    let mut _0: Test;                    // return place in scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
 
     bb0: {
-        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
-        return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:13
+        Deinit(_0);                      // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        ((_0 as X).0: usize) = move _1;  // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        discriminant(_0) = 0;            // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
+        return;                          // scope 0 at $DIR/unusual-item-types.rs:16:5: 16:6
     }
 }
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
index 5dc81b787a9..54ecaccdb4f 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir
@@ -34,6 +34,6 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
         _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
     }
 }
diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
index 5dc81b787a9..54ecaccdb4f 100644
--- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
+++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir
@@ -34,6 +34,6 @@ fn std::ptr::drop_in_place(_1: *mut Vec<i32>) -> () {
         _3 = <Vec<i32> as Drop>::drop(move _2) -> [return: bb5, unwind: bb4]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: for<'r> fn(&'r mut Vec<i32>) {<Vec<i32> as Drop>::drop}, val: Value(<ZST>) }
     }
 }
diff --git a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
index ec2d161251b..f1c5d95df19 100644
--- a/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
+++ b/src/test/mir-opt/while_storage.while_loop.PreCodegen.after.mir
@@ -19,7 +19,7 @@ fn while_loop(_1: bool) -> () {
         _2 = get_bool(move _3) -> bb2;   // scope 0 at $DIR/while-storage.rs:10:11: 10:22
                                          // mir::Constant
                                          // + span: $DIR/while-storage.rs:10:11: 10:19
-                                         // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb2: {
@@ -34,7 +34,7 @@ fn while_loop(_1: bool) -> () {
         _4 = get_bool(move _5) -> bb4;   // scope 0 at $DIR/while-storage.rs:11:12: 11:23
                                          // mir::Constant
                                          // + span: $DIR/while-storage.rs:11:12: 11:20
-                                         // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
     }
 
     bb4: {
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
index e463099a5ee..09ad276aa45 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
@@ -37,7 +37,7 @@
    37|      0|            countdown = 10;
    38|      0|        }
    39|      0|        "alt string 2".to_owned()
-   40|      0|    };
+   40|       |    };
    41|      1|    println!(
    42|      1|        "The string or alt: {}"
    43|      1|        ,
@@ -79,7 +79,7 @@
    79|      0|            countdown = 10;
    80|      1|        }
    81|      1|        "alt string 4".to_owned()
-   82|      1|    };
+   82|       |    };
    83|      1|    println!(
    84|      1|        "The string or alt: {}"
    85|      1|        ,
@@ -101,7 +101,7 @@
   101|      0|            countdown = 10;
   102|      5|        }
   103|      5|        format!("'{}'", val)
-  104|      5|    };
+  104|       |    };
   105|      1|    println!(
   106|      1|        "Repeated, quoted string: {:?}"
   107|      1|        ,
@@ -125,7 +125,7 @@
   125|      0|            countdown = 10;
   126|      0|        }
   127|      0|        "closure should be unused".to_owned()
-  128|      0|    };
+  128|       |    };
   129|       |
   130|      1|    let mut countdown = 10;
   131|      1|    let _short_unused_closure = | _unused_arg: u8 | countdown += 1;
@@ -177,7 +177,7 @@
   173|      0|            println!(
   174|      0|                "not called: {}",
   175|      0|                if is_true { "check" } else { "me" }
-  176|      0|            )
+  176|       |            )
   177|       |    ;
   178|       |
   179|      1|    let short_used_not_covered_closure_line_break_block_embedded_branch =
@@ -187,7 +187,7 @@
   183|      0|                "not called: {}",
   184|      0|                if is_true { "check" } else { "me" }
   185|       |            )
-  186|      0|        }
+  186|       |        }
   187|       |    ;
   188|       |
   189|      1|    let short_used_covered_closure_line_break_no_block_embedded_branch =
@@ -196,7 +196,7 @@
   192|      1|                "not called: {}",
   193|      1|                if is_true { "check" } else { "me" }
                                                             ^0
-  194|      1|            )
+  194|       |            )
   195|       |    ;
   196|       |
   197|      1|    let short_used_covered_closure_line_break_block_embedded_branch =
@@ -207,7 +207,7 @@
   202|      1|                if is_true { "check" } else { "me" }
                                                             ^0
   203|       |            )
-  204|      1|        }
+  204|       |        }
   205|       |    ;
   206|       |
   207|      1|    if is_false {
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
index 0fb3808ff2e..d70e12e4128 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
@@ -18,7 +18,7 @@
    17|      1|    let mut generator = || {
    18|      1|        yield get_u32(is_true);
    19|      1|        return "foo";
-   20|      1|    };
+   20|       |    };
    21|       |
    22|      1|    match Pin::new(&mut generator).resume(()) {
    23|      1|        GeneratorState::Yielded(Ok(1)) => {}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
index 55a49548cb5..65eb1008dd8 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
@@ -36,12 +36,12 @@
    22|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
    23|      2|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt
index 6e2f23ee77b..60a8d943f1f 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt
@@ -8,7 +8,7 @@
     8|      1|    let mut generator = || {
     9|      1|        yield 1;
    10|      1|        return "foo"
-   11|      1|    };
+   11|       |    };
    12|       |
    13|      1|    match Pin::new(&mut generator).resume(()) {
    14|      1|        GeneratorState::Yielded(1) => {}
@@ -24,7 +24,7 @@
    24|      1|        yield 2;
    25|      0|        yield 3;
    26|      0|        return "foo"
-   27|      0|    };
+   27|       |    };
    28|       |
    29|      1|    match Pin::new(&mut generator).resume(()) {
    30|      1|        GeneratorState::Yielded(1) => {}
diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir
index f02bccc4b2d..ab4084c952a 100644
--- a/src/test/run-make/const_fn_mir/dump.mir
+++ b/src/test/run-make/const_fn_mir/dump.mir
@@ -33,7 +33,7 @@ fn main() -> () {
         _1 = foo() -> bb1;               // scope 0 at main.rs:9:5: 9:10
                                          // mir::Constant
                                          // + span: main.rs:9:5: 9:8
-                                         // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn() -> i32 {foo}, val: Value(<ZST>) }
     }
 
     bb1: {
diff --git a/src/test/run-make/issue-88756-default-output/output-default.stdout b/src/test/run-make/issue-88756-default-output/output-default.stdout
index 6d16fe5673b..08877af9286 100644
--- a/src/test/run-make/issue-88756-default-output/output-default.stdout
+++ b/src/test/run-make/issue-88756-default-output/output-default.stdout
@@ -110,6 +110,9 @@ Options:
                         never = never colorize output
         --error-format human|json|short
                         How errors and other messages are produced
+        --diagnostic-width WIDTH
+                        Provide width of the output for truncated error
+                        messages
         --json CONFIG   Configure the structure of JSON diagnostics
         --disable-minification 
                         Disable minification applied on JS files
diff --git a/src/test/run-make/issue-88756-opt-help/Makefile b/src/test/run-make/issue-88756-opt-help/Makefile
deleted file mode 100644
index 8ababbf5b4e..00000000000
--- a/src/test/run-make/issue-88756-opt-help/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
--include ../../run-make-fulldeps/tools.mk
-
-all:
-	$(RUSTDOC) -W help 2>&1 | diff - output-default.stdout
diff --git a/src/test/run-make/issue-88756-opt-help/README.md b/src/test/run-make/issue-88756-opt-help/README.md
deleted file mode 100644
index 9b742753f25..00000000000
--- a/src/test/run-make/issue-88756-opt-help/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This is a test to verify that `rustdoc` behaves the same as rustc and prints out help output for its options like -W (#88756).
diff --git a/src/test/run-make/issue-88756-opt-help/output-default.stdout b/src/test/run-make/issue-88756-opt-help/output-default.stdout
deleted file mode 100644
index 5cb7ecb649a..00000000000
--- a/src/test/run-make/issue-88756-opt-help/output-default.stdout
+++ /dev/null
@@ -1,193 +0,0 @@
-    -W                          allow-features=val -- only allow the listed language features to be enabled in code (space separated)
-    -W                       always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no)
-    -W               assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
-    -W                            asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
-    -W                       assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
-    -W                      binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
-    -W                       branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
-    -W                           cf-protection=val -- instrument control-flow architecture protection
-    -W               cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
-    -W                                   chalk=val -- enable the experimental Chalk-based trait solving engine
-    -W                         codegen-backend=val -- the backend to use
-    -W                             combine-cgu=val -- combine CGUs into a single one
-    -W                              crate-attr=val -- inject the given attribute in the crate
-    -W                debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO
-    -W                            debug-macros=val -- emit line numbers debug info inside macros (default: no)
-    -W                 deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes)
-    -W                  dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no)
-    -W                               dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no)
-    -W                                 dlltool=val -- import library generation tool (windows-gnu only)
-    -W                 dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
-    -W                           drop-tracking=val -- enables drop tracking in generators (default: no)
-    -W                        dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no)
-    -W                          dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no)
-    -W                                dump-mir=val -- dump MIR state to file.
-        `val` is used to select which passes and functions to dump. For example:
-        `all` matches all passes and functions,
-        `foo` matches all passes for functions whose name contains 'foo',
-        `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
-        `foo | bar` all passes for function names containing 'foo' or 'bar'.
-    -W                       dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no)
-    -W                            dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`)
-    -W            dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
-    -W                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
-    -W                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
-    -W                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
-    -W                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
-    -W              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
-    -W                                    fuel=val -- set the optimization fuel quota for a crate
-    -W                       function-sections=val -- whether each function should go in its own section
-    -W                    future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no)
-    -W                                  gcc-ld=val -- implementation of ld used by cc
-    -W                      graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no)
-    -W                           graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)
-    -W                               hir-stats=val -- print some statistics about AST and HIR (default: no)
-    -W                human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no)
-    -W                        identify-regions=val -- display unnamed regions as `'<id>`, using a non-ident unique id (default: no)
-    -W                incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no)
-    -W                        incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
-    -W              incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
-    -W                  incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
-    -W                              inline-mir=val -- enable MIR inlining (default: no)
-    -W                    inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
-    -W               inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
-    -W                      inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
-    -W                             input-stats=val -- gather statistics about the input (default: no)
-    -W                     instrument-coverage=val -- 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)
-    -W                       instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
-    -W                       keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
-    -W                   link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
-    -W                               link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
-    -W                            llvm-plugins=val -- a list LLVM plugins to enable (space separated)
-    -W                         llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
-    -W                         location-detail=val -- comma separated list of location details to be tracked when using caller_location valid options are `file`, `line`, and `column` (default: all)
-    -W                                      ls=val -- list the symbols defined by a library crate (default: no)
-    -W                         macro-backtrace=val -- show macro backtraces (default: no)
-    -W                         merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name
-    -W                              meta-stats=val -- gather metadata statistics (default: no)
-    -W                          mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
-    -W                       mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual.
-    -W                           mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
-    -W                         move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
-    -W                         mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
-    -W                   new-llvm-pass-manager=val -- use new LLVM pass manager (default: no)
-    -W                               nll-facts=val -- dump facts from NLL analysis into side files (default: no)
-    -W                           nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`)
-    -W                             no-analysis=val -- parse and expand the source, but run no analysis
-    -W                              no-codegen=val -- run all passes except codegen; no output
-    -W              no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups
-    -W                     no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints
-    -W                           no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
-    -W                                 no-link=val -- compile without linking
-    -W                        no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
-    -W                 no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
-    -W                     no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate
-    -W                          normalize-docs=val -- normalize associated items in rustdoc when generating documentation
-    -W                                     oom=val -- panic strategy for out-of-memory handling
-    -W                  osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no)
-    -W                       panic-abort-tests=val -- support compiling tests with panic=abort (default: no)
-    -W                           panic-in-drop=val -- panic strategy for panics in drops
-    -W                              parse-only=val -- parse only; do not compile, assemble, or link (default: no)
-    -W                              perf-stats=val -- print some performance-related statistics (default: no)
-    -W pick-stable-methods-before-any-unstable=val -- try to pick stable methods first before picking any unstable methods (default: yes)
-    -W                                     plt=val -- whether to use the PLT when calling into shared libraries;
-        only has effect for PIC code on systems with ELF binaries
-        (default: PLT is disabled if full relro is enabled)
-    -W                                polonius=val -- enable polonius-based borrow-checker (default: no)
-    -W                            polymorphize=val -- perform polymorphization analysis
-    -W                            pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times)
-    -W                           pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated)
-    -W           precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551.
-    -W                              print-fuel=val -- make rustc print the total optimization fuel used by a crate
-    -W                       print-llvm-passes=val -- print the LLVM optimization passes being run (default: no)
-    -W                        print-mono-items=val -- print the result of the monomorphization collection pass
-    -W                        print-type-sizes=val -- print layout information for each type encountered (default: no)
-    -W                    proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no)
-    -W                                 profile=val -- insert profiling code (default: no)
-    -W                        profile-closures=val -- profile size of closures
-    -W                            profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path)
-    -W                        profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
-    -W                      profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)
-    -W                         query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no)
-    -W                        randomize-layout=val -- randomize the layout of types (default: no)
-    -W                             layout-seed=val -- seed layout randomization
-    -W                   relax-elf-relocations=val -- whether ELF relocations can be relaxed
-    -W                             relro-level=val -- choose which RELRO level to use
-    -W                        remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix
-    -W         simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
-    -W                     report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
-    -W                               sanitizer=val -- use a sanitizer
-    -W          sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
-    -W                       sanitizer-recover=val -- enable recovery for selected sanitizers
-    -W                  saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes)
-    -W                           save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no)
-    -W                            self-profile=val -- run the self profiler and output the raw event data
-    -W                     self-profile-events=val -- specify the events recorded by the self profiler;
-        for example: `-Z self-profile-events=default,query-keys`
-        all options: none, all, default, generic-activity, query-provider, query-cache-hit
-                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
-    -W                    self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of:
-        `wall-time` (monotonic clock, i.e. `std::time::Instant`)
-        `instructions:u` (retired instructions, userspace-only)
-        `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
-    -W                          share-generics=val -- make the current crate share its generic instantiations
-    -W                               show-span=val -- show spans for compiler debugging (expr|pat|ty)
-    -W                              span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span`
-    -W                       span-free-formats=val -- exclude spans when debug-printing compiler state (default: no)
-    -W                      src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
-    -W                         stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
-    -W                      strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
-    -W                                   strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
-    -W                        split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
-        (default: `split`)
-
-        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
-                 file which is ignored by the linker
-        `single`: sections which do not require relocation are written into object file but ignored
-                  by the linker
-    -W                    split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
-    -W                 symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
-    -W                                   teach=val -- show extended diagnostic help (default: no)
-    -W                               temps-dir=val -- the directory the intermediate files are written to
-    -W                          terminal-width=val -- set the current terminal width
-    -W                          translate-lang=val -- language identifier for diagnostic output
-    -W                translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
-    -W        translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
-    -W                                tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
-    -W                                 thinlto=val -- enable ThinLTO when possible
-    -W                           thir-unsafeck=val -- use the THIR unsafety checker (default: no)
-    -W                                 threads=val -- use a thread pool with N threads
-    -W                                    time=val -- measure time of rustc processes (default: no)
-    -W                        time-llvm-passes=val -- measure time of each LLVM pass (default: no)
-    -W                             time-passes=val -- measure time of each rustc pass (default: no)
-    -W                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
-    -W                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
-    -W   translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes)
-    -W                        trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)
-    -W                        treat-err-as-bug=val -- treat error number `val` that occurs as bug
-    -W                   trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items
-    -W                              ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no)
-    -W            uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16)
-    -W          unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no)
-    -W                                unpretty=val -- present the input source, unstable (and less-pretty) variants;
-        `normal`, `identified`,
-        `expanded`, `expanded,identified`,
-        `expanded,hygiene` (with internal representations),
-        `ast-tree` (raw AST before expansion),
-        `ast-tree,expanded` (raw AST after expansion),
-        `hir` (the HIR), `hir,identified`,
-        `hir,typed` (HIR with types for each node),
-        `hir-tree` (dump the raw HIR),
-        `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)
-    -W                        unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no)
-    -W                        unstable-options=val -- adds unstable command line options to rustc interface (default: no)
-    -W                       use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array
-    -W                            validate-mir=val -- validate MIR after each transformation
-    -W                                 verbose=val -- in general, enable more debug printouts (default: no)
-    -W                          verify-llvm-ir=val -- verify LLVM IR (default: no)
-    -W            virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]`
-    -W                         wasi-exec-model=val -- whether to build a wasi command or reactor
diff --git a/src/test/run-make/issue-88756-opt-help/x.rs b/src/test/run-make/issue-88756-opt-help/x.rs
deleted file mode 100644
index 5df7576133a..00000000000
--- a/src/test/run-make/issue-88756-opt-help/x.rs
+++ /dev/null
@@ -1 +0,0 @@
-// nothing to see here
diff --git a/src/test/run-make/native-link-modifier-bundle/Makefile b/src/test/run-make/native-link-modifier-bundle/Makefile
index 723bb4689fe..e4b0f74ac26 100644
--- a/src/test/run-make/native-link-modifier-bundle/Makefile
+++ b/src/test/run-make/native-link-modifier-bundle/Makefile
@@ -3,27 +3,31 @@
 
 -include ../../run-make-fulldeps/tools.mk
 
+# We're using the llvm-nm instead of the system nm to ensure it is compatible
+# with the LLVM bitcode generated by rustc.
+NM = "$(LLVM_BIN_DIR)"/llvm-nm
+
 all: $(call NATIVE_STATICLIB,native-staticlib)
 	# Build a staticlib and a rlib, the `native_func` symbol will be bundled into them
 	$(RUSTC) bundled.rs --crate-type=staticlib --crate-type=rlib
-	nm $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func"
-	nm $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func"
-	nm $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func"
-	nm $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func"
+	$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "T _*native_func"
+	$(NM) $(TMPDIR)/libbundled.a | $(CGREP) -e "U _*native_func"
+	$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "T _*native_func"
+	$(NM) $(TMPDIR)/libbundled.rlib | $(CGREP) -e "U _*native_func"
 
 	# Build a staticlib and a rlib, the `native_func` symbol will not be bundled into it
 	$(RUSTC) non-bundled.rs --crate-type=staticlib --crate-type=rlib
-	nm $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func"
-	nm $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func"
-	nm $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func"
-	nm $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func"
+	$(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -ve "T _*native_func"
+	$(NM) $(TMPDIR)/libnon_bundled.a | $(CGREP) -e "U _*native_func"
+	$(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -ve "T _*native_func"
+	$(NM) $(TMPDIR)/libnon_bundled.rlib | $(CGREP) -e "U _*native_func"
 
 	# Build a cdylib, `native-staticlib` will not appear on the linker line because it was bundled previously
 	# The cdylib will contain the `native_func` symbol in the end
 	$(RUSTC) cdylib-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -ve '-l[" ]*native-staticlib'
-	nm $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func"
+	$(NM) $(call DYLIB,cdylib_bundled) | $(CGREP) -e "[Tt] _*native_func"
 
 	# Build a cdylib, `native-staticlib` will appear on the linker line because it was not bundled previously
 	# The cdylib will contain the `native_func` symbol in the end
 	$(RUSTC) cdylib-non-bundled.rs --crate-type=cdylib --print link-args | $(CGREP) -e '-l[" ]*native-staticlib'
-	nm $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func"
+	$(NM) $(call DYLIB,cdylib_non_bundled) | $(CGREP) -e "[Tt] _*native_func"
diff --git a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs
index 998d202b117..f29bc50e84c 100644
--- a/src/test/run-pass-valgrind/cast-enum-with-dtor.rs
+++ b/src/test/run-pass-valgrind/cast-enum-with-dtor.rs
@@ -30,5 +30,5 @@ fn main() {
         assert_eq!(e as u32, 2);
         assert_eq!(FLAG.load(Ordering::SeqCst), 0);
     }
-    assert_eq!(FLAG.load(Ordering::SeqCst), 0);
+    assert_eq!(FLAG.load(Ordering::SeqCst), 1);
 }
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
index ddfb23a4f86..84b8bbd1b32 100644
--- a/src/test/rustdoc-gui/anchors.goml
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -28,7 +28,7 @@ move-cursor-to: "h2#implementations"
 assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"})
 
 // Same thing with the impl block title.
-move-cursor-to: "#impl"
-assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"})
+move-cursor-to: "#impl-HeavilyDocumentedStruct"
+assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"})
 
 assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
diff --git a/src/test/rustdoc-gui/headers-color.goml b/src/test/rustdoc-gui/headers-color.goml
index cf9caa2d586..a47a9c8a14c 100644
--- a/src/test/rustdoc-gui/headers-color.goml
+++ b/src/test/rustdoc-gui/headers-color.goml
@@ -23,9 +23,9 @@ assert-css: (
     ALL,
 )
 
-goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
 assert-css: (
-    "#impl",
+    "#impl-Foo",
     {"color": "rgb(197, 197, 197)", "background-color": "rgba(255, 236, 164, 0.06)"},
 )
 
@@ -62,9 +62,9 @@ assert-css: (
     ALL,
 )
 
-goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
 assert-css: (
-    "#impl",
+    "#impl-Foo",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(73, 74, 61)"},
 )
 
@@ -99,8 +99,8 @@ assert-css: (
     ALL,
 )
 
-goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl
-assert-css: ("#impl", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"})
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html#impl-Foo
+assert-css: ("#impl-Foo", {"color": "rgb(0, 0, 0)", "background-color": "rgb(253, 255, 211)"})
 
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.must_use
 assert-css: (
diff --git a/src/test/rustdoc-gui/headings.goml b/src/test/rustdoc-gui/headings.goml
index 67e97eb686e..cc3dd61e99a 100644
--- a/src/test/rustdoc-gui/headings.goml
+++ b/src/test/rustdoc-gui/headings.goml
@@ -32,8 +32,8 @@ assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
 assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
-assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedStruct > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
 
@@ -87,8 +87,8 @@ assert-css: ("h6#structy-prose-sub-heading", {"border-bottom-width": "0px"})
 assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
-assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedEnum > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
 
@@ -129,8 +129,8 @@ assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
 assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
-assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"font-size": "18px"})
+assert-css: ("#impl-HeavilyDocumentedUnion > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
 assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
 assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
diff --git a/src/test/rustdoc-gui/implementors.goml b/src/test/rustdoc-gui/implementors.goml
index f29613f78b1..666a6e1253d 100644
--- a/src/test/rustdoc-gui/implementors.goml
+++ b/src/test/rustdoc-gui/implementors.goml
@@ -6,8 +6,8 @@ assert: "#implementors-list"
 assert-count: ("#implementors-list .impl", 2)
 // Now we check that both implementors have an anchor, an ID and a similar DOM.
 assert: ("#implementors-list .impl:nth-child(1) > a.anchor")
-assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever"})
-assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever"})
+assert-attribute: ("#implementors-list .impl:nth-child(1)", {"id": "impl-Whatever-for-Struct"})
+assert-attribute: ("#implementors-list .impl:nth-child(1) > a.anchor", {"href": "#impl-Whatever-for-Struct"})
 assert: "#implementors-list .impl:nth-child(1) > .code-header.in-band"
 
 assert: ("#implementors-list .impl:nth-child(2) > a.anchor")
@@ -16,8 +16,16 @@ assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href":
 assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band"
 
 goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html
-compare-elements-position-near-false: ("#impl-EmptyTrait1", "#impl-EmptyTrait2", {"y": 30})
-compare-elements-position-near: ("#impl-EmptyTrait3 h3", "#impl-EmptyTrait3 .item-info", {"y": 30})
+compare-elements-position-near-false: (
+    "#impl-EmptyTrait1-for-HasEmptyTraits",
+    "#impl-EmptyTrait2-for-HasEmptyTraits",
+    {"y": 30},
+)
+compare-elements-position-near: (
+    "#impl-EmptyTrait3-for-HasEmptyTraits h3",
+    "#impl-EmptyTrait3-for-HasEmptyTraits .item-info",
+    {"y": 30},
+)
 
 // Now check that re-exports work correctly.
 // There should be exactly one impl shown on both of these pages.
diff --git a/src/test/rustdoc-gui/item-info-overflow.goml b/src/test/rustdoc-gui/item-info-overflow.goml
index d6385e2acb8..b7095a3c532 100644
--- a/src/test/rustdoc-gui/item-info-overflow.goml
+++ b/src/test/rustdoc-gui/item-info-overflow.goml
@@ -15,14 +15,17 @@ assert-text: (
 // Checking the "item-info" on an impl block as well:
 goto: file://|DOC_PATH|/lib2/struct.LongItemInfo2.html
 compare-elements-property: (
-    "#impl-SimpleTrait .item-info",
-    "#impl-SimpleTrait + .docblock",
+    "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
+    "#impl-SimpleTrait-for-LongItemInfo2 + .docblock",
     ["scrollWidth"],
 )
-assert-property: ("#impl-SimpleTrait .item-info", {"scrollWidth": "866"})
+assert-property: (
+    "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
+    {"scrollWidth": "866"},
+)
 // Just to be sure we're comparing the correct "item-info":
 assert-text: (
-    "#impl-SimpleTrait .item-info",
+    "#impl-SimpleTrait-for-LongItemInfo2 .item-info",
     "Available on Android or Linux or Emscripten or DragonFly BSD",
     STARTS_WITH,
 )
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index ff792eced70..b31905a126a 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -10,3 +10,31 @@ size: (600, 100)
 // As counter-intuitive as it may seem, in this width, the width is "100%", which is why
 // when computed it's larger.
 assert-css: (".search-results div.desc", {"width": "570px"})
+
+// Check that the crate filter `<select>` is correctly handled when it goes to next line.
+// To do so we need to update the length of one of its `<option>`.
+size: (900, 900)
+
+// First we check the current width and position.
+assert-css: ("#crate-search", {"width": "222px"})
+compare-elements-position-near: (
+    "#crate-search",
+    "#search-settings .search-results-title",
+    {"y": 5},
+)
+
+// Then we update the text of one of the `<option>`.
+text: (
+    "#crate-search option",
+    "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa",
+)
+
+// Then we compare again.
+assert-css: ("#crate-search", {"width": "640px"})
+compare-elements-position-near-false: (
+    "#crate-search",
+    "#search-settings .search-results-title",
+    {"y": 5},
+)
+// And we check that the `<select>` isn't bigger than its container.
+assert-css: ("#search", {"width": "640px"})
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
index c441f84a821..fa322574fde 100644
--- a/src/test/rustdoc-gui/sidebar-source-code-display.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -18,6 +18,17 @@ click: "#sidebar-toggle"
 // Because of the transition CSS, we check by using `wait-for-css` instead of `assert-css`.
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 
+// We now check that opening the sidebar and clicking a link will leave it open.
+// The behavior here on desktop is different than the behavior on mobile,
+// but since the sidebar doesn't fill the entire screen here, it makes sense to have the
+// sidebar stay resident.
+wait-for-css: (".sidebar", {"width": "300px"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+click: ".sidebar a.selected"
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+wait-for-css: (".sidebar", {"width": "300px"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+
 // Now we check the display of the sidebar items.
 show-text: true
 
@@ -27,29 +38,52 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files a.selected",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(255, 255, 255)"},
 )
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(224, 224, 224)"})
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+    "#source-sidebar details[open] > .files a:not(.selected)",
+    {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+    "#source-sidebar details[open] > .folders > details > summary",
+    {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(0, 0, 0)", "background-color": "rgb(224, 224, 224)"},
 )
 
@@ -59,29 +93,52 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files > a.selected",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(51, 51, 51)"},
 )
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgb(103, 103, 103)"})
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files > a:not(.selected)",
     {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+    "#source-sidebar details[open] > .files a:not(.selected)",
+    {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+    "#source-sidebar details[open] > .folders > details > summary",
+    {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(221, 221, 221)", "background-color": "rgb(68, 68, 68)"},
 )
 
@@ -91,29 +148,52 @@ reload:
 // Waiting for the sidebar to be displayed...
 wait-for-css: ("#sidebar-toggle", {"visibility": "visible", "opacity": 1})
 assert-css: (
-    "#source-sidebar .expand + .children a.selected",
+    "#source-sidebar details[open] > .files a.selected",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
+// Without hover or focus.
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(0, 0, 0, 0)"})
+// With focus.
+focus: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"})
+focus: ".search-input"
+// With hover.
+move-cursor-to: "#sidebar-toggle > button"
+assert-css: ("#sidebar-toggle > button", {"background-color": "rgba(70, 70, 70, 0.33)"})
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .files a:not(.selected)"
+wait-for-css: (
+    "#source-sidebar details[open] > .files a:not(.selected)",
+    {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children > .files a:not(.selected)"
+move-cursor-to: "#source-sidebar details[open] > .files a:not(.selected)"
 assert-css: (
-    "#source-sidebar .expand + .children > .files a:not(.selected)",
+    "#source-sidebar details[open] > .files a:not(.selected)",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
 // Without hover.
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(197, 197, 197)", "background-color": "rgba(0, 0, 0, 0)"},
 )
+// With focus.
+focus: "#source-sidebar details[open] > .folders > details > summary"
+wait-for-css: (
+    "#source-sidebar details[open] > .folders > details > summary",
+    {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
+)
+focus: ".search-input"
 // With hover.
-move-cursor-to: "#source-sidebar .expand + .children .folders .name"
+move-cursor-to: "#source-sidebar details[open] > .folders > details > summary"
 assert-css: (
-    "#source-sidebar .expand + .children .folders .name",
+    "#source-sidebar details[open] > .folders > details > summary",
     {"color": "rgb(255, 180, 76)", "background-color": "rgb(20, 25, 31)"},
 )
 
@@ -152,3 +232,23 @@ click: "#sidebar-toggle"
 wait-for-css: (".sidebar", {"width": "0px"})
 // The "scrollTop" property should be the same.
 assert-window-property: {"pageYOffset": "2519"}
+
+// We now check that opening the sidebar and clicking a link will close it.
+// The behavior here on mobile is different than the behavior on desktop,
+// but common sense dictates that if you have a list of files that fills the entire screen, and
+// you click one of them, you probably want to actually see the file's contents, and not just
+// make it the current selection.
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
+click: ".sidebar a.selected"
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
+// Resize back to desktop size, to check that the sidebar doesn't spontaneously open.
+size: (1000, 1000)
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "false"}
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-local-storage: {"rustdoc-source-sidebar-show": "true"}
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index b45512601f2..581f826a3d9 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -34,19 +34,16 @@ assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
 click: "#sidebar-toggle"
 assert: ".source-sidebar-expanded"
 
-// We check that the first entry of the sidebar is collapsed (which, for whatever reason,
-// is number 2 and not 1...).
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
-assert-text: ("#source-sidebar .name:nth-child(2)", "implementors")
-// We also check its children are hidden too.
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
+// We check that the first entry of the sidebar is collapsed
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
+assert-text: ("#source-sidebar details:first-of-type > summary", "implementors")
 // We now click on it.
-click: "#source-sidebar .name:nth-child(2)"
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name expand"})
-// Checking that its children are displayed as well.
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "block"})
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
 
 // And now we collapse it again.
-click: "#source-sidebar .name:nth-child(2)"
-assert-attribute: ("#source-sidebar .name:nth-child(2)", {"class": "name"})
-assert-css: ("#source-sidebar .name:nth-child(2) + .children", {"display": "none"})
+click: "#source-sidebar details:first-of-type > summary"
+assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
+
+// Check the spacing.
+assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
diff --git a/src/test/rustdoc-gui/toggle-click-deadspace.goml b/src/test/rustdoc-gui/toggle-click-deadspace.goml
index 7bc3c563157..4a328c9f9e0 100644
--- a/src/test/rustdoc-gui/toggle-click-deadspace.goml
+++ b/src/test/rustdoc-gui/toggle-click-deadspace.goml
@@ -8,5 +8,5 @@ click: ".impl-items .rustdoc-toggle summary::before" // This is the position of
 assert-attribute-false: (".impl-items .rustdoc-toggle", {"open": ""})
 
 // Click the "Trait" part of "impl Trait" and verify it navigates.
-click: "#impl-Trait h3 a:first-of-type"
+click: "#impl-Trait-for-Foo h3 a:first-of-type"
 assert-text: (".fqn .in-band", "Trait lib2::Trait")
diff --git a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
index 821e6b99f7b..5025b0b0ca8 100644
--- a/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
+++ b/src/test/rustdoc-ui/deny-missing-docs-crate.stderr
@@ -16,7 +16,7 @@ error: missing documentation for a struct
   --> $DIR/deny-missing-docs-crate.rs:3:1
    |
 LL | pub struct Foo;
-   | ^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/rustdoc-ui/diagnostic-width.rs b/src/test/rustdoc-ui/diagnostic-width.rs
new file mode 100644
index 00000000000..61961d5ec71
--- /dev/null
+++ b/src/test/rustdoc-ui/diagnostic-width.rs
@@ -0,0 +1,5 @@
+// compile-flags: -Zunstable-options --diagnostic-width=10
+#![deny(rustdoc::bare_urls)]
+
+/// This is a long line that contains a http://link.com
+pub struct Foo; //~^ ERROR
diff --git a/src/test/rustdoc-ui/diagnostic-width.stderr b/src/test/rustdoc-ui/diagnostic-width.stderr
new file mode 100644
index 00000000000..fed049d2b37
--- /dev/null
+++ b/src/test/rustdoc-ui/diagnostic-width.stderr
@@ -0,0 +1,15 @@
+error: this URL is not a hyperlink
+  --> $DIR/diagnostic-width.rs:4:41
+   |
+LL | ... a http://link.com
+   |       ^^^^^^^^^^^^^^^ help: use an automatic link instead: `<http://link.com>`
+   |
+note: the lint level is defined here
+  --> $DIR/diagnostic-width.rs:2:9
+   |
+LL | ...ny(rustdoc::bare_url...
+   |       ^^^^^^^^^^^^^^^^^^
+   = note: bare URLs are not automatically turned into clickable links
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/issue-79467.rs b/src/test/rustdoc-ui/issue-79467.rs
new file mode 100644
index 00000000000..eb0b9b38071
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79467.rs
@@ -0,0 +1,8 @@
+fn g()
+where
+    'static: 'static,
+    dyn 'static: 'static + Copy, //~ ERROR at least one trait is required for an object type
+{
+}
+
+fn main() {}
diff --git a/src/test/rustdoc-ui/issue-79467.stderr b/src/test/rustdoc-ui/issue-79467.stderr
new file mode 100644
index 00000000000..561513a432b
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79467.stderr
@@ -0,0 +1,9 @@
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/issue-79467.rs:4:5
+   |
+LL |     dyn 'static: 'static + Copy,
+   |     ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/src/test/rustdoc-ui/issue-79494.rs b/src/test/rustdoc-ui/issue-79494.rs
new file mode 100644
index 00000000000..fc39424b793
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79494.rs
@@ -0,0 +1,5 @@
+// only-x86_64-unknown-linux-gnu
+
+#![feature(const_transmute)]
+
+const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types
diff --git a/src/test/rustdoc-ui/issue-79494.stderr b/src/test/rustdoc-ui/issue-79494.stderr
new file mode 100644
index 00000000000..7ed5ed38247
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-79494.stderr
@@ -0,0 +1,12 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/issue-79494.rs:5:29
+   |
+LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) };
+   |                             ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `usize` (64 bits)
+   = note: target type: `&[u8]` (128 bits)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.rs b/src/test/rustdoc-ui/issue-83883-describe-lints.rs
index a261b782d48..0474d6c143e 100644
--- a/src/test/rustdoc-ui/issue-83883-describe-lints.rs
+++ b/src/test/rustdoc-ui/issue-83883-describe-lints.rs
@@ -1,8 +1,10 @@
 // compile-flags: -W help
 // check-pass
+// check-stdout
+// error-pattern:Lint checks provided
+// error-pattern:rustdoc::broken-intra-doc-links
 //
 // ignore-tidy-linelength
 //
 // normalize-stdout-test: "( +name  default  meaning\n +----  -------  -------\n)?( *[[:word:]:-]+  (allow  |warn   |deny   |forbid )  [^\n]+\n)+" -> "    $$NAMES  $$LEVELS  $$MEANINGS"
 // normalize-stdout-test: " +name  sub-lints\n +----  ---------\n( *[[:word:]:-]+  [^\n]+\n)+" -> "    $$NAMES  $$SUB_LINTS"
-// normalize-stdout-test: " +rustdoc::all(  (rustdoc::[[:word:]-]+, )*rustdoc::[[:word:]-]+)?" -> "    rustdoc::all  $$GROUPS$4"
diff --git a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout
index 5cb7ecb649a..bbf66a31583 100644
--- a/src/test/rustdoc-ui/issue-83883-describe-lints.stdout
+++ b/src/test/rustdoc-ui/issue-83883-describe-lints.stdout
@@ -1,193 +1,24 @@
-    -W                          allow-features=val -- only allow the listed language features to be enabled in code (space separated)
-    -W                       always-encode-mir=val -- encode MIR of all functions into the crate metadata (default: no)
-    -W               assume-incomplete-release=val -- make cfg(version) treat the current version as incomplete (default: no)
-    -W                            asm-comments=val -- generate comments into the assembly (may change behavior) (default: no)
-    -W                       assert-incr-state=val -- assert that the incremental cache is in given state: either `loaded` or `not-loaded`.
-    -W                      binary-dep-depinfo=val -- include artifacts (sysroot, crate dependencies) used during compilation in dep-info (default: no)
-    -W                       branch-protection=val -- set options for branch target identification and pointer authentication on AArch64
-    -W                           cf-protection=val -- instrument control-flow architecture protection
-    -W               cgu-partitioning-strategy=val -- the codegen unit partitioning strategy to use
-    -W                                   chalk=val -- enable the experimental Chalk-based trait solving engine
-    -W                         codegen-backend=val -- the backend to use
-    -W                             combine-cgu=val -- combine CGUs into a single one
-    -W                              crate-attr=val -- inject the given attribute in the crate
-    -W                debug-info-for-profiling=val -- emit discriminators and other data necessary for AutoFDO
-    -W                            debug-macros=val -- emit line numbers debug info inside macros (default: no)
-    -W                 deduplicate-diagnostics=val -- deduplicate identical diagnostics (default: yes)
-    -W                  dep-info-omit-d-target=val -- in dep-info output, omit targets for tracking dependencies of the dep-info files themselves (default: no)
-    -W                               dep-tasks=val -- print tasks that execute and the color their dep node gets (requires debug build) (default: no)
-    -W                                 dlltool=val -- import library generation tool (windows-gnu only)
-    -W                 dont-buffer-diagnostics=val -- emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) (default: no)
-    -W                           drop-tracking=val -- enables drop tracking in generators (default: no)
-    -W                        dual-proc-macros=val -- load proc macros for both target and host, but only link to the target (default: no)
-    -W                          dump-dep-graph=val -- dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) (default: no)
-    -W                                dump-mir=val -- dump MIR state to file.
-        `val` is used to select which passes and functions to dump. For example:
-        `all` matches all passes and functions,
-        `foo` matches all passes for functions whose name contains 'foo',
-        `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
-        `foo | bar` all passes for function names containing 'foo' or 'bar'.
-    -W                       dump-mir-dataflow=val -- in addition to `.mir` files, create graphviz `.dot` files with dataflow results (default: no)
-    -W                            dump-mir-dir=val -- the directory the MIR is dumped into (default: `mir_dump`)
-    -W            dump-mir-exclude-pass-number=val -- exclude the pass number when dumping MIR (used in tests) (default: no)
-    -W                       dump-mir-graphviz=val -- in addition to `.mir` files, create graphviz `.dot` files (and with `-Z instrument-coverage`, also create a `.dot` file for the MIR-derived coverage graph) (default: no)
-    -W                       dump-mir-spanview=val -- in addition to `.mir` files, create `.html` files to view spans for all `statement`s (including terminators), only `terminator` spans, or computed `block` spans (one span encompassing a block's terminator and all statements). If `-Z instrument-coverage` is also enabled, create an additional `.html` file showing the computed coverage spans.
-    -W                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
-    -W                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
-    -W              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
-    -W                                    fuel=val -- set the optimization fuel quota for a crate
-    -W                       function-sections=val -- whether each function should go in its own section
-    -W                    future-incompat-test=val -- forces all lints to be future incompatible, used for internal testing (default: no)
-    -W                                  gcc-ld=val -- implementation of ld used by cc
-    -W                      graphviz-dark-mode=val -- use dark-themed colors in graphviz output (default: no)
-    -W                           graphviz-font=val -- use the given `fontname` in graphviz output; can be overridden by setting environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)
-    -W                               hir-stats=val -- print some statistics about AST and HIR (default: no)
-    -W                human-readable-cgu-names=val -- generate human-readable, predictable names for codegen units (default: no)
-    -W                        identify-regions=val -- display unnamed regions as `'<id>`, using a non-ident unique id (default: no)
-    -W                incremental-ignore-spans=val -- ignore spans during ICH computation -- used for testing (default: no)
-    -W                        incremental-info=val -- print high-level information about incremental reuse (or the lack thereof) (default: no)
-    -W              incremental-relative-spans=val -- hash spans relative to their parent item for incr. comp. (default: no)
-    -W                  incremental-verify-ich=val -- verify incr. comp. hashes of green query instances (default: no)
-    -W                              inline-mir=val -- enable MIR inlining (default: no)
-    -W                    inline-mir-threshold=val -- a default MIR inlining threshold (default: 50)
-    -W               inline-mir-hint-threshold=val -- inlining threshold for functions with inline hint (default: 100)
-    -W                      inline-in-all-cgus=val -- control whether `#[inline]` functions are in all CGUs
-    -W                             input-stats=val -- gather statistics about the input (default: no)
-    -W                     instrument-coverage=val -- 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)
-    -W                       instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
-    -W                       keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
-    -W                   link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
-    -W                               link-only=val -- link the `.rlink` file generated by `-Z no-link` (default: no)
-    -W                            llvm-plugins=val -- a list LLVM plugins to enable (space separated)
-    -W                         llvm-time-trace=val -- generate JSON tracing data file from LLVM data (default: no)
-    -W                         location-detail=val -- comma separated list of location details to be tracked when using caller_location valid options are `file`, `line`, and `column` (default: all)
-    -W                                      ls=val -- list the symbols defined by a library crate (default: no)
-    -W                         macro-backtrace=val -- show macro backtraces (default: no)
-    -W                         merge-functions=val -- control the operation of the MergeFunctions LLVM pass, taking the same values as the target option of the same name
-    -W                              meta-stats=val -- gather metadata statistics (default: no)
-    -W                          mir-emit-retag=val -- emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 (default: no)
-    -W                       mir-enable-passes=val -- use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be enabled, overriding all other checks. Passes that are not specified are enabled or disabled by other flags as usual.
-    -W                           mir-opt-level=val -- MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)
-    -W                         move-size-limit=val -- the size at which the `large_assignments` lint starts to be emitted
-    -W                         mutable-noalias=val -- emit noalias metadata for mutable references (default: yes)
-    -W                   new-llvm-pass-manager=val -- use new LLVM pass manager (default: no)
-    -W                               nll-facts=val -- dump facts from NLL analysis into side files (default: no)
-    -W                           nll-facts-dir=val -- the directory the NLL facts are dumped into (default: `nll-facts`)
-    -W                             no-analysis=val -- parse and expand the source, but run no analysis
-    -W                              no-codegen=val -- run all passes except codegen; no output
-    -W              no-generate-arange-section=val -- omit DWARF address ranges that give faster lookups
-    -W                     no-interleave-lints=val -- execute lints separately; allows benchmarking individual lints
-    -W                           no-leak-check=val -- disable the 'leak check' for subtyping; unsound, but useful for tests
-    -W                                 no-link=val -- compile without linking
-    -W                        no-parallel-llvm=val -- run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)
-    -W                 no-unique-section-names=val -- do not use unique names for text and data sections when -Z function-sections is used
-    -W                     no-profiler-runtime=val -- prevent automatic injection of the profiler_builtins crate
-    -W                          normalize-docs=val -- normalize associated items in rustdoc when generating documentation
-    -W                                     oom=val -- panic strategy for out-of-memory handling
-    -W                  osx-rpath-install-name=val -- pass `-install_name @rpath/...` to the macOS linker (default: no)
-    -W                       panic-abort-tests=val -- support compiling tests with panic=abort (default: no)
-    -W                           panic-in-drop=val -- panic strategy for panics in drops
-    -W                              parse-only=val -- parse only; do not compile, assemble, or link (default: no)
-    -W                              perf-stats=val -- print some performance-related statistics (default: no)
-    -W pick-stable-methods-before-any-unstable=val -- try to pick stable methods first before picking any unstable methods (default: yes)
-    -W                                     plt=val -- whether to use the PLT when calling into shared libraries;
-        only has effect for PIC code on systems with ELF binaries
-        (default: PLT is disabled if full relro is enabled)
-    -W                                polonius=val -- enable polonius-based borrow-checker (default: no)
-    -W                            polymorphize=val -- perform polymorphization analysis
-    -W                            pre-link-arg=val -- a single extra argument to prepend the linker invocation (can be used several times)
-    -W                           pre-link-args=val -- extra arguments to prepend to the linker invocation (space separated)
-    -W           precise-enum-drop-elaboration=val -- use a more precise version of drop elaboration for matches on enums (default: yes). This results in better codegen, but has caused miscompilations on some tier 2 platforms. See #77382 and #74551.
-    -W                              print-fuel=val -- make rustc print the total optimization fuel used by a crate
-    -W                       print-llvm-passes=val -- print the LLVM optimization passes being run (default: no)
-    -W                        print-mono-items=val -- print the result of the monomorphization collection pass
-    -W                        print-type-sizes=val -- print layout information for each type encountered (default: no)
-    -W                    proc-macro-backtrace=val -- show backtraces for panics during proc-macro execution (default: no)
-    -W                                 profile=val -- insert profiling code (default: no)
-    -W                        profile-closures=val -- profile size of closures
-    -W                            profile-emit=val -- file path to emit profiling data at runtime when using 'profile' (default based on relative source path)
-    -W                        profiler-runtime=val -- name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)
-    -W                      profile-sample-use=val -- use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)
-    -W                         query-dep-graph=val -- enable queries of the dependency graph for regression testing (default: no)
-    -W                        randomize-layout=val -- randomize the layout of types (default: no)
-    -W                             layout-seed=val -- seed layout randomization
-    -W                   relax-elf-relocations=val -- whether ELF relocations can be relaxed
-    -W                             relro-level=val -- choose which RELRO level to use
-    -W                        remap-cwd-prefix=val -- remap paths under the current working directory to this path prefix
-    -W         simulate-remapped-rust-src-base=val -- simulate the effect of remap-debuginfo = true at bootstrapping by remapping path to rust's source base directory. only meant for testing purposes
-    -W                     report-delayed-bugs=val -- immediately print bugs registered with `delay_span_bug` (default: no)
-    -W                               sanitizer=val -- use a sanitizer
-    -W          sanitizer-memory-track-origins=val -- enable origins tracking in MemorySanitizer
-    -W                       sanitizer-recover=val -- enable recovery for selected sanitizers
-    -W                  saturating-float-casts=val -- make float->int casts UB-free: numbers outside the integer type's range are clipped to the max/min integer respectively, and NaN is mapped to 0 (default: yes)
-    -W                           save-analysis=val -- write syntax and type analysis (in JSON format) information, in addition to normal output (default: no)
-    -W                            self-profile=val -- run the self profiler and output the raw event data
-    -W                     self-profile-events=val -- specify the events recorded by the self profiler;
-        for example: `-Z self-profile-events=default,query-keys`
-        all options: none, all, default, generic-activity, query-provider, query-cache-hit
-                     query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes
-    -W                    self-profile-counter=val -- counter used by the self profiler (default: `wall-time`), one of:
-        `wall-time` (monotonic clock, i.e. `std::time::Instant`)
-        `instructions:u` (retired instructions, userspace-only)
-        `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)
-    -W                          share-generics=val -- make the current crate share its generic instantiations
-    -W                               show-span=val -- show spans for compiler debugging (expr|pat|ty)
-    -W                              span-debug=val -- forward proc_macro::Span's `Debug` impl to `Span`
-    -W                       span-free-formats=val -- exclude spans when debug-printing compiler state (default: no)
-    -W                      src-hash-algorithm=val -- hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)
-    -W                         stack-protector=val -- control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)
-    -W                      strict-init-checks=val -- control if mem::uninitialized and mem::zeroed panic on more UB
-    -W                                   strip=val -- tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)
-    -W                        split-dwarf-kind=val -- split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
-        (default: `split`)
 
-        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
-                 file which is ignored by the linker
-        `single`: sections which do not require relocation are written into object file but ignored
-                  by the linker
-    -W                    split-dwarf-inlining=val -- provide minimal debug info in the object/executable to facilitate online symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF
-    -W                 symbol-mangling-version=val -- which mangling version to use for symbol names ('legacy' (default) or 'v0')
-    -W                                   teach=val -- show extended diagnostic help (default: no)
-    -W                               temps-dir=val -- the directory the intermediate files are written to
-    -W                          terminal-width=val -- set the current terminal width
-    -W                          translate-lang=val -- language identifier for diagnostic output
-    -W                translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
-    -W        translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
-    -W                                tune-cpu=val -- select processor to schedule for (`rustc --print target-cpus` for details)
-    -W                                 thinlto=val -- enable ThinLTO when possible
-    -W                           thir-unsafeck=val -- use the THIR unsafety checker (default: no)
-    -W                                 threads=val -- use a thread pool with N threads
-    -W                                    time=val -- measure time of rustc processes (default: no)
-    -W                        time-llvm-passes=val -- measure time of each LLVM pass (default: no)
-    -W                             time-passes=val -- measure time of each rustc pass (default: no)
-    -W                               tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
-    -W                            trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
-    -W   translate-remapped-path-to-local-path=val -- translate remapped paths into local paths when possible (default: yes)
-    -W                        trap-unreachable=val -- generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)
-    -W                        treat-err-as-bug=val -- treat error number `val` that occurs as bug
-    -W                   trim-diagnostic-paths=val -- in diagnostics, use heuristics to shorten paths referring to items
-    -W                              ui-testing=val -- emit compiler diagnostics in a form suitable for UI testing (default: no)
-    -W            uninit-const-chunk-threshold=val -- allow generating const initializers with mixed init/uninit chunks, and set the maximum number of chunks for which this is allowed (default: 16)
-    -W          unleash-the-miri-inside-of-you=val -- take the brakes off const evaluation. NOTE: this is unsound (default: no)
-    -W                                unpretty=val -- present the input source, unstable (and less-pretty) variants;
-        `normal`, `identified`,
-        `expanded`, `expanded,identified`,
-        `expanded,hygiene` (with internal representations),
-        `ast-tree` (raw AST before expansion),
-        `ast-tree,expanded` (raw AST after expansion),
-        `hir` (the HIR), `hir,identified`,
-        `hir,typed` (HIR with types for each node),
-        `hir-tree` (dump the raw HIR),
-        `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)
-    -W                        unsound-mir-opts=val -- enable unsound and buggy MIR optimizations (default: no)
-    -W                        unstable-options=val -- adds unstable command line options to rustc interface (default: no)
-    -W                       use-ctors-section=val -- use legacy .ctors section for initializers rather than .init_array
-    -W                            validate-mir=val -- validate MIR after each transformation
-    -W                                 verbose=val -- in general, enable more debug printouts (default: no)
-    -W                          verify-llvm-ir=val -- verify LLVM IR (default: no)
-    -W            virtual-function-elimination=val -- enables dead virtual function elimination optimization. Requires `-Clto[=[fat,yes]]`
-    -W                         wasi-exec-model=val -- whether to build a wasi command or reactor
+Available lint options:
+    -W <foo>           Warn about <foo>
+    -A <foo>           Allow <foo>
+    -D <foo>           Deny <foo>
+    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)
+
+
+Lint checks provided by rustc:
+
+    $NAMES  $LEVELS  $MEANINGS
+
+Lint groups provided by rustc:
+
+    $NAMES  $SUB_LINTS
+
+Lint checks provided by plugins loaded by this crate:
+
+    $NAMES  $LEVELS  $MEANINGS
+
+Lint groups provided by plugins loaded by this crate:
+
+    $NAMES  $SUB_LINTS
+
diff --git a/src/test/rustdoc/anchors.no_const_anchor.html b/src/test/rustdoc/anchors.no_const_anchor.html
new file mode 100644
index 00000000000..98f47e53038
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_const_anchor.html
@@ -0,0 +1 @@
+<div id="associatedconstant.YOLO" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#16">source</a></div><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div>
diff --git a/src/test/rustdoc/anchors.no_const_anchor2.html b/src/test/rustdoc/anchors.no_const_anchor2.html
new file mode 100644
index 00000000000..6d37e8e5eee
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_const_anchor2.html
@@ -0,0 +1 @@
+<section id="associatedconstant.X" class="associatedconstant has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#42">source</a></span><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
diff --git a/src/test/rustdoc/anchors.no_method_anchor.html b/src/test/rustdoc/anchors.no_method_anchor.html
new file mode 100644
index 00000000000..f46d3090ed3
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_method_anchor.html
@@ -0,0 +1 @@
+<section id="method.new" class="method has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#48">source</a></span><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -&gt; Self</h4></section>
\ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_trait_method_anchor.html b/src/test/rustdoc/anchors.no_trait_method_anchor.html
new file mode 100644
index 00000000000..445a7bb560a
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_trait_method_anchor.html
@@ -0,0 +1 @@
+<div id="method.bar" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#23">source</a></div><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_tymethod_anchor.html b/src/test/rustdoc/anchors.no_tymethod_anchor.html
new file mode 100644
index 00000000000..bb0771b1003
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_tymethod_anchor.html
@@ -0,0 +1 @@
+<div id="tymethod.foo" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#20">source</a></div><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_type_anchor.html b/src/test/rustdoc/anchors.no_type_anchor.html
new file mode 100644
index 00000000000..d317eb50050
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_type_anchor.html
@@ -0,0 +1 @@
+<div id="associatedtype.T" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#13">source</a></div><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div>
\ No newline at end of file
diff --git a/src/test/rustdoc/anchors.no_type_anchor2.html b/src/test/rustdoc/anchors.no_type_anchor2.html
new file mode 100644
index 00000000000..72a1186bf7e
--- /dev/null
+++ b/src/test/rustdoc/anchors.no_type_anchor2.html
@@ -0,0 +1 @@
+<section id="associatedtype.Y" class="associatedtype has-srclink"><h4 class="code-header">type <a href="#associatedtype.Y" class="associatedtype">Y</a> = <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></section>
diff --git a/src/test/rustdoc/anchors.rs b/src/test/rustdoc/anchors.rs
new file mode 100644
index 00000000000..034cf8eaf4f
--- /dev/null
+++ b/src/test/rustdoc/anchors.rs
@@ -0,0 +1,49 @@
+// This test ensures that anchors are generated in the right places.
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+// @has 'foo/trait.Bar.html'
+pub trait Bar {
+    // There should be no anchors here.
+    // @snapshot no_type_anchor - '//*[@id="associatedtype.T"]'
+    type T;
+    // There should be no anchors here.
+    // @snapshot no_const_anchor - '//*[@id="associatedconstant.YOLO"]'
+    const YOLO: u32;
+
+    // There should be no anchors here.
+    // @snapshot no_tymethod_anchor - '//*[@id="tymethod.foo"]'
+    fn foo();
+    // There should be no anchors here.
+    // @snapshot no_trait_method_anchor - '//*[@id="method.bar"]'
+    fn bar() {}
+}
+
+// @has 'foo/struct.Foo.html'
+impl Bar for Foo {
+    // @has - '//*[@id="associatedtype.T"]/a[@class="anchor"]' ''
+    type T = u32;
+    // @has - '//*[@id="associatedconstant.YOLO"]/a[@class="anchor"]' ''
+    const YOLO: u32 = 0;
+
+    // @has - '//*[@id="method.foo"]/a[@class="anchor"]' ''
+    fn foo() {}
+    // Same check for provided "bar" method.
+    // @has - '//*[@id="method.bar"]/a[@class="anchor"]' ''
+}
+
+impl Foo {
+    // @snapshot no_const_anchor2 - '//*[@id="associatedconstant.X"]'
+    // There should be no anchors here.
+    pub const X: i32 = 0;
+    // @snapshot no_type_anchor2 - '//*[@id="associatedtype.Y"]'
+    // There should be no anchors here.
+    pub type Y = u32;
+    // @snapshot no_method_anchor - '//*[@id="method.new"]'
+    // There should be no anchors here.
+    pub fn new() -> Self { Self }
+}
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index 0ac6dc763df..a79e93145ba 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -27,6 +27,10 @@ impl Bar {
     // @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.BAR"]' \
     //      'const BAR: usize'
     pub const BAR: usize = 3;
+
+    // @has - '//*[@id="associatedconstant.BAR_ESCAPED"]' \
+    //      "const BAR_ESCAPED: &'static str = \"<em>markup</em>\""
+    pub const BAR_ESCAPED: &'static str = "<em>markup</em>";
 }
 
 pub struct Baz<'a, U: 'a, T>(T, &'a [U]);
diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs
index d9e4ffab1c7..a9e5b8d0019 100644
--- a/src/test/rustdoc/assoc-types.rs
+++ b/src/test/rustdoc/assoc-types.rs
@@ -2,7 +2,7 @@
 
 // @has assoc_types/trait.Index.html
 pub trait Index<I: ?Sized> {
-        // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized'
+    // @has - '//*[@id="associatedtype.Output"]//h4[@class="code-header"]' 'type Output: ?Sized'
     type Output: ?Sized;
     // @has - '//*[@id="tymethod.index"]//h4[@class="code-header"]' \
     //      "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
diff --git a/src/test/rustdoc/auto-trait-not-send.rs b/src/test/rustdoc/auto-trait-not-send.rs
index 7bd4f6dbd8c..661d905ab63 100644
--- a/src/test/rustdoc/auto-trait-not-send.rs
+++ b/src/test/rustdoc/auto-trait-not-send.rs
@@ -1,8 +1,8 @@
 #![crate_name = "foo"]
 
 // @has 'foo/struct.Foo.html'
-// @has - '//*[@id="impl-Send"]' 'impl !Send for Foo'
-// @has - '//*[@id="impl-Sync"]' 'impl !Sync for Foo'
+// @has - '//*[@id="impl-Send-for-Foo"]' 'impl !Send for Foo'
+// @has - '//*[@id="impl-Sync-for-Foo"]' 'impl !Sync for Foo'
 pub struct Foo(*const i8);
 pub trait Whatever: Send {}
 impl<T: Send + ?Sized> Whatever for T {}
diff --git a/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs
index 22cbeae7266..4e55e7ed576 100644
--- a/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs
+++ b/src/test/rustdoc/auxiliary/issue-98697-reexport-with-anonymous-lifetime.rs
@@ -7,3 +7,11 @@ where
 {
     unimplemented!()
 }
+
+pub struct Extra;
+
+pub trait MyTrait<T> {
+    fn run() {}
+}
+
+impl MyTrait<&Extra> for Extra {}
diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs
index 4c686730b11..676d656dabf 100644
--- a/src/test/rustdoc/blanket-reexport-item.rs
+++ b/src/test/rustdoc/blanket-reexport-item.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E-for-S"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs
index fc3a2731089..61af7de4794 100644
--- a/src/test/rustdoc/const-generics/const-generics-docs.rs
+++ b/src/test/rustdoc/const-generics/const-generics-docs.rs
@@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//*[@id="impl-Foo%3CM%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> {
     }
 }
 
-// @has foo/struct.Bar.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//*[@id="impl-Bar%3Cu8%2C%20M%3E"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
     //      'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
index a3ef084165a..f1181d54ac8 100644
--- a/src/test/rustdoc/const-generics/const-impl.rs
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -9,20 +9,20 @@ pub enum Order {
 }
 
 // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//*[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Send-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Sync-for-VSet%3CT%2C%20ORDER%3E"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
     inner: Vec<T>,
 }
 
-// @has foo/struct.VSet.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3ASorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
 impl<T> VSet<T, { Order::Sorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
     }
 }
 
-// @has foo/struct.VSet.html '//*[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl-VSet%3CT%2C%20{%20Order%3A%3AUnsorted%20}%3E"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
 impl<T> VSet<T, { Order::Unsorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
@@ -31,7 +31,7 @@ impl<T> VSet<T, { Order::Unsorted }> {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+// @has foo/struct.Escape.html '//*[@id="impl-Escape%3Cr#%22%3Cscript%3Ealert(%22Escape%22)%3B%3C/script%3E%22#%3E"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
 impl Escape<r#"<script>alert("Escape");</script>"#> {
     pub fn f() {}
 }
diff --git a/src/test/rustdoc/const-value-display.rs b/src/test/rustdoc/const-value-display.rs
index 0ae52592b64..5b2f3c48d57 100644
--- a/src/test/rustdoc/const-value-display.rs
+++ b/src/test/rustdoc/const-value-display.rs
@@ -1,9 +1,9 @@
 #![crate_name = "foo"]
 
 // @has 'foo/constant.HOUR_IN_SECONDS.html'
-// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = 60 * 60; // 3_600u64'
+// @has - '//*[@class="docblock item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64'
 pub const HOUR_IN_SECONDS: u64 = 60 * 60;
 
 // @has 'foo/constant.NEGATIVE.html'
-// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = -60 * 60; // -3_600i64'
+// @has - '//*[@class="docblock item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64'
 pub const NEGATIVE: i64 = -60 * 60;
diff --git a/src/test/rustdoc/decl-trailing-whitespace.declaration.html b/src/test/rustdoc/decl-trailing-whitespace.declaration.html
new file mode 100644
index 00000000000..e60caaeff38
--- /dev/null
+++ b/src/test/rustdoc/decl-trailing-whitespace.declaration.html
@@ -0,0 +1,7 @@
+<code>pub trait Write {
+    fn <a href="#tymethod.poll_write" class="fnname">poll_write</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;buf: &amp;mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" />    fn <a href="#tymethod.poll_flush" class="fnname">poll_flush</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+<span class="item-spacer" />    fn <a href="#tymethod.poll_close" class="fnname">poll_close</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt;;
+
+    fn <a href="#method.poll_write_vectored" class="fnname">poll_write_vectored</a>(<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;self: <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cx: &amp;mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,<br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;bufs: &amp;[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>]<br />&#160;&#160;&#160;&#160;) -&gt; <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>&gt;&gt; { ... }
+}</code>
diff --git a/src/test/rustdoc/decl-trailing-whitespace.rs b/src/test/rustdoc/decl-trailing-whitespace.rs
new file mode 100644
index 00000000000..46a2307abef
--- /dev/null
+++ b/src/test/rustdoc/decl-trailing-whitespace.rs
@@ -0,0 +1,30 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/98803>.
+
+#![crate_name = "foo"]
+
+pub struct Error;
+
+// @has 'foo/trait.Write.html'
+
+pub trait Write {
+    // @snapshot 'declaration' - '//*[@class="docblock item-decl"]//code'
+    fn poll_write(
+        self: Option<String>,
+        cx: &mut Option<String>,
+        buf: &mut [usize]
+    ) -> Option<Result<usize, Error>>;
+    fn poll_flush(
+        self: Option<String>,
+        cx: &mut Option<String>
+    ) -> Option<Result<(), Error>>;
+    fn poll_close(
+        self: Option<String>,
+        cx: &mut Option<String>,
+    ) -> Option<Result<(), Error>>;
+
+    fn poll_write_vectored(
+        self: Option<String>,
+        cx: &mut Option<String>,
+        bufs: &[usize]
+    ) -> Option<Result<usize, Error>> {}
+}
diff --git a/src/test/rustdoc/double-quote-escape.rs b/src/test/rustdoc/double-quote-escape.rs
index b7bbf140cfd..350c897417d 100644
--- a/src/test/rustdoc/double-quote-escape.rs
+++ b/src/test/rustdoc/double-quote-escape.rs
@@ -1,6 +1,5 @@
 #![crate_name = "foo"]
 
-
 pub trait Foo<T> {
     fn foo() {}
 }
@@ -8,5 +7,5 @@ pub trait Foo<T> {
 pub struct Bar;
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E-for-Bar"]' 'Foo<unsafe extern "C" fn()>'
 impl Foo<unsafe extern "C" fn()> for Bar {}
diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs
index d18f404212f..83902d6f7ab 100644
--- a/src/test/rustdoc/empty-impls.rs
+++ b/src/test/rustdoc/empty-impls.rs
@@ -1,19 +1,19 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send-for-Foo"]' 'impl Send for Foo'
 pub struct Foo;
 
 pub trait EmptyTrait {}
 
-// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait-for-Foo"]' 'impl EmptyTrait for Foo'
 impl EmptyTrait for Foo {}
 
 pub trait NotEmpty {
     fn foo(&self);
 }
 
-// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty-for-Foo"]' 'impl NotEmpty for Foo'
 impl NotEmpty for Foo {
     fn foo(&self) {}
 }
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
index 1268c9587f8..c6beed70abe 100644
--- a/src/test/rustdoc/generic-impl.rs
+++ b/src/test/rustdoc/generic-impl.rs
@@ -2,12 +2,12 @@
 
 use std::fmt;
 
-// @!has foo/struct.Bar.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//*[@id="impl-ToString-for-Bar"]' ''
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//*[@id="impl-ToString-for-Foo"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 pub struct Foo;
-// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString"]' 'ToString'
+// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString-for-Foo"]' 'ToString'
 
 impl fmt::Display for Foo {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/test/rustdoc/hidden-trait-struct-impls.rs b/src/test/rustdoc/hidden-trait-struct-impls.rs
index 1be956ef393..cc3f6337719 100644
--- a/src/test/rustdoc/hidden-trait-struct-impls.rs
+++ b/src/test/rustdoc/hidden-trait-struct-impls.rs
@@ -11,11 +11,11 @@ pub struct Bar;
 
 struct Hidden;
 
-// @!has foo/struct.Bar.html '//*[@id="impl-Foo"]' 'impl Foo for Bar'
+// @!has foo/struct.Bar.html '//*[@id="impl-Foo-for-Bar"]' 'impl Foo for Bar'
 impl Foo for Bar {}
-// @!has foo/struct.Bar.html '//*[@id="impl-Dark"]' 'impl Dark for Bar'
+// @!has foo/struct.Bar.html '//*[@id="impl-Dark-for-Bar"]' 'impl Dark for Bar'
 impl Dark for Bar {}
-// @has foo/struct.Bar.html '//*[@id="impl-Bam"]' 'impl Bam for Bar'
+// @has foo/struct.Bar.html '//*[@id="impl-Bam-for-Bar"]' 'impl Bam for Bar'
 // @has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Bar'
 impl Bam for Bar {}
 // @!has foo/trait.Bam.html '//*[@id="implementors-list"]' 'impl Bam for Hidden'
diff --git a/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs
new file mode 100644
index 00000000000..644a6e1cf33
--- /dev/null
+++ b/src/test/rustdoc/hide-complex-unevaluated-const-arguments.rs
@@ -0,0 +1,82 @@
+// Test that certain unevaluated constant expression arguments that are
+// deemed too verbose or complex and that may leak private or
+// `doc(hidden)` struct fields are not displayed in the documentation.
+//
+// Read the documentation of `rustdoc::clean::utils::print_const_expr`
+// for further details.
+#![feature(const_trait_impl, generic_const_exprs)]
+#![allow(incomplete_features)]
+
+// @has hide_complex_unevaluated_const_arguments/trait.Stage.html
+pub trait Stage {
+    // A helper constant that prevents const expressions containing it
+    // from getting fully evaluated since it doesn't have a body and
+    // thus is non-reducible. This allows us to specifically test the
+    // pretty-printing of *unevaluated* consts.
+    const ABSTRACT: usize;
+
+    // Currently considered "overly complex" by the `generic_const_exprs`
+    // feature. If / once this expression kind gets supported, this
+    // unevaluated const expression could leak the private struct field.
+    //
+    // FIXME: Once the line below compiles, make this a test that
+    //        ensures that the private field is not printed.
+    //
+    //const ARRAY0: [u8; Struct { private: () } + Self::ABSTRACT];
+
+    // This assoc. const could leak the private assoc. function `Struct::new`.
+    // Ensure that this does not happen.
+    //
+    // @has - '//*[@id="associatedconstant.ARRAY1"]' \
+    //        'const ARRAY1: [u8; { _ }]'
+    const ARRAY1: [u8; Struct::new(/* ... */) + Self::ABSTRACT * 1_000];
+
+    // @has - '//*[@id="associatedconstant.VERBOSE"]' \
+    //        'const VERBOSE: [u16; { _ }]'
+    const VERBOSE: [u16; compute("thing", 9 + 9) * Self::ABSTRACT];
+
+    // Check that we do not leak the private struct field contained within
+    // the path. The output could definitely be improved upon
+    // (e.g. printing sth. akin to `<Self as Helper<{ _ }>>::OUT`) but
+    // right now “safe is safe”.
+    //
+    // @has - '//*[@id="associatedconstant.PATH"]' \
+    //        'const PATH: usize = _'
+    const PATH: usize = <Self as Helper<{ Struct { private: () } }>>::OUT;
+}
+
+const fn compute(input: &str, extra: usize) -> usize {
+    input.len() + extra
+}
+
+pub trait Helper<const S: Struct> {
+    const OUT: usize;
+}
+
+impl<const S: Struct, St: Stage + ?Sized> Helper<S> for St {
+    const OUT: usize = St::ABSTRACT;
+}
+
+// Currently in rustdoc, const arguments are not evaluated in this position
+// and therefore they fall under the realm of `print_const_expr`.
+// If rustdoc gets patched to evaluate const arguments, it is fine to replace
+// this test as long as one can ensure that private fields are not leaked!
+//
+// @has hide_complex_unevaluated_const_arguments/trait.Sub.html \
+//      '//*[@class="rust trait"]' \
+//      'pub trait Sub: Sup<{ _ }, { _ }> { }'
+pub trait Sub: Sup<{ 90 * 20 * 4 }, { Struct { private: () } }> {}
+
+pub trait Sup<const N: usize, const S: Struct> {}
+
+pub struct Struct { private: () }
+
+impl Struct {
+    const fn new() -> Self { Self { private: () } }
+}
+
+impl const std::ops::Add<usize> for Struct {
+    type Output = usize;
+
+    fn add(self, _: usize) -> usize { 0 }
+}
diff --git a/src/test/rustdoc/hide-complex-unevaluated-consts.rs b/src/test/rustdoc/hide-complex-unevaluated-consts.rs
new file mode 100644
index 00000000000..ba623246a01
--- /dev/null
+++ b/src/test/rustdoc/hide-complex-unevaluated-consts.rs
@@ -0,0 +1,71 @@
+// Regression test for issue #97933.
+//
+// Test that certain unevaluated constant expressions that are
+// deemed too verbose or complex and that may leak private or
+// `doc(hidden)` struct fields are not displayed in the documentation.
+//
+// Read the documentation of `rustdoc::clean::utils::print_const_expr`
+// for further details.
+
+// @has hide_complex_unevaluated_consts/trait.Container.html
+pub trait Container {
+    // A helper constant that prevents const expressions containing it
+    // from getting fully evaluated since it doesn't have a body and
+    // thus is non-reducible. This allows us to specifically test the
+    // pretty-printing of *unevaluated* consts.
+    const ABSTRACT: i32;
+
+    // Ensure that the private field does not get leaked:
+    //
+    // @has - '//*[@id="associatedconstant.STRUCT0"]' \
+    //        'const STRUCT0: Struct = _'
+    const STRUCT0: Struct = Struct { private: () };
+
+    // @has - '//*[@id="associatedconstant.STRUCT1"]' \
+    //        'const STRUCT1: (Struct,) = _'
+    const STRUCT1: (Struct,) = (Struct{private: /**/()},);
+
+    // Although the struct field is public here, check that it is not
+    // displayed. In a future version of rustdoc, we definitely want to
+    // show it. However for the time being, the printing logic is a bit
+    // conservative.
+    //
+    // @has - '//*[@id="associatedconstant.STRUCT2"]' \
+    //        'const STRUCT2: Record = _'
+    const STRUCT2: Record = Record { public: 5 };
+
+    // Test that we do not show the incredibly verbose match expr:
+    //
+    // @has - '//*[@id="associatedconstant.MATCH0"]' \
+    //        'const MATCH0: i32 = _'
+    const MATCH0: i32 = match 234 {
+        0 => 1,
+        _ => Self::ABSTRACT,
+    };
+
+    // @has - '//*[@id="associatedconstant.MATCH1"]' \
+    //        'const MATCH1: bool = _'
+    const MATCH1: bool = match Self::ABSTRACT {
+        _ => true,
+    };
+
+    // Check that we hide complex (arithmetic) operations.
+    // In this case, it is a bit unfortunate since the expression
+    // is not *that* verbose and it might be quite useful to the reader.
+    //
+    // However in general, the expression might be quite large and
+    // contain match expressions and structs with private fields.
+    // We would need to recurse over the whole expression and even more
+    // importantly respect operator precedence when pretty-printing
+    // the potentially partially censored expression.
+    // For now, the implementation is quite simple and the choices
+    // rather conservative.
+    //
+    // @has - '//*[@id="associatedconstant.ARITH_OPS"]' \
+    //        'const ARITH_OPS: i32 = _'
+    const ARITH_OPS: i32 = Self::ABSTRACT * 2 + 1;
+}
+
+pub struct Struct { private: () }
+
+pub struct Record { pub public: i32 }
diff --git a/src/test/rustdoc/impl-box.rs b/src/test/rustdoc/impl-box.rs
index a371db135cf..592b6c98587 100644
--- a/src/test/rustdoc/impl-box.rs
+++ b/src/test/rustdoc/impl-box.rs
@@ -5,7 +5,7 @@
 pub struct MyType;
 
 // @has 'impl_box/struct.MyType.html'
-// @has '-' '//*[@id="impl-Iterator"]' 'impl Iterator for Box<MyType>'
+// @has '-' '//*[@id="impl-Iterator-for-Box%3CMyType%3E"]' 'impl Iterator for Box<MyType>'
 
 impl Iterator for Box<MyType> {
     type Item = ();
diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs
index 0c70cdee914..8a998496cf5 100644
--- a/src/test/rustdoc/intra-doc/pub-use.rs
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
@@ -5,21 +5,11 @@
 extern crate inner;
 
 /// [mod@std::env] [g]
-
-// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports.
-// Until then, comment out the `htmldocck` test.
-// This test still does something; namely check that no incorrect errors are emitted when
-// documenting the re-export.
-
 // @has outer/index.html
-// @ has - '//a[@href="{{channel}}/std/env/fn.var.html"]' "std::env"
-// @ has - '//a[@href="fn.f.html"]' "g"
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
+// @has - '//a[@href="fn.f.html"]' "g"
 pub use f as g;
 
-// FIXME: same as above
-/// [std::env]
-extern crate self as _;
-
 // Make sure the documentation is actually correct by documenting an inlined re-export
 /// [mod@std::env]
 // @has outer/fn.f.html
diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs
index 490d7e51e32..635c3175f81 100644
--- a/src/test/rustdoc/issue-29503.rs
+++ b/src/test/rustdoc/issue-29503.rs
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait-for-T']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
 impl<T> MyTrait for T
 where
     T: fmt::Debug,
diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs
index a8cb16ec34c..ac97b94fb35 100644
--- a/src/test/rustdoc/issue-75588.rs
+++ b/src/test/rustdoc/issue-75588.rs
@@ -13,5 +13,5 @@ extern crate real_gimli;
 // @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice'
 pub use realcore::Deref;
 
-// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo'
 pub use realcore::Join;
diff --git a/src/test/rustdoc/issue-78701.rs b/src/test/rustdoc/issue-78701.rs
index 796d553fac4..e3e46468f38 100644
--- a/src/test/rustdoc/issue-78701.rs
+++ b/src/test/rustdoc/issue-78701.rs
@@ -5,8 +5,8 @@
 // the ID is correctly derived.
 
 // @has 'foo/struct.AnotherStruct.html'
-// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait"]' 1
-// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-1"]' 1
+// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3C()%3E"]' 1
+// @count - '//*[@class="sidebar"]//a[@href="#impl-AnAmazingTrait-for-AnotherStruct%3CT%3E"]' 1
 
 pub trait Something {}
 
diff --git a/src/test/rustdoc/issue-98697.rs b/src/test/rustdoc/issue-98697.rs
index 25ab55acd77..83e08094c09 100644
--- a/src/test/rustdoc/issue-98697.rs
+++ b/src/test/rustdoc/issue-98697.rs
@@ -11,3 +11,7 @@ extern crate issue_98697_reexport_with_anonymous_lifetime;
 // @has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'fn repro<F>() where F: Fn(&str)'
 // @!has issue_98697/fn.repro.html '//pre[@class="rust fn"]/code' 'for<'
 pub use issue_98697_reexport_with_anonymous_lifetime::repro;
+
+// @has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl MyTrait<&Extra> for Extra'
+// @!has issue_98697/struct.Extra.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl<'
+pub use issue_98697_reexport_with_anonymous_lifetime::Extra;
diff --git a/src/test/rustdoc/primitive/primitive-generic-impl.rs b/src/test/rustdoc/primitive/primitive-generic-impl.rs
index 28adff84c70..eebb2cf5a35 100644
--- a/src/test/rustdoc/primitive/primitive-generic-impl.rs
+++ b/src/test/rustdoc/primitive/primitive-generic-impl.rs
@@ -1,7 +1,7 @@
 #![feature(rustdoc_internals)]
 #![crate_name = "foo"]
 
-// @has foo/primitive.i32.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//*[@id="impl-ToString-for-i32"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 
 #[doc(primitive = "i32")]
 /// Some useless docs, wouhou!
diff --git a/src/test/rustdoc/rfc-2632-const-trait-impl.rs b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
index ec70a69ff10..f3e211e3017 100644
--- a/src/test/rustdoc/rfc-2632-const-trait-impl.rs
+++ b/src/test/rustdoc/rfc-2632-const-trait-impl.rs
@@ -29,10 +29,11 @@ pub trait Tr<T> {
     }
 }
 
-// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]' '~const'
-// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
-// @!has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
-// @has - '//section[@id="impl-Tr%3CT%3E"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]' ''
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/a[@class="trait"]' 'Clone'
+// @!has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where"]' '~const'
+// @has - '//section[@id="impl-Tr%3CT%3E-for-T"]/h3[@class="code-header in-band"]/span[@class="where fmt-newline"]' ': Clone'
 impl<T: ~const Clone + ~const Destruct> const Tr<T> for T
 where
     Option<T>: ~const Clone + ~const Destruct,
diff --git a/src/test/rustdoc/show-const-contents.rs b/src/test/rustdoc/show-const-contents.rs
index f5a356bcae6..48b60885974 100644
--- a/src/test/rustdoc/show-const-contents.rs
+++ b/src/test/rustdoc/show-const-contents.rs
@@ -21,7 +21,7 @@ pub const CONST_NEG_I32: i32 = -42;
 // @!has show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32'
 pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32;
 
-// @has show_const_contents/constant.CONST_CALC_I32.html '= 42 + 1; // 43i32'
+// @has show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32'
 pub const CONST_CALC_I32: i32 = 42 + 1;
 
 // @!has show_const_contents/constant.CONST_REF_I32.html '= &42;'
diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs
index 252a8126036..9d2c1967757 100644
--- a/src/test/rustdoc/sized_trait.rs
+++ b/src/test/rustdoc/sized_trait.rs
@@ -11,7 +11,7 @@ pub struct Bar {
 pub struct Foo<T: ?Sized>(T);
 
 // @has foo/struct.Unsized.html
-// @has - '//*[@id="impl-Sized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @has - '//*[@id="impl-Sized-for-Unsized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs
index 0f461a1185b..69be9aa8d5f 100644
--- a/src/test/rustdoc/src-links-auto-impls.rs
+++ b/src/test/rustdoc/src-links-auto-impls.rs
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Unsized.html
-// @has - '//*[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
-// @!has - '//*[@id="impl-Sized"]//a[@class="srclink"]' 'source'
-// @has - '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
-// @!has - '//*[@id="impl-Sync"]//a[@class="srclink"]' 'source'
-// @has - '//*[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
-// @has - '//*[@id="impl-Any"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Sized-for-Unsized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @!has - '//*[@id="impl-Sized-for-Unsized"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
+// @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
+// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink"]' 'source'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs
index 05ccc074bf1..4f7e2dfe3b9 100644
--- a/src/test/rustdoc/trait-impl.rs
+++ b/src/test/rustdoc/trait-impl.rs
@@ -43,5 +43,5 @@ impl Trait for Struct {
     // @!has - '//*[@id="method.d"]/../../div[@class="docblock"]/p/em'
     fn d() {}
 
-    // @has - '//*[@id="impl-Trait"]/h3//a/@href' 'trait.Trait.html'
+    // @has - '//*[@id="impl-Trait-for-Struct"]/h3//a/@href' 'trait.Trait.html'
 }
diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum.html b/src/test/rustdoc/whitespace-after-where-clause.enum.html
new file mode 100644
index 00000000000..9e5bf45ae7d
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.enum.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+    Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.enum2.html b/src/test/rustdoc/whitespace-after-where-clause.enum2.html
new file mode 100644
index 00000000000..6bc47beaed1
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.enum2.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust enum"><code>pub enum Cow2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+    Borrowed(<a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B),
+    Whatever(<a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>),
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.rs b/src/test/rustdoc/whitespace-after-where-clause.rs
new file mode 100644
index 00000000000..c36386a2aa2
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.rs
@@ -0,0 +1,77 @@
+// This test ensures there is no whitespace before the first brace of
+// trait, enum, struct and union items when they have a where clause.
+
+#![crate_name = "foo"]
+
+// @has 'foo/trait.ToOwned.html'
+// @snapshot trait - '//*[@class="docblock item-decl"]'
+pub trait ToOwned<T>
+where T: Clone
+{
+    type Owned;
+    fn to_owned(&self) -> Self::Owned;
+    fn whatever(&self) -> T;
+}
+
+// @has 'foo/trait.ToOwned2.html'
+// @snapshot trait2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub trait ToOwned2<T: Clone> {
+    type Owned;
+    fn to_owned(&self) -> Self::Owned;
+    fn whatever(&self) -> T;
+}
+
+// @has 'foo/enum.Cow.html'
+// @snapshot enum - '//*[@class="docblock item-decl"]'
+pub enum Cow<'a, B: ?Sized + 'a>
+where
+    B: ToOwned<Clone>,
+{
+    Borrowed(&'a B),
+    Whatever(u32),
+}
+
+// @has 'foo/enum.Cow2.html'
+// @snapshot enum2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub enum Cow2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+    Borrowed(&'a B),
+    Whatever(u32),
+}
+
+// @has 'foo/struct.Struct.html'
+// @snapshot struct - '//*[@class="docblock item-decl"]'
+pub struct Struct<'a, B: ?Sized + 'a>
+where
+    B: ToOwned<Clone>,
+{
+    pub a: &'a B,
+    pub b: u32,
+}
+
+// @has 'foo/struct.Struct2.html'
+// @snapshot struct2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub struct Struct2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+    pub a: &'a B,
+    pub b: u32,
+}
+
+// @has 'foo/union.Union.html'
+// @snapshot union - '//*[@class="docblock item-decl"]'
+pub union Union<'a, B: ?Sized + 'a>
+where
+    B: ToOwned<Clone>,
+{
+    a: &'a B,
+    b: u32,
+}
+
+// @has 'foo/union.Union2.html'
+// @snapshot union2 - '//*[@class="docblock item-decl"]'
+// There should be a whitespace before `{` in this case!
+pub union Union2<'a, B: ?Sized + ToOwned<Clone> + 'a> {
+    a: &'a B,
+    b: u32,
+}
diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct.html b/src/test/rustdoc/whitespace-after-where-clause.struct.html
new file mode 100644
index 00000000000..236cc3b30d0
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.struct.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+    pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+    pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.struct2.html b/src/test/rustdoc/whitespace-after-where-clause.struct2.html
new file mode 100644
index 00000000000..47f5c6ba9c8
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.struct2.html
@@ -0,0 +1,4 @@
+<div class="docblock item-decl"><pre class="rust struct"><code>pub struct Struct2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+    pub a: <a class="primitive" href="{{channel}}/std/primitive.reference.html">&amp;'a </a>B,
+    pub b: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a>,
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait.html b/src/test/rustdoc/whitespace-after-where-clause.trait.html
new file mode 100644
index 00000000000..98f03b837b5
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.trait.html
@@ -0,0 +1,6 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned&lt;T&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;T: <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>,&#160;</span>{
+    type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
+
+    fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned.html#associatedtype.Owned" title="type foo::ToOwned::Owned">Owned</a>;
+<span class="item-spacer" />    fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.trait2.html b/src/test/rustdoc/whitespace-after-where-clause.trait2.html
new file mode 100644
index 00000000000..35052869e76
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.trait2.html
@@ -0,0 +1,6 @@
+<div class="docblock item-decl"><pre class="rust trait"><code>pub trait ToOwned2&lt;T:&#160;<a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; {
+    type <a href="#associatedtype.Owned" class="associatedtype">Owned</a>;
+
+    fn <a href="#tymethod.to_owned" class="fnname">to_owned</a>(&amp;self) -&gt; Self::<a class="associatedtype" href="trait.ToOwned2.html#associatedtype.Owned" title="type foo::ToOwned2::Owned">Owned</a>;
+<span class="item-spacer" />    fn <a href="#tymethod.whatever" class="fnname">whatever</a>(&amp;self) -&gt; T;
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.union.html b/src/test/rustdoc/whitespace-after-where-clause.union.html
new file mode 100644
index 00000000000..97e1bbcf339
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.union.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust union"><code>pub union Union&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + 'a&gt; <span class="where fmt-newline">where<br />&#160;&#160;&#160;&#160;B: <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt;,&#160;</span>{
+    /* private fields */
+}</code></pre></div>
diff --git a/src/test/rustdoc/whitespace-after-where-clause.union2.html b/src/test/rustdoc/whitespace-after-where-clause.union2.html
new file mode 100644
index 00000000000..6c752a8b4c5
--- /dev/null
+++ b/src/test/rustdoc/whitespace-after-where-clause.union2.html
@@ -0,0 +1,3 @@
+<div class="docblock item-decl"><pre class="rust union"><code>pub union Union2&lt;'a, B:&#160;?<a class="trait" href="{{channel}}/core/marker/trait.Sized.html" title="trait core::marker::Sized">Sized</a> + <a class="trait" href="trait.ToOwned.html" title="trait foo::ToOwned">ToOwned</a>&lt;dyn <a class="trait" href="{{channel}}/core/clone/trait.Clone.html" title="trait core::clone::Clone">Clone</a>&gt; + 'a&gt; {
+    /* private fields */
+}</code></pre></div>
diff --git a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr
index bac44f338b7..bc9fcdd7bc7 100644
--- a/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr
+++ b/src/test/ui-fulldeps/internal-lints/existing_doc_keyword.stderr
@@ -1,4 +1,4 @@
-error: Found non-existing keyword `tadam` used in `#[doc(keyword = "...")]`
+error: found non-existing keyword `tadam` used in `#[doc(keyword = \"...\")]`
   --> $DIR/existing_doc_keyword.rs:10:1
    |
 LL | #[doc(keyword = "tadam")]
diff --git a/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs
new file mode 100644
index 00000000000..fdf1150f8d2
--- /dev/null
+++ b/src/test/ui-fulldeps/issue-81357-unsound-file-methods.rs
@@ -0,0 +1,81 @@
+// run-fail
+// only-windows
+
+fn main() {
+    use std::fs;
+    use std::io::prelude::*;
+    use std::os::windows::prelude::*;
+    use std::ptr;
+    use std::sync::Arc;
+    use std::thread;
+    use std::time::Duration;
+
+    const FILE_FLAG_OVERLAPPED: u32 = 0x40000000;
+
+    fn create_pipe_server(path: &str) -> fs::File {
+        let mut path0 = path.as_bytes().to_owned();
+        path0.push(0);
+        extern "system" {
+            fn CreateNamedPipeA(
+                lpName: *const u8,
+                dwOpenMode: u32,
+                dwPipeMode: u32,
+                nMaxInstances: u32,
+                nOutBufferSize: u32,
+                nInBufferSize: u32,
+                nDefaultTimeOut: u32,
+                lpSecurityAttributes: *mut u8,
+            ) -> RawHandle;
+        }
+
+        unsafe {
+            let h = CreateNamedPipeA(path0.as_ptr(), 3, 0, 1, 0, 0, 0, ptr::null_mut());
+            assert_ne!(h as isize, -1);
+            fs::File::from_raw_handle(h)
+        }
+    }
+
+    let path = "\\\\.\\pipe\\repro";
+    let mut server = create_pipe_server(path);
+
+    let client = Arc::new(
+        fs::OpenOptions::new().custom_flags(FILE_FLAG_OVERLAPPED).read(true).open(path).unwrap(),
+    );
+
+    let spawn_read = |is_first: bool| {
+        thread::spawn({
+            let f = client.clone();
+            move || {
+                let mut buf = [0xcc; 1];
+                let mut f = f.as_ref();
+                f.read(&mut buf).unwrap();
+                if is_first {
+                    assert_ne!(buf[0], 0xcc);
+                } else {
+                    let b = buf[0]; // capture buf[0]
+                    thread::sleep(Duration::from_millis(200));
+
+                    // Check the buffer hasn't been written to after read.
+                    dbg!(buf[0], b);
+                    assert_eq!(buf[0], b);
+                }
+            }
+        })
+    };
+
+    let t1 = spawn_read(true);
+    thread::sleep(Duration::from_millis(20));
+    let t2 = spawn_read(false);
+    thread::sleep(Duration::from_millis(100));
+    let _ = server.write(b"x");
+    thread::sleep(Duration::from_millis(100));
+    let _ = server.write(b"y");
+
+    // This is run fail because we need to test for the `abort`.
+    // That failing to run is the success case.
+    if t1.join().is_err() || t2.join().is_err() {
+        return;
+    } else {
+        panic!("success");
+    }
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 7bec1897fa5..56e95d70fd5 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -1,6 +1,8 @@
 // check-fail
 // Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)]
 
+// normalize-stderr-test "the following other types implement trait `IntoDiagnosticArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr"
+
 // The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly,
 // changing the output of this test. Since SessionDiagnostic is strictly internal to the compiler
 // the test is just ignored on stable and beta:
@@ -15,7 +17,7 @@ use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
 extern crate rustc_macros;
-use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
+use rustc_macros::{SessionDiagnostic, LintDiagnostic, SessionSubdiagnostic};
 
 extern crate rustc_middle;
 use rustc_middle::ty::Ty;
@@ -533,3 +535,20 @@ struct LabelWithTrailingList {
     //~^ ERROR `#[label(...)]` is not a valid attribute
     span: Span,
 }
+
+#[derive(SessionDiagnostic)]
+#[lint(typeck::ambiguous_lifetime_bound)]
+//~^ ERROR only `#[error(..)]` and `#[warn(..)]` are supported
+struct LintsBad {
+}
+
+#[derive(LintDiagnostic)]
+#[lint(typeck::ambiguous_lifetime_bound)]
+struct LintsGood {
+}
+
+#[derive(LintDiagnostic)]
+#[error(typeck::ambiguous_lifetime_bound)]
+//~^ ERROR only `#[lint(..)]` is supported
+struct ErrorsBad {
+}
diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 0d9690e1f5a..98c22af387e 100644
--- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,5 +1,5 @@
 error: `#[derive(SessionDiagnostic)]` can only be used on structs
-  --> $DIR/diagnostic-derive.rs:37:1
+  --> $DIR/diagnostic-derive.rs:39:1
    |
 LL | / #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -10,13 +10,13 @@ LL | | }
    | |_^
 
 error: `#[error = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:46:1
+  --> $DIR/diagnostic-derive.rs:48:1
    |
 LL | #[error = "E0123"]
    | ^^^^^^^^^^^^^^^^^^
 
 error: `#[nonsense(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:51:1
+  --> $DIR/diagnostic-derive.rs:53:1
    |
 LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    = help: only `error`, `warning`, `help` and `note` are valid attributes
 
 error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:51:1
+  --> $DIR/diagnostic-derive.rs:53:1
    |
 LL | / #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
 LL | |
@@ -36,7 +36,7 @@ LL | | struct InvalidStructAttr {}
    = help: use the `#[error(...)]` attribute to create an error
 
 error: `#[error("...")]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:58:9
+  --> $DIR/diagnostic-derive.rs:60:9
    |
 LL | #[error("E0123")]
    |         ^^^^^^^
@@ -44,7 +44,7 @@ LL | #[error("E0123")]
    = help: first argument of the attribute should be the diagnostic slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:58:1
+  --> $DIR/diagnostic-derive.rs:60:1
    |
 LL | / #[error("E0123")]
 LL | |
@@ -55,7 +55,7 @@ LL | | struct InvalidLitNestedAttr {}
    = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:69:9
+  --> $DIR/diagnostic-derive.rs:71:9
    |
 LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL | #[error(nonsense("foo"), code = "E0123", slug = "foo")]
    = help: first argument of the attribute should be the diagnostic slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:69:1
+  --> $DIR/diagnostic-derive.rs:71:1
    |
 LL | / #[error(nonsense("foo"), code = "E0123", slug = "foo")]
 LL | |
@@ -74,7 +74,7 @@ LL | | struct InvalidNestedStructAttr1 {}
    = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:75:9
+  --> $DIR/diagnostic-derive.rs:77:9
    |
 LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^^^^^
@@ -82,7 +82,7 @@ LL | #[error(nonsense = "...", code = "E0123", slug = "foo")]
    = help: first argument of the attribute should be the diagnostic slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:75:1
+  --> $DIR/diagnostic-derive.rs:77:1
    |
 LL | / #[error(nonsense = "...", code = "E0123", slug = "foo")]
 LL | |
@@ -93,7 +93,7 @@ LL | | struct InvalidNestedStructAttr2 {}
    = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:81:9
+  --> $DIR/diagnostic-derive.rs:83:9
    |
 LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
    |         ^^^^^^^^^^^^
@@ -101,7 +101,7 @@ LL | #[error(nonsense = 4, code = "E0123", slug = "foo")]
    = help: first argument of the attribute should be the diagnostic slug
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:81:1
+  --> $DIR/diagnostic-derive.rs:83:1
    |
 LL | / #[error(nonsense = 4, code = "E0123", slug = "foo")]
 LL | |
@@ -112,7 +112,7 @@ LL | | struct InvalidNestedStructAttr3 {}
    = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: `#[error(slug = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:87:59
+  --> $DIR/diagnostic-derive.rs:89:59
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
    |                                                           ^^^^^^^^^^^^
@@ -120,103 +120,103 @@ LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123", slug = "foo")]
    = help: only `code` is a valid nested attributes following the slug
 
 error: `#[suggestion = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:94:5
+  --> $DIR/diagnostic-derive.rs:96:5
    |
 LL |     #[suggestion = "bar"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:1
+  --> $DIR/diagnostic-derive.rs:103:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:1
+  --> $DIR/diagnostic-derive.rs:102:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:1
+  --> $DIR/diagnostic-derive.rs:103:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:1
+  --> $DIR/diagnostic-derive.rs:102:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:101:50
+  --> $DIR/diagnostic-derive.rs:103:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456")]
    |                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:100:50
+  --> $DIR/diagnostic-derive.rs:102:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:1
+  --> $DIR/diagnostic-derive.rs:111:1
    |
 LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:1
+  --> $DIR/diagnostic-derive.rs:110:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:1
+  --> $DIR/diagnostic-derive.rs:111:1
    |
 LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:1
+  --> $DIR/diagnostic-derive.rs:110:1
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:109:52
+  --> $DIR/diagnostic-derive.rs:111:52
    |
 LL | #[warning(typeck::ambiguous_lifetime_bound, code = "E0293")]
    |                                                    ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:108:50
+  --> $DIR/diagnostic-derive.rs:110:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |                                                  ^^^^^^^
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:116:66
+  --> $DIR/diagnostic-derive.rs:118:66
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                                  ^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:116:50
+  --> $DIR/diagnostic-derive.rs:118:50
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, code = "E0456", code = "E0457")]
    |                                                  ^^^^^^^
 
 error: `#[error(typeck::ambiguous_lifetime_bound)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:121:43
+  --> $DIR/diagnostic-derive.rs:123:43
    |
 LL | #[error(typeck::ambiguous_lifetime_bound, typeck::ambiguous_lifetime_bound, code = "E0456")]
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic kind not specified
-  --> $DIR/diagnostic-derive.rs:126:1
+  --> $DIR/diagnostic-derive.rs:128:1
    |
 LL | struct KindNotProvided {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -224,7 +224,7 @@ LL | struct KindNotProvided {}
    = help: use the `#[error(...)]` attribute to create an error
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:129:1
+  --> $DIR/diagnostic-derive.rs:131:1
    |
 LL | / #[error(code = "E0456")]
 LL | |
@@ -234,13 +234,13 @@ LL | | struct SlugNotProvided {}
    = help: specify the slug as the first argument to the attribute, such as `#[error(typeck::example_error)]`
 
 error: the `#[primary_span]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:140:5
+  --> $DIR/diagnostic-derive.rs:142:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
 
 error: `#[nonsense]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:148:5
+  --> $DIR/diagnostic-derive.rs:150:5
    |
 LL |     #[nonsense]
    |     ^^^^^^^^^^^
@@ -248,19 +248,19 @@ LL |     #[nonsense]
    = help: only `skip_arg`, `primary_span`, `label`, `note`, `help` and `subdiagnostic` are valid field attributes
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:165:5
+  --> $DIR/diagnostic-derive.rs:167:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `name` doesn't refer to a field on this type
-  --> $DIR/diagnostic-derive.rs:173:45
+  --> $DIR/diagnostic-derive.rs:175:45
    |
 LL |     #[suggestion(typeck::suggestion, code = "{name}")]
    |                                             ^^^^^^^^
 
 error: invalid format string: expected `'}'` but string was terminated
-  --> $DIR/diagnostic-derive.rs:178:16
+  --> $DIR/diagnostic-derive.rs:180:16
    |
 LL | #[derive(SessionDiagnostic)]
    |           -    ^ expected `'}'` in format string
@@ -271,7 +271,7 @@ LL | #[derive(SessionDiagnostic)]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: invalid format string: unmatched `}` found
-  --> $DIR/diagnostic-derive.rs:188:15
+  --> $DIR/diagnostic-derive.rs:190:15
    |
 LL | #[derive(SessionDiagnostic)]
    |               ^ unmatched `}` in format string
@@ -280,13 +280,13 @@ LL | #[derive(SessionDiagnostic)]
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: the `#[label(...)]` attribute can only be applied to fields of type `Span`
-  --> $DIR/diagnostic-derive.rs:208:5
+  --> $DIR/diagnostic-derive.rs:210:5
    |
 LL |     #[label(typeck::label)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[suggestion(nonsense = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:233:18
+  --> $DIR/diagnostic-derive.rs:235:18
    |
 LL |     #[suggestion(nonsense = "bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -294,7 +294,7 @@ LL |     #[suggestion(nonsense = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: `#[suggestion(msg = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:241:18
+  --> $DIR/diagnostic-derive.rs:243:18
    |
 LL |     #[suggestion(msg = "bar")]
    |                  ^^^^^^^^^^^
@@ -302,7 +302,7 @@ LL |     #[suggestion(msg = "bar")]
    = help: only `message`, `code` and `applicability` are valid field attributes
 
 error: wrong field type for suggestion
-  --> $DIR/diagnostic-derive.rs:263:5
+  --> $DIR/diagnostic-derive.rs:265:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -312,7 +312,7 @@ LL | |     suggestion: Applicability,
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one `Span`
-  --> $DIR/diagnostic-derive.rs:278:5
+  --> $DIR/diagnostic-derive.rs:280:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -320,7 +320,7 @@ LL | |     suggestion: (Span, Span, Applicability),
    | |___________________________________________^
 
 error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability
-  --> $DIR/diagnostic-derive.rs:286:5
+  --> $DIR/diagnostic-derive.rs:288:5
    |
 LL | /     #[suggestion(typeck::suggestion, code = "This is suggested code")]
 LL | |
@@ -328,72 +328,88 @@ LL | |     suggestion: (Applicability, Applicability, Span),
    | |____________________________________________________^
 
 error: `#[label = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:294:5
+  --> $DIR/diagnostic-derive.rs:296:5
    |
 LL |     #[label = "bar"]
    |     ^^^^^^^^^^^^^^^^
 
 error: applicability cannot be set in both the field and attribute
-  --> $DIR/diagnostic-derive.rs:445:52
+  --> $DIR/diagnostic-derive.rs:447:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "maybe-incorrect")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: invalid applicability
-  --> $DIR/diagnostic-derive.rs:453:52
+  --> $DIR/diagnostic-derive.rs:455:52
    |
 LL |     #[suggestion(typeck::suggestion, code = "...", applicability = "batman")]
    |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:516:5
+  --> $DIR/diagnostic-derive.rs:518:5
    |
 LL |     #[label(typeck::label, foo)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:524:5
+  --> $DIR/diagnostic-derive.rs:526:5
    |
 LL |     #[label(typeck::label, foo = "...")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[label(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:532:5
+  --> $DIR/diagnostic-derive.rs:534:5
    |
 LL |     #[label(typeck::label, foo("..."))]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: only `#[error(..)]` and `#[warn(..)]` are supported
+  --> $DIR/diagnostic-derive.rs:540:1
+   |
+LL | / #[lint(typeck::ambiguous_lifetime_bound)]
+LL | |
+LL | | struct LintsBad {
+LL | | }
+   | |_^
+   |
+   = help: use the `#[error(...)]` attribute to create a error
+
+error: only `#[lint(..)]` is supported
+  --> $DIR/diagnostic-derive.rs:551:1
+   |
+LL | / #[error(typeck::ambiguous_lifetime_bound)]
+LL | |
+LL | | struct ErrorsBad {
+LL | | }
+   | |_^
+   |
+   = help: use the `#[lint(...)]` attribute to create a lint
+
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:51:3
+  --> $DIR/diagnostic-derive.rs:53:3
    |
 LL | #[nonsense(typeck::ambiguous_lifetime_bound, code = "E0123")]
    |   ^^^^^^^^
 
 error: cannot find attribute `nonsense` in this scope
-  --> $DIR/diagnostic-derive.rs:148:7
+  --> $DIR/diagnostic-derive.rs:150:7
    |
 LL |     #[nonsense]
    |       ^^^^^^^^
 
 error[E0425]: cannot find value `nonsense` in module `rustc_errors::fluent`
-  --> $DIR/diagnostic-derive.rs:64:9
+  --> $DIR/diagnostic-derive.rs:66:9
    |
 LL | #[error(nonsense, code = "E0123")]
    |         ^^^^^^^^ not found in `rustc_errors::fluent`
 
 error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
-  --> $DIR/diagnostic-derive.rs:338:10
+  --> $DIR/diagnostic-derive.rs:340:10
    |
 LL | #[derive(SessionDiagnostic)]
    |          ^^^^^^^^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
    |
-   = help: the following other types implement trait `IntoDiagnosticArg`:
-             &'a str
-             Ident
-             String
-             Symbol
-             rustc_middle::ty::Ty<'tcx>
-             usize
+   = help: normalized in stderr
 note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:538:19
    |
@@ -401,7 +417,7 @@ LL |         arg: impl IntoDiagnosticArg,
    |                   ^^^^^^^^^^^^^^^^^ required by this bound in `DiagnosticBuilder::<'a, G>::set_arg`
    = note: this error originates in the derive macro `SessionDiagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 46 previous errors
+error: aborting due to 48 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/abi/rustcall-generic.rs b/src/test/ui/abi/rustcall-generic.rs
index 2fa41a7e35a..411c98e1031 100644
--- a/src/test/ui/abi/rustcall-generic.rs
+++ b/src/test/ui/abi/rustcall-generic.rs
@@ -1,4 +1,7 @@
+// revisions: normal opt
 // check-pass
+//[opt] compile-flags: -Zmir-opt-level=3
+
 #![feature(unboxed_closures)]
 
 extern "rust-call" fn foo<T>(_: T) {}
diff --git a/src/test/ui/aligned_enum_cast.rs b/src/test/ui/aligned_enum_cast.rs
index 4b5776a6aa8..1ddf127172e 100644
--- a/src/test/ui/aligned_enum_cast.rs
+++ b/src/test/ui/aligned_enum_cast.rs
@@ -11,5 +11,15 @@ enum Aligned {
 fn main() {
     let aligned = Aligned::Zero;
     let fo = aligned as u8;
-    println!("foo {}",fo);
+    println!("foo {}", fo);
+    assert_eq!(fo, 0);
+    println!("{}", tou8(Aligned::Zero));
+    assert_eq!(tou8(Aligned::Zero), 0);
+}
+
+#[inline(never)]
+fn tou8(al: Aligned) -> u8 {
+    // Cast behind a function call so ConstProp does not see it
+    // (so that we can test codegen).
+    al as u8
 }
diff --git a/src/test/ui/asm/aarch64/type-check-2-2.rs b/src/test/ui/asm/aarch64/type-check-2-2.rs
index e4d29754556..aa12d4aa4b4 100644
--- a/src/test/ui/asm/aarch64/type-check-2-2.rs
+++ b/src/test/ui/asm/aarch64/type-check-2-2.rs
@@ -17,10 +17,10 @@ fn main() {
 
         let x: u64;
         asm!("{}", in(reg) x);
-        //~^ ERROR use of possibly-uninitialized variable: `x`
+        //~^ ERROR used binding `x` isn't initialized
         let mut y: u64;
         asm!("{}", inout(reg) y);
-        //~^ ERROR use of possibly-uninitialized variable: `y`
+        //~^ ERROR used binding `y` isn't initialized
         let _ = y;
 
         // Outputs require mutable places
diff --git a/src/test/ui/asm/aarch64/type-check-2-2.stderr b/src/test/ui/asm/aarch64/type-check-2-2.stderr
index 37bbe394994..b2a695529f9 100644
--- a/src/test/ui/asm/aarch64/type-check-2-2.stderr
+++ b/src/test/ui/asm/aarch64/type-check-2-2.stderr
@@ -1,14 +1,18 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/type-check-2-2.rs:19:28
    |
+LL |         let x: u64;
+   |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
-   |                            ^ use of possibly-uninitialized `x`
+   |                            ^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `y`
+error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-2-2.rs:22:9
    |
+LL |         let mut y: u64;
+   |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-2-2.rs:30:29
diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr
index 4b99652cd20..875df44ffab 100644
--- a/src/test/ui/asm/aarch64/type-check-2.stderr
+++ b/src/test/ui/asm/aarch64/type-check-2.stderr
@@ -22,7 +22,7 @@ LL |         asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
    |
    = note: `SimdNonCopy` does not implement the Copy trait
 
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:38]` for inline assembly
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:41:28: 41:36]` for inline assembly
   --> $DIR/type-check-2.rs:41:28
    |
 LL |         asm!("{}", in(reg) |x: i32| x);
diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr
index 46baeb511ca..d9ca25519dc 100644
--- a/src/test/ui/asm/x86_64/type-check-2.stderr
+++ b/src/test/ui/asm/x86_64/type-check-2.stderr
@@ -30,7 +30,7 @@ LL |         asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
    |
    = note: `SimdNonCopy` does not implement the Copy trait
 
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:38]` for inline assembly
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:52:28: 52:36]` for inline assembly
   --> $DIR/type-check-2.rs:52:28
    |
 LL |         asm!("{}", in(reg) |x: i32| x);
diff --git a/src/test/ui/asm/x86_64/type-check-5.rs b/src/test/ui/asm/x86_64/type-check-5.rs
index 474478f6a88..6190e0b52f4 100644
--- a/src/test/ui/asm/x86_64/type-check-5.rs
+++ b/src/test/ui/asm/x86_64/type-check-5.rs
@@ -13,10 +13,10 @@ fn main() {
 
         let x: u64;
         asm!("{}", in(reg) x);
-        //~^ ERROR use of possibly-uninitialized variable: `x`
+        //~^ ERROR E0381
         let mut y: u64;
         asm!("{}", inout(reg) y);
-        //~^ ERROR use of possibly-uninitialized variable: `y`
+        //~^ ERROR E0381
         let _ = y;
 
         // Outputs require mutable places
diff --git a/src/test/ui/asm/x86_64/type-check-5.stderr b/src/test/ui/asm/x86_64/type-check-5.stderr
index 181ecaf5855..e9c93fea561 100644
--- a/src/test/ui/asm/x86_64/type-check-5.stderr
+++ b/src/test/ui/asm/x86_64/type-check-5.stderr
@@ -1,14 +1,18 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/type-check-5.rs:15:28
    |
+LL |         let x: u64;
+   |             - binding declared here but left uninitialized
 LL |         asm!("{}", in(reg) x);
-   |                            ^ use of possibly-uninitialized `x`
+   |                            ^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `y`
+error[E0381]: used binding `y` isn't initialized
   --> $DIR/type-check-5.rs:18:9
    |
+LL |         let mut y: u64;
+   |             ----- binding declared here but left uninitialized
 LL |         asm!("{}", inout(reg) y);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ `y` used here but it isn't initialized
 
 error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
   --> $DIR/type-check-5.rs:26:29
diff --git a/src/test/ui/associated-item/associated-item-enum.stderr b/src/test/ui/associated-item/associated-item-enum.stderr
index a09b64aa2f5..ebf3c5499a6 100644
--- a/src/test/ui/associated-item/associated-item-enum.stderr
+++ b/src/test/ui/associated-item/associated-item-enum.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `mispellable` found for enum `
   --> $DIR/associated-item-enum.rs:17:11
    |
 LL | enum Enum { Variant }
-   |      ---- variant or associated item `mispellable` not found for this enum
+   | --------- variant or associated item `mispellable` not found for this enum
 ...
 LL |     Enum::mispellable();
    |           ^^^^^^^^^^^
@@ -14,7 +14,7 @@ error[E0599]: no variant or associated item named `mispellable_trait` found for
   --> $DIR/associated-item-enum.rs:18:11
    |
 LL | enum Enum { Variant }
-   |      ---- variant or associated item `mispellable_trait` not found for this enum
+   | --------- variant or associated item `mispellable_trait` not found for this enum
 ...
 LL |     Enum::mispellable_trait();
    |           ^^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ error[E0599]: no variant or associated item named `MISPELLABLE` found for enum `
   --> $DIR/associated-item-enum.rs:19:11
    |
 LL | enum Enum { Variant }
-   |      ---- variant or associated item `MISPELLABLE` not found for this enum
+   | --------- variant or associated item `MISPELLABLE` not found for this enum
 ...
 LL |     Enum::MISPELLABLE;
    |           ^^^^^^^^^^^
diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs
index 6e1b155e181..8bf1385b3c5 100644
--- a/src/test/ui/async-await/await-into-future.rs
+++ b/src/test/ui/async-await/await-into-future.rs
@@ -1,8 +1,6 @@
 // run-pass
 // aux-build: issue-72470-lib.rs
 // edition:2021
-#![feature(into_future)]
-
 extern crate issue_72470_lib;
 use std::{future::{Future, IntoFuture}, pin::Pin};
 
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
index e9b76b19dc4..9b6917df45d 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr
@@ -9,11 +9,8 @@ LL | fn foo(tx: std::sync::mpsc::Sender<i32>) -> impl Future + Send {
 note: required because it's used within this closure
   --> $DIR/issue-70935-complex-spans.rs:25:13
    |
-LL |           baz(|| async{
-   |  _____________^
-LL | |             foo(tx.clone());
-LL | |         }).await;
-   | |_________^
+LL |         baz(|| async{
+   |             ^^
 note: required because it's used within this `async fn` body
   --> $DIR/issue-70935-complex-spans.rs:9:67
    |
diff --git a/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr
index 2174f260a71..88b646d2792 100644
--- a/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr
+++ b/src/test/ui/async-await/issue-70935-complex-spans.normal.stderr
@@ -14,7 +14,7 @@ LL | |             foo(tx.clone());
 LL | |         }).await;
    | |         - ^^^^^^ await occurs here, with the value maybe used later
    | |_________|
-   |           has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 27:10]` which is not `Send`
+   |           has type `[closure@$DIR/issue-70935-complex-spans.rs:25:13: 25:15]` which is not `Send`
 note: the value is later dropped here
   --> $DIR/issue-70935-complex-spans.rs:27:17
    |
diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr
index ccdd9c57a0f..5cbbf89a222 100644
--- a/src/test/ui/async-await/issues/issue-62009-1.stderr
+++ b/src/test/ui/async-await/issues/issue-62009-1.stderr
@@ -24,15 +24,15 @@ LL | fn main() {
 LL |     (|_| 2333).await;
    |               ^^^^^^ only allowed inside `async` functions and blocks
 
-error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
+error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future
   --> $DIR/issue-62009-1.rs:12:15
    |
 LL |     (|_| 2333).await;
-   |               ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
+   |               ^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]` is not a future
    |
-   = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
-   = note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
-   = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
+   = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
+   = note: [closure@$DIR/issue-62009-1.rs:12:6: 12:9] must be a future or must implement `IntoFuture` to be awaited
+   = note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:6: 12:9]`
 help: remove the `.await`
    |
 LL -     (|_| 2333).await;
diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.rs b/src/test/ui/async-await/no-non-guaranteed-initialization.rs
index 24070fe3308..c4d81bf83a3 100644
--- a/src/test/ui/async-await/no-non-guaranteed-initialization.rs
+++ b/src/test/ui/async-await/no-non-guaranteed-initialization.rs
@@ -6,8 +6,7 @@ async fn no_non_guaranteed_initialization(x: usize) -> usize {
     if x > 5 {
         y = echo(10).await;
     }
-    y
-    //~^ use of possibly-uninitialized variable: `y`
+    y //~ ERROR E0381
 }
 
 async fn echo(x: usize) -> usize { x + 1 }
diff --git a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr
index f5991f4bcca..12c15bf56ce 100644
--- a/src/test/ui/async-await/no-non-guaranteed-initialization.stderr
+++ b/src/test/ui/async-await/no-non-guaranteed-initialization.stderr
@@ -1,8 +1,15 @@
-error[E0381]: use of possibly-uninitialized variable: `y`
+error[E0381]: used binding `y` is possibly-uninitialized
   --> $DIR/no-non-guaranteed-initialization.rs:9:5
    |
+LL |     let y;
+   |         - binding declared here but left uninitialized
+LL |     if x > 5 {
+   |        ----- if this `if` condition is `false`, `y` is not initialized
+LL |         y = echo(10).await;
+LL |     }
+   |      - an `else` arm might be missing here, initializing `y`
 LL |     y
-   |     ^ use of possibly-uninitialized `y`
+   |     ^ `y` used here but it is possibly-uninitialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/partial-initialization-across-await.rs b/src/test/ui/async-await/partial-initialization-across-await.rs
index 8a98a4b0f6b..7577aee3fb7 100644
--- a/src/test/ui/async-await/partial-initialization-across-await.rs
+++ b/src/test/ui/async-await/partial-initialization-across-await.rs
@@ -10,8 +10,7 @@ async fn noop() {}
 
 async fn test_tuple() {
     let mut t: (i32, i32);
-    t.0 = 42;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.0 = 42; //~ ERROR E0381
     noop().await;
     t.1 = 88;
     let _ = t;
@@ -19,8 +18,7 @@ async fn test_tuple() {
 
 async fn test_tuple_struct() {
     let mut t: T;
-    t.0 = 42;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.0 = 42; //~ ERROR E0381
     noop().await;
     t.1 = 88;
     let _ = t;
@@ -28,8 +26,7 @@ async fn test_tuple_struct() {
 
 async fn test_struct() {
     let mut t: S;
-    t.x = 42;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.x = 42; //~ ERROR E0381
     noop().await;
     t.y = 88;
     let _ = t;
diff --git a/src/test/ui/async-await/partial-initialization-across-await.stderr b/src/test/ui/async-await/partial-initialization-across-await.stderr
index 9a510c22c4b..6a0eeffb946 100644
--- a/src/test/ui/async-await/partial-initialization-across-await.stderr
+++ b/src/test/ui/async-await/partial-initialization-across-await.stderr
@@ -1,20 +1,32 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/partial-initialization-across-await.rs:13:5
    |
+LL |     let mut t: (i32, i32);
+   |         ----- binding declared here but left uninitialized
 LL |     t.0 = 42;
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/partial-initialization-across-await.rs:22:5
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/partial-initialization-across-await.rs:21:5
    |
+LL |     let mut t: T;
+   |         ----- binding declared here but left uninitialized
 LL |     t.0 = 42;
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/partial-initialization-across-await.rs:31:5
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/partial-initialization-across-await.rs:29:5
    |
+LL |     let mut t: S;
+   |         ----- binding declared here but left uninitialized
 LL |     t.x = 42;
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/async-await/pin-needed-to-poll.stderr b/src/test/ui/async-await/pin-needed-to-poll.stderr
index ba22b7aaf98..2e8723b2743 100644
--- a/src/test/ui/async-await/pin-needed-to-poll.stderr
+++ b/src/test/ui/async-await/pin-needed-to-poll.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `poll` found for struct `Sleep` in the current sco
   --> $DIR/pin-needed-to-poll.rs:42:20
    |
 LL | struct Sleep;
-   |        ----- method `poll` not found for this struct
+   | ------------ method `poll` not found for this struct
 ...
 LL |         self.sleep.poll(cx)
    |                    ^^^^ method not found in `Sleep`
diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr
index e9ca0ad9029..37bad64c5bf 100644
--- a/src/test/ui/block-result/issue-20862.stderr
+++ b/src/test/ui/block-result/issue-20862.stderr
@@ -7,7 +7,7 @@ LL |     |y| x + y
    |     ^^^^^^^^^ expected `()`, found closure
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14]`
+                found closure `[closure@$DIR/issue-20862.rs:2:5: 2:8]`
 
 error[E0618]: expected function, found `()`
   --> $DIR/issue-20862.rs:7:13
diff --git a/src/test/ui/bogus-tag.stderr b/src/test/ui/bogus-tag.stderr
index b215adfa593..899ff4261ba 100644
--- a/src/test/ui/bogus-tag.stderr
+++ b/src/test/ui/bogus-tag.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Hsl` found for enum `Color` i
   --> $DIR/bogus-tag.rs:7:16
    |
 LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), }
-   |      ----- variant or associated item `Hsl` not found for this enum
+   | ---------- variant or associated item `Hsl` not found for this enum
 ...
 LL |         Color::Hsl(h, s, l) => { println!("hsl"); }
    |                ^^^ variant or associated item not found in `Color`
diff --git a/src/test/ui/borrowck/assign_mutable_fields.stderr b/src/test/ui/borrowck/assign_mutable_fields.stderr
index 40f1aae092d..1ed92865da5 100644
--- a/src/test/ui/borrowck/assign_mutable_fields.stderr
+++ b/src/test/ui/borrowck/assign_mutable_fields.stderr
@@ -1,14 +1,22 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/assign_mutable_fields.rs:9:5
    |
+LL |     let mut x: (u32, u32);
+   |         ----- binding declared here but left uninitialized
 LL |     x.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/assign_mutable_fields.rs:17:5
    |
+LL |     let mut x: (u32, u32);
+   |         ----- binding declared here but left uninitialized
 LL |     x.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr
index 003c40d2773..6235e0db0da 100644
--- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr
+++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation-impl-trait.stderr
@@ -1,15 +1,13 @@
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9
    |
-LL |   fn bar() -> impl Fn() -> usize {
-   |      ---      ------------------ change this to return `FnMut` instead of `Fn`
-LL |       let mut x = 0;
-LL | /     move || {
-LL | |         x += 1;
-   | |         ^^^^^^ cannot assign
-LL | |         x
-LL | |     }
-   | |_____- in this closure
+LL | fn bar() -> impl Fn() -> usize {
+   |    ---      ------------------ change this to return `FnMut` instead of `Fn`
+LL |     let mut x = 0;
+LL |     move || {
+   |     ------- in this closure
+LL |         x += 1;
+   |         ^^^^^^ cannot assign
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
index a28cb7431e6..093589ed092 100644
--- a/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
+++ b/src/test/ui/borrowck/borrow-immutable-upvar-mutation.stderr
@@ -5,8 +5,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _f = to_fn(|| x = 42);
-   |                  -----    ^^^^^^ cannot assign
-   |                  |
+   |                  ----- -- ^^^^^^ cannot assign
+   |                  |     |
+   |                  |     in this closure
    |                  expects `Fn` instead of `FnMut`
 
 error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
@@ -16,8 +17,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _g = to_fn(|| set(&mut y));
-   |                  -----        ^^^^^^ cannot borrow as mutable
-   |                  |
+   |                  ----- --     ^^^^^^ cannot borrow as mutable
+   |                  |     |
+   |                  |     in this closure
    |                  expects `Fn` instead of `FnMut`
 
 error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
@@ -27,8 +29,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |             to_fn(|| z = 42);
-   |             -----    ^^^^^^ cannot assign
-   |             |
+   |             ----- -- ^^^^^^ cannot assign
+   |             |     |
+   |             |     in this closure
    |             expects `Fn` instead of `FnMut`
 
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
@@ -38,8 +41,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _f = to_fn(move || x = 42);
-   |                  -----         ^^^^^^ cannot assign
-   |                  |
+   |                  ----- ------- ^^^^^^ cannot assign
+   |                  |     |
+   |                  |     in this closure
    |                  expects `Fn` instead of `FnMut`
 
 error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
@@ -49,8 +53,9 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         let _g = to_fn(move || set(&mut y));
-   |                  -----             ^^^^^^ cannot borrow as mutable
-   |                  |
+   |                  ----- -------     ^^^^^^ cannot borrow as mutable
+   |                  |     |
+   |                  |     in this closure
    |                  expects `Fn` instead of `FnMut`
 
 error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
@@ -60,23 +65,21 @@ LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
    |                          - change this to accept `FnMut` instead of `Fn`
 ...
 LL |             to_fn(move || z = 42);
-   |             -----         ^^^^^^ cannot assign
-   |             |
+   |             ----- ------- ^^^^^^ cannot assign
+   |             |     |
+   |             |     in this closure
    |             expects `Fn` instead of `FnMut`
 
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-immutable-upvar-mutation.rs:53:9
    |
-LL |   fn foo() -> Box<dyn Fn() -> usize> {
-   |      ---      ---------------------- change this to return `FnMut` instead of `Fn`
-LL |       let mut x = 0;
-LL |       Box::new(move || {
-   |  ______________-
-LL | |         x += 1;
-   | |         ^^^^^^ cannot assign
-LL | |         x
-LL | |     })
-   | |_____- in this closure
+LL | fn foo() -> Box<dyn Fn() -> usize> {
+   |    ---      ---------------------- change this to return `FnMut` instead of `Fn`
+LL |     let mut x = 0;
+LL |     Box::new(move || {
+   |              ------- in this closure
+LL |         x += 1;
+   |         ^^^^^^ cannot assign
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
index ea74fb96684..869375cb2c6 100644
--- a/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
+++ b/src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
@@ -29,32 +29,28 @@ LL |     f();
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-raw-address-of-mutability.rs:29:17
    |
-LL |   fn make_fn<F: Fn()>(f: F) -> F { f }
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn make_fn<F: Fn()>(f: F) -> F { f }
+   |                        - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       let f = make_fn(|| {
-   |  _____________-------_-
-   | |             |
-   | |             expects `Fn` instead of `FnMut`
-LL | |         let y = &raw mut x;
-   | |                 ^^^^^^^^^^ cannot borrow as mutable
-LL | |     });
-   | |_____- in this closure
+LL |     let f = make_fn(|| {
+   |             ------- -- in this closure
+   |             |
+   |             expects `Fn` instead of `FnMut`
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/borrow-raw-address-of-mutability.rs:37:17
    |
-LL |   fn make_fn<F: Fn()>(f: F) -> F { f }
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn make_fn<F: Fn()>(f: F) -> F { f }
+   |                        - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       let f = make_fn(move || {
-   |  _____________-------_-
-   | |             |
-   | |             expects `Fn` instead of `FnMut`
-LL | |         let y = &raw mut x;
-   | |                 ^^^^^^^^^^ cannot borrow as mutable
-LL | |     });
-   | |_____- in this closure
+LL |     let f = make_fn(move || {
+   |             ------- ------- in this closure
+   |             |
+   |             expects `Fn` instead of `FnMut`
+LL |         let y = &raw mut x;
+   |                 ^^^^^^^^^^ cannot borrow as mutable
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-and-init.rs b/src/test/ui/borrowck/borrowck-and-init.rs
index f11d44e2217..eeb4f05d60c 100644
--- a/src/test/ui/borrowck/borrowck-and-init.rs
+++ b/src/test/ui/borrowck/borrowck-and-init.rs
@@ -2,5 +2,5 @@ fn main() {
     let i: isize;
 
     println!("{}", false && { i = 5; true });
-    println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i`
+    println!("{}", i); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-and-init.stderr b/src/test/ui/borrowck/borrowck-and-init.stderr
index d2c7473c036..7f3d27d6091 100644
--- a/src/test/ui/borrowck/borrowck-and-init.stderr
+++ b/src/test/ui/borrowck/borrowck-and-init.stderr
@@ -1,8 +1,13 @@
-error[E0381]: borrow of possibly-uninitialized variable: `i`
+error[E0381]: used binding `i` is possibly-uninitialized
   --> $DIR/borrowck-and-init.rs:5:20
    |
+LL |     let i: isize;
+   |         - binding declared here but left uninitialized
+LL |
+LL |     println!("{}", false && { i = 5; true });
+   |                               ----- binding initialized here in some conditions
 LL |     println!("{}", i);
-   |                    ^ use of possibly-uninitialized `i`
+   |                    ^ `i` used here but it is possibly-uninitialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/borrowck-block-unint.rs b/src/test/ui/borrowck/borrowck-block-unint.rs
index 1e7306acaee..8d13b25a357 100644
--- a/src/test/ui/borrowck/borrowck-block-unint.rs
+++ b/src/test/ui/borrowck/borrowck-block-unint.rs
@@ -1,7 +1,7 @@
 fn force<F>(f: F) where F: FnOnce() { f(); }
 fn main() {
     let x: isize;
-    force(|| {  //~ ERROR borrow of possibly-uninitialized variable: `x`
+    force(|| {  //~ ERROR E0381
         println!("{}", x);
     });
 }
diff --git a/src/test/ui/borrowck/borrowck-block-unint.stderr b/src/test/ui/borrowck/borrowck-block-unint.stderr
index 578f89df46c..e720db1c696 100644
--- a/src/test/ui/borrowck/borrowck-block-unint.stderr
+++ b/src/test/ui/borrowck/borrowck-block-unint.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-block-unint.rs:4:11
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     force(|| {
-   |           ^^ use of possibly-uninitialized `x`
+   |           ^^ `x` used here but it isn't initialized
 LL |         println!("{}", x);
    |                        - borrow occurs due to use in closure
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.rs b/src/test/ui/borrowck/borrowck-break-uninit-2.rs
index 126d991a51c..3abca33a84a 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit-2.rs
+++ b/src/test/ui/borrowck/borrowck-break-uninit-2.rs
@@ -6,7 +6,7 @@ fn foo() -> isize {
         x = 0;
     }
 
-    println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x`
+    println!("{}", x); //~ ERROR E0381
 
     return 17;
 }
diff --git a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
index b134f5cc2d8..23ea1a2de7f 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit-2.stderr
@@ -1,8 +1,11 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-break-uninit-2.rs:9:20
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+...
 LL |     println!("{}", x);
-   |                    ^ use of possibly-uninitialized `x`
+   |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/borrowck-break-uninit.rs b/src/test/ui/borrowck/borrowck-break-uninit.rs
index 8ccb21ae8ee..824f91dbc62 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit.rs
+++ b/src/test/ui/borrowck/borrowck-break-uninit.rs
@@ -6,7 +6,7 @@ fn foo() -> isize {
         x = 0;
     }
 
-    println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x`
+    println!("{}", x); //~ ERROR E0381
 
     return 17;
 }
diff --git a/src/test/ui/borrowck/borrowck-break-uninit.stderr b/src/test/ui/borrowck/borrowck-break-uninit.stderr
index 652d7d3076f..2b9b0a190f6 100644
--- a/src/test/ui/borrowck/borrowck-break-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-break-uninit.stderr
@@ -1,8 +1,11 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-break-uninit.rs:9:20
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+...
 LL |     println!("{}", x);
-   |                    ^ use of possibly-uninitialized `x`
+   |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.rs b/src/test/ui/borrowck/borrowck-field-sensitivity.rs
index 50edfb6ba2d..03edf445ee9 100644
--- a/src/test/ui/borrowck/borrowck-field-sensitivity.rs
+++ b/src/test/ui/borrowck/borrowck-field-sensitivity.rs
@@ -78,20 +78,20 @@ fn fu_move_after_fu_move() {
 
 fn copy_after_field_assign_after_uninit() {
     let mut x: A;
-    x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x`
+    x.a = 1; //~ ERROR E0381
     drop(x.a);
 }
 
 fn borrow_after_field_assign_after_uninit() {
     let mut x: A;
-    x.a = 1; //~ ERROR assign to part of possibly-uninitialized variable: `x`
+    x.a = 1; //~ ERROR E0381
     let p = &x.a;
     drop(*p);
 }
 
 fn move_after_field_assign_after_uninit() {
     let mut x: A;
-    x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x`
+    x.b = Box::new(1); //~ ERROR E0381
     drop(x.b);
 }
 
diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr
index bb4d2f06016..e009f5913ed 100644
--- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr
+++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr
@@ -108,23 +108,35 @@ LL |     let _z = A { a: 4, .. x };
    |
    = note: move occurs because `x.b` has type `Box<isize>`, which does not implement the `Copy` trait
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/borrowck-field-sensitivity.rs:81:5
    |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
 LL |     x.a = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/borrowck-field-sensitivity.rs:87:5
    |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
 LL |     x.a = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/borrowck-field-sensitivity.rs:94:5
    |
+LL |     let mut x: A;
+   |         ----- binding declared here but left uninitialized
 LL |     x.b = Box::new(1);
-   |     ^^^ use of possibly-uninitialized `x`
+   |     ^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs
new file mode 100644
index 00000000000..f619c045b25
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.rs
@@ -0,0 +1,7 @@
+fn f() -> isize {
+    let mut x: isize;
+    for _ in 0..0 { x = 10; }
+    return x; //~ ERROR E0381
+}
+
+fn main() { f(); }
diff --git a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
new file mode 100644
index 00000000000..c08c93f3617
--- /dev/null
+++ b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
@@ -0,0 +1,13 @@
+error[E0381]: used binding `x` is possibly-uninitialized
+  --> $DIR/borrowck-for-loop-uninitialized-binding.rs:4:12
+   |
+LL |     let mut x: isize;
+   |         ----- binding declared here but left uninitialized
+LL |     for _ in 0..0 { x = 10; }
+   |              ---- if the `for` loop runs 0 times, `x` is not initialized 
+LL |     return x;
+   |            ^ `x` used here but it is possibly-uninitialized
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/borrowck/borrowck-if-no-else.rs b/src/test/ui/borrowck/borrowck-if-no-else.rs
index f59bcad6f61..534d771be1d 100644
--- a/src/test/ui/borrowck/borrowck-if-no-else.rs
+++ b/src/test/ui/borrowck/borrowck-if-no-else.rs
@@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); }
 
 fn main() {
     let x: isize; if 1 > 2 { x = 10; }
-    foo(x); //~ ERROR use of possibly-uninitialized variable: `x`
+    foo(x); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-if-no-else.stderr b/src/test/ui/borrowck/borrowck-if-no-else.stderr
index 3e9d3d4f6d5..9eafc2c2a86 100644
--- a/src/test/ui/borrowck/borrowck-if-no-else.stderr
+++ b/src/test/ui/borrowck/borrowck-if-no-else.stderr
@@ -1,8 +1,13 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` is possibly-uninitialized
   --> $DIR/borrowck-if-no-else.rs:5:9
    |
+LL |     let x: isize; if 1 > 2 { x = 10; }
+   |         -            -----            - an `else` arm might be missing here, initializing `x`
+   |         |            |
+   |         |            if this `if` condition is `false`, `x` is not initialized
+   |         binding declared here but left uninitialized
 LL |     foo(x);
-   |         ^ use of possibly-uninitialized `x`
+   |         ^ `x` used here but it is possibly-uninitialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-if-with-else.rs b/src/test/ui/borrowck/borrowck-if-with-else.rs
index c13318b16c2..69d450c5989 100644
--- a/src/test/ui/borrowck/borrowck-if-with-else.rs
+++ b/src/test/ui/borrowck/borrowck-if-with-else.rs
@@ -7,5 +7,5 @@ fn main() {
     } else {
         x = 10;
     }
-    foo(x); //~ ERROR use of possibly-uninitialized variable: `x`
+    foo(x); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-if-with-else.stderr b/src/test/ui/borrowck/borrowck-if-with-else.stderr
index 53b8a6bba2c..3f0fe291ca2 100644
--- a/src/test/ui/borrowck/borrowck-if-with-else.stderr
+++ b/src/test/ui/borrowck/borrowck-if-with-else.stderr
@@ -1,8 +1,13 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` is possibly-uninitialized
   --> $DIR/borrowck-if-with-else.rs:10:9
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
+LL |     if 1 > 2 {
+   |        ----- if this condition is `true`, `x` is not initialized
+...
 LL |     foo(x);
-   |         ^ use of possibly-uninitialized `x`
+   |         ^ `x` used here but it is possibly-uninitialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr
index 30e74c5ec95..2033e4a5730 100644
--- a/src/test/ui/borrowck/borrowck-in-static.stderr
+++ b/src/test/ui/borrowck/borrowck-in-static.stderr
@@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |     let x = Box::new(0);
    |         - captured outer variable
 LL |     Box::new(|| x)
-   |              ---^
-   |              |  |
-   |              |  move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |              -- ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |              |
    |              captured by this `Fn` closure
 
 error: aborting due to previous error
diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs
index 9905e420f94..e6476b9c1be 100644
--- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs
+++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.rs
@@ -1,7 +1,7 @@
 fn main() {
     let j = || -> isize {
         let i: isize;
-        i //~ ERROR use of possibly-uninitialized variable: `i`
+        i //~ ERROR E0381
     };
     j();
 }
diff --git a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
index 2d1d9bc8fa4..e8a2fbc91ea 100644
--- a/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-called-fn-expr.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `i`
+error[E0381]: used binding `i` isn't initialized
   --> $DIR/borrowck-init-in-called-fn-expr.rs:4:9
    |
+LL |         let i: isize;
+   |             - binding declared here but left uninitialized
 LL |         i
-   |         ^ use of possibly-uninitialized `i`
+   |         ^ `i` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs
index 7dd3396c8c2..7eb204a0d16 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs
+++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.rs
@@ -1,7 +1,7 @@
 fn main() {
     let f  = || -> isize {
         let i: isize;
-        i //~ ERROR use of possibly-uninitialized variable: `i`
+        i //~ ERROR E0381
     };
     println!("{}", f());
 }
diff --git a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
index fd8b90eda60..1e950d6a20d 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fn-expr.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `i`
+error[E0381]: used binding `i` isn't initialized
   --> $DIR/borrowck-init-in-fn-expr.rs:4:9
    |
+LL |         let i: isize;
+   |             - binding declared here but left uninitialized
 LL |         i
-   |         ^ use of possibly-uninitialized `i`
+   |         ^ `i` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.rs b/src/test/ui/borrowck/borrowck-init-in-fru.rs
index d7ec2ed75c8..c07957ab139 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fru.rs
+++ b/src/test/ui/borrowck/borrowck-init-in-fru.rs
@@ -7,6 +7,6 @@ struct Point {
 fn main() {
     let mut origin: Point;
     origin = Point { x: 10, ..origin };
-    //~^ ERROR use of possibly-uninitialized variable: `origin` [E0381]
+    //~^ ERROR E0381
     origin.clone();
 }
diff --git a/src/test/ui/borrowck/borrowck-init-in-fru.stderr b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
index f01afe1466a..83a3e3e0e3a 100644
--- a/src/test/ui/borrowck/borrowck-init-in-fru.stderr
+++ b/src/test/ui/borrowck/borrowck-init-in-fru.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `origin`
+error[E0381]: used binding `origin` isn't initialized
   --> $DIR/borrowck-init-in-fru.rs:9:14
    |
+LL |     let mut origin: Point;
+   |         ---------- binding declared here but left uninitialized
 LL |     origin = Point { x: 10, ..origin };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `origin.y`
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ `origin.y` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.rs b/src/test/ui/borrowck/borrowck-init-op-equal.rs
index 784eb8cf85b..3d08c1b81a7 100644
--- a/src/test/ui/borrowck/borrowck-init-op-equal.rs
+++ b/src/test/ui/borrowck/borrowck-init-op-equal.rs
@@ -1,6 +1,6 @@
 fn test() {
     let v: isize;
-    v += 1; //~ ERROR use of possibly-uninitialized variable: `v`
+    v += 1; //~ ERROR E0381
     v.clone();
 }
 
diff --git a/src/test/ui/borrowck/borrowck-init-op-equal.stderr b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
index 6c88778ae0e..74704b2abfe 100644
--- a/src/test/ui/borrowck/borrowck-init-op-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-op-equal.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `v`
+error[E0381]: used binding `v` isn't initialized
   --> $DIR/borrowck-init-op-equal.rs:3:5
    |
+LL |     let v: isize;
+   |         - binding declared here but left uninitialized
 LL |     v += 1;
-   |     ^^^^^^ use of possibly-uninitialized `v`
+   |     ^^^^^^ `v` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.rs b/src/test/ui/borrowck/borrowck-init-plus-equal.rs
index d9d20a2a9c1..2a52a3f4e5e 100644
--- a/src/test/ui/borrowck/borrowck-init-plus-equal.rs
+++ b/src/test/ui/borrowck/borrowck-init-plus-equal.rs
@@ -1,6 +1,6 @@
 fn test() {
     let mut v: isize;
-    v = v + 1; //~ ERROR use of possibly-uninitialized variable: `v`
+    v = v + 1; //~ ERROR E0381
     v.clone();
 }
 
diff --git a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
index fe09c8581df..7542576d636 100644
--- a/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
+++ b/src/test/ui/borrowck/borrowck-init-plus-equal.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `v`
+error[E0381]: used binding `v` isn't initialized
   --> $DIR/borrowck-init-plus-equal.rs:3:9
    |
+LL |     let mut v: isize;
+   |         ----- binding declared here but left uninitialized
 LL |     v = v + 1;
-   |         ^ use of possibly-uninitialized `v`
+   |         ^ `v` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
index f81b34a641b..8ddc48b2a99 100644
--- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr
+++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr
@@ -1,18 +1,16 @@
 error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-move-by-capture.rs:9:29
    |
-LL |       let bar: Box<_> = Box::new(3);
-   |           --- captured outer variable
-LL |       let _g = to_fn_mut(|| {
-   |  ________________________-
-LL | |         let _h = to_fn_once(move || -> isize { *bar });
-   | |                             ^^^^^^^^^^^^^^^^   ----
-   | |                             |                  |
-   | |                             |                  variable moved due to use in closure
-   | |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
-   | |                             move out of `bar` occurs here
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let bar: Box<_> = Box::new(3);
+   |         --- captured outer variable
+LL |     let _g = to_fn_mut(|| {
+   |                        -- captured by this `FnMut` closure
+LL |         let _h = to_fn_once(move || -> isize { *bar });
+   |                             ^^^^^^^^^^^^^^^^   ----
+   |                             |                  |
+   |                             |                  variable moved due to use in closure
+   |                             |                  move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
+   |                             move out of `bar` occurs here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-or-init.rs b/src/test/ui/borrowck/borrowck-or-init.rs
index 81b0b80bf11..079cf899e6d 100644
--- a/src/test/ui/borrowck/borrowck-or-init.rs
+++ b/src/test/ui/borrowck/borrowck-or-init.rs
@@ -2,5 +2,5 @@ fn main() {
     let i: isize;
 
     println!("{}", false || { i = 5; true });
-    println!("{}", i); //~ ERROR borrow of possibly-uninitialized variable: `i`
+    println!("{}", i); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-or-init.stderr b/src/test/ui/borrowck/borrowck-or-init.stderr
index 6c757759f71..0bc24f1b693 100644
--- a/src/test/ui/borrowck/borrowck-or-init.stderr
+++ b/src/test/ui/borrowck/borrowck-or-init.stderr
@@ -1,8 +1,13 @@
-error[E0381]: borrow of possibly-uninitialized variable: `i`
+error[E0381]: used binding `i` is possibly-uninitialized
   --> $DIR/borrowck-or-init.rs:5:20
    |
+LL |     let i: isize;
+   |         - binding declared here but left uninitialized
+LL |
+LL |     println!("{}", false || { i = 5; true });
+   |                               ----- binding initialized here in some conditions
 LL |     println!("{}", i);
-   |                    ^ use of possibly-uninitialized `i`
+   |                    ^ `i` used here but it is possibly-uninitialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs
index 5e5a8cdf423..a43a1936678 100644
--- a/src/test/ui/borrowck/borrowck-partial-reinit-4.rs
+++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.rs
@@ -14,8 +14,7 @@ impl Drop for Test2 {
 
 fn stuff() {
     let mut x : (Test2, Test2);
-    (x.0).0 = Some(Test);
-    //~^ ERROR assign of possibly-uninitialized variable: `x.0`
+    (x.0).0 = Some(Test); //~ ERROR E0381
 }
 
 fn main() {
diff --git a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr
index 218c4f2de5b..d12a482cb69 100644
--- a/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr
+++ b/src/test/ui/borrowck/borrowck-partial-reinit-4.stderr
@@ -1,8 +1,12 @@
-error[E0381]: assign of possibly-uninitialized variable: `x.0`
+error[E0381]: assigned binding `x.0` isn't fully initialized
   --> $DIR/borrowck-partial-reinit-4.rs:17:5
    |
+LL |     let mut x : (Test2, Test2);
+   |         ----- binding declared here but left uninitialized
 LL |     (x.0).0 = Some(Test);
-   |     ^^^^^^^ use of possibly-uninitialized `x.0`
+   |     ^^^^^^^ `x.0` assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-return.rs b/src/test/ui/borrowck/borrowck-return.rs
index 8c623356f6c..a63ffcff732 100644
--- a/src/test/ui/borrowck/borrowck-return.rs
+++ b/src/test/ui/borrowck/borrowck-return.rs
@@ -1,6 +1,6 @@
 fn f() -> isize {
     let x: isize;
-    return x; //~ ERROR use of possibly-uninitialized variable: `x`
+    return x; //~ ERROR E0381
 }
 
 fn main() { f(); }
diff --git a/src/test/ui/borrowck/borrowck-return.stderr b/src/test/ui/borrowck/borrowck-return.stderr
index bc74e8e3438..1c916e22317 100644
--- a/src/test/ui/borrowck/borrowck-return.stderr
+++ b/src/test/ui/borrowck/borrowck-return.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-return.rs:3:12
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     return x;
-   |            ^ use of possibly-uninitialized `x`
+   |            ^ `x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-storage-dead.stderr b/src/test/ui/borrowck/borrowck-storage-dead.stderr
index 8e4932142f0..2cea4392d6a 100644
--- a/src/test/ui/borrowck/borrowck-storage-dead.stderr
+++ b/src/test/ui/borrowck/borrowck-storage-dead.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-storage-dead.rs:16:17
    |
+LL |         let x: i32;
+   |             - binding declared here but left uninitialized
 LL |         let _ = x + 1;
-   |                 ^ use of possibly-uninitialized `x`
+   |                 ^ `x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.rs b/src/test/ui/borrowck/borrowck-uninit-after-item.rs
index e9a389657c8..e97ce6aa407 100644
--- a/src/test/ui/borrowck/borrowck-uninit-after-item.rs
+++ b/src/test/ui/borrowck/borrowck-uninit-after-item.rs
@@ -1,5 +1,5 @@
 fn main() {
     let bar;
     fn baz(_x: isize) { }
-    baz(bar); //~ ERROR use of possibly-uninitialized variable: `bar`
+    baz(bar); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
index f7f069b81be..588b1b0c972 100644
--- a/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-after-item.stderr
@@ -1,8 +1,11 @@
-error[E0381]: use of possibly-uninitialized variable: `bar`
+error[E0381]: used binding `bar` isn't initialized
   --> $DIR/borrowck-uninit-after-item.rs:4:9
    |
+LL |     let bar;
+   |         --- binding declared here but left uninitialized
+LL |     fn baz(_x: isize) { }
 LL |     baz(bar);
-   |         ^^^ use of possibly-uninitialized `bar`
+   |         ^^^ `bar` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
index 7951a5b1b5d..6a38a798919 100644
--- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `a`
+error[E0381]: used binding `a` isn't initialized
   --> $DIR/borrowck-uninit-field-access.rs:21:13
    |
+LL |     let mut a: Point;
+   |         ----- binding declared here but left uninitialized
 LL |     let _ = a.x + 1;
-   |             ^^^ use of possibly-uninitialized `a.x`
+   |             ^^^ `a.x` used here but it isn't initialized
 
 error[E0382]: use of moved value: `line1.origin`
   --> $DIR/borrowck-uninit-field-access.rs:25:13
diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs
index 20350d61d5b..92c3692bd2f 100644
--- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs
+++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.rs
@@ -3,32 +3,32 @@
 
 pub fn main() {
     let x: isize;
-    x += 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x += 1; //~ ERROR E0381
 
     let x: isize;
-    x -= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x -= 1; //~ ERROR E0381
 
     let x: isize;
-    x *= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x *= 1; //~ ERROR E0381
 
     let x: isize;
-    x /= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x /= 1; //~ ERROR E0381
 
     let x: isize;
-    x %= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x %= 1; //~ ERROR E0381
 
     let x: isize;
-    x ^= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x ^= 1; //~ ERROR E0381
 
     let x: isize;
-    x &= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x &= 1; //~ ERROR E0381
 
     let x: isize;
-    x |= 1; //~ ERROR use of possibly-uninitialized variable: `x`
+    x |= 1; //~ ERROR E0381
 
     let x: isize;
-    x <<= 1;    //~ ERROR use of possibly-uninitialized variable: `x`
+    x <<= 1; //~ ERROR E0381
 
     let x: isize;
-    x >>= 1;    //~ ERROR use of possibly-uninitialized variable: `x`
+    x >>= 1; //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
index f2036df3ce9..744cb14e662 100644
--- a/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-in-assignop.stderr
@@ -1,62 +1,82 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:6:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x += 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:9:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x -= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:12:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x *= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:15:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x /= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:18:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x %= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:21:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x ^= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:24:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x &= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:27:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x |= 1;
-   |     ^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:30:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x <<= 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-in-assignop.rs:33:5
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     x >>= 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` used here but it isn't initialized
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs
index 0ccea49f329..c36b9707d22 100644
--- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs
+++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.rs
@@ -5,29 +5,29 @@ struct S<X, Y> {
 
 fn main() {
     let x: &&Box<i32>;
-    let _y = &**x; //~ [E0381]
+    let _y = &**x; //~ ERROR [E0381]
 
     let x: &&S<i32, i32>;
-    let _y = &**x; //~ [E0381]
+    let _y = &**x; //~ ERROR [E0381]
 
     let x: &&i32;
-    let _y = &**x; //~ [E0381]
+    let _y = &**x; //~ ERROR [E0381]
 
 
     let mut a: S<i32, i32>;
-    a.x = 0;            //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381]
+    a.x = 0; //~ ERROR [E0381]
     let _b = &a.x;
 
     let mut a: S<&&i32, &&i32>;
-    a.x = &&0;          //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381]
+    a.x = &&0; //~ ERROR [E0381]
     let _b = &**a.x;
 
 
     let mut a: S<i32, i32>;
-    a.x = 0;            //~ ERROR assign to part of possibly-uninitialized variable: `a` [E0381]
+    a.x = 0; //~ ERROR [E0381]
     let _b = &a.y;
 
     let mut a: S<&&i32, &&i32>;
-    a.x = &&0;          //~ assign to part of possibly-uninitialized variable: `a` [E0381]
+    a.x = &&0; //~ ERROR [E0381]
     let _b = &**a.y;
 }
diff --git a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
index d99a50df75b..c486cb6dd0c 100644
--- a/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit-ref-chain.stderr
@@ -1,44 +1,66 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:8:14
    |
+LL |     let x: &&Box<i32>;
+   |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
-   |              ^^^^ use of possibly-uninitialized `**x`
+   |              ^^^^ `**x` used here but it isn't initialized
 
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:11:14
    |
+LL |     let x: &&S<i32, i32>;
+   |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
-   |              ^^^^ use of possibly-uninitialized `**x`
+   |              ^^^^ `**x` used here but it isn't initialized
 
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:14:14
    |
+LL |     let x: &&i32;
+   |         - binding declared here but left uninitialized
 LL |     let _y = &**x;
-   |              ^^^^ use of possibly-uninitialized `**x`
+   |              ^^^^ `**x` used here but it isn't initialized
 
-error[E0381]: assign to part of possibly-uninitialized variable: `a`
+error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:18:5
    |
+LL |     let mut a: S<i32, i32>;
+   |         ----- binding declared here but left uninitialized
 LL |     a.x = 0;
-   |     ^^^^^^^ use of possibly-uninitialized `a`
+   |     ^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `a`
+error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:22:5
    |
+LL |     let mut a: S<&&i32, &&i32>;
+   |         ----- binding declared here but left uninitialized
 LL |     a.x = &&0;
-   |     ^^^^^^^^^ use of possibly-uninitialized `a`
+   |     ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `a`
+error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:27:5
    |
+LL |     let mut a: S<i32, i32>;
+   |         ----- binding declared here but left uninitialized
 LL |     a.x = 0;
-   |     ^^^^^^^ use of possibly-uninitialized `a`
+   |     ^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `a`
+error[E0381]: partially assigned binding `a` isn't fully initialized
   --> $DIR/borrowck-uninit-ref-chain.rs:31:5
    |
+LL |     let mut a: S<&&i32, &&i32>;
+   |         ----- binding declared here but left uninitialized
 LL |     a.x = &&0;
-   |     ^^^^^^^^^ use of possibly-uninitialized `a`
+   |     ^^^^^^^^^ `a` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-uninit.rs b/src/test/ui/borrowck/borrowck-uninit.rs
index 017b955a395..5d0ebabb008 100644
--- a/src/test/ui/borrowck/borrowck-uninit.rs
+++ b/src/test/ui/borrowck/borrowck-uninit.rs
@@ -2,5 +2,5 @@ fn foo(x: isize) { println!("{}", x); }
 
 fn main() {
     let x: isize;
-    foo(x); //~ ERROR use of possibly-uninitialized variable: `x`
+    foo(x); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-uninit.stderr b/src/test/ui/borrowck/borrowck-uninit.stderr
index effc209e816..d5566691a82 100644
--- a/src/test/ui/borrowck/borrowck-uninit.stderr
+++ b/src/test/ui/borrowck/borrowck-uninit.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-uninit.rs:5:9
    |
+LL |     let x: isize;
+   |         - binding declared here but left uninitialized
 LL |     foo(x);
-   |         ^ use of possibly-uninitialized `x`
+   |         ^ `x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.rs b/src/test/ui/borrowck/borrowck-union-uninitialized.rs
index 3cc71e7cece..bbe9f22aac3 100644
--- a/src/test/ui/borrowck/borrowck-union-uninitialized.rs
+++ b/src/test/ui/borrowck/borrowck-union-uninitialized.rs
@@ -10,8 +10,8 @@ fn main() {
     unsafe {
         let mut s: S;
         let mut u: U;
-        s.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `s`
-        u.a = 0; //~ ERROR assign to part of possibly-uninitialized variable: `u`
+        s.a = 0; //~ ERROR E0381
+        u.a = 0; //~ ERROR E0381
         let sa = s.a;
         let ua = u.a;
     }
diff --git a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr
index bd9ec5e579c..b7ff5f3955e 100644
--- a/src/test/ui/borrowck/borrowck-union-uninitialized.stderr
+++ b/src/test/ui/borrowck/borrowck-union-uninitialized.stderr
@@ -1,14 +1,24 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `s`
+error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/borrowck-union-uninitialized.rs:13:9
    |
+LL |         let mut s: S;
+   |             ----- binding declared here but left uninitialized
+LL |         let mut u: U;
 LL |         s.a = 0;
-   |         ^^^^^^^ use of possibly-uninitialized `s`
+   |         ^^^^^^^ `s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `u`
+error[E0381]: partially assigned binding `u` isn't fully initialized
   --> $DIR/borrowck-union-uninitialized.rs:14:9
    |
+LL |         let mut u: U;
+   |             ----- binding declared here but left uninitialized
+LL |         s.a = 0;
 LL |         u.a = 0;
-   |         ^^^^^^^ use of possibly-uninitialized `u`
+   |         ^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
index d1b396aba82..459cf1398b7 100644
--- a/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
+++ b/src/test/ui/borrowck/borrowck-use-in-index-lvalue.stderr
@@ -1,14 +1,18 @@
-error[E0381]: use of possibly-uninitialized variable: `w`
+error[E0381]: used binding `w` isn't initialized
   --> $DIR/borrowck-use-in-index-lvalue.rs:3:5
    |
+LL |     let w: &mut [isize];
+   |         - binding declared here but left uninitialized
 LL |     w[5] = 0;
-   |     ^^^^ use of possibly-uninitialized `*w`
+   |     ^^^^ `*w` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `w`
+error[E0381]: used binding `w` isn't initialized
   --> $DIR/borrowck-use-in-index-lvalue.rs:6:5
    |
+LL |     let mut w: &mut [isize];
+   |         ----- binding declared here but left uninitialized
 LL |     w[5] = 0;
-   |     ^^^^ use of possibly-uninitialized `*w`
+   |     ^^^^ `*w` used here but it isn't initialized
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
index ca5227c98c8..942ed4fc6ca 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast-trait.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-use-uninitialized-in-cast-trait.rs:9:13
    |
+LL |     let x: &i32;
+   |         - binding declared here but left uninitialized
 LL |     let y = x as *const dyn Foo;
-   |             ^ use of possibly-uninitialized `*x`
+   |             ^ `*x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
index 24897a0f2dc..f3289e23981 100644
--- a/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
+++ b/src/test/ui/borrowck/borrowck-use-uninitialized-in-cast.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-use-uninitialized-in-cast.rs:7:13
    |
+LL |     let x: &i32;
+   |         - binding declared here but left uninitialized
 LL |     let y = x as *const i32;
-   |             ^ use of possibly-uninitialized `*x`
+   |             ^ `*x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-while-break.rs b/src/test/ui/borrowck/borrowck-while-break.rs
index 48e42214702..7100b713031 100644
--- a/src/test/ui/borrowck/borrowck-while-break.rs
+++ b/src/test/ui/borrowck/borrowck-while-break.rs
@@ -4,7 +4,7 @@ fn test(cond: bool) {
         v = 3;
         break;
     }
-    println!("{}", v); //~ ERROR borrow of possibly-uninitialized variable: `v`
+    println!("{}", v); //~ ERROR E0381
 }
 
 fn main() {
diff --git a/src/test/ui/borrowck/borrowck-while-break.stderr b/src/test/ui/borrowck/borrowck-while-break.stderr
index fc144a066bb..44674febf49 100644
--- a/src/test/ui/borrowck/borrowck-while-break.stderr
+++ b/src/test/ui/borrowck/borrowck-while-break.stderr
@@ -1,8 +1,13 @@
-error[E0381]: borrow of possibly-uninitialized variable: `v`
+error[E0381]: used binding `v` is possibly-uninitialized
   --> $DIR/borrowck-while-break.rs:7:20
    |
+LL |     let v;
+   |         - binding declared here but left uninitialized
+LL |     while cond {
+   |           ---- if this condition isn't met and the `while` loop runs 0 times, `v` is not initialized
+...
 LL |     println!("{}", v);
-   |                    ^ use of possibly-uninitialized `v`
+   |                    ^ `v` used here but it is possibly-uninitialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/borrowck-while-cond.rs b/src/test/ui/borrowck/borrowck-while-cond.rs
index b3ec20711c1..62a9bdd2020 100644
--- a/src/test/ui/borrowck/borrowck-while-cond.rs
+++ b/src/test/ui/borrowck/borrowck-while-cond.rs
@@ -1,4 +1,4 @@
 fn main() {
     let x: bool;
-    while x { } //~ ERROR use of possibly-uninitialized variable: `x`
+    while x { } //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/borrowck-while-cond.stderr b/src/test/ui/borrowck/borrowck-while-cond.stderr
index 92937a9c573..e41c1c55e60 100644
--- a/src/test/ui/borrowck/borrowck-while-cond.stderr
+++ b/src/test/ui/borrowck/borrowck-while-cond.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/borrowck-while-cond.rs:3:11
    |
+LL |     let x: bool;
+   |         - binding declared here but left uninitialized
 LL |     while x { }
-   |           ^ use of possibly-uninitialized `x`
+   |           ^ `x` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-while.rs b/src/test/ui/borrowck/borrowck-while.rs
index 6b3220c7d85..f49a778eb6b 100644
--- a/src/test/ui/borrowck/borrowck-while.rs
+++ b/src/test/ui/borrowck/borrowck-while.rs
@@ -1,7 +1,7 @@
 fn f() -> isize {
     let mut x: isize;
     while 1 == 1 { x = 10; }
-    return x; //~ ERROR use of possibly-uninitialized variable: `x`
+    return x; //~ ERROR E0381
 }
 
 fn main() { f(); }
diff --git a/src/test/ui/borrowck/borrowck-while.stderr b/src/test/ui/borrowck/borrowck-while.stderr
index a1f8f64725d..c45235990c3 100644
--- a/src/test/ui/borrowck/borrowck-while.stderr
+++ b/src/test/ui/borrowck/borrowck-while.stderr
@@ -1,8 +1,12 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` is possibly-uninitialized
   --> $DIR/borrowck-while.rs:4:12
    |
+LL |     let mut x: isize;
+   |         ----- binding declared here but left uninitialized
+LL |     while 1 == 1 { x = 10; }
+   |           ------ if this condition isn't met and the `while` loop runs 0 times, `x` is not initialized
 LL |     return x;
-   |            ^ use of possibly-uninitialized `x`
+   |            ^ `x` used here but it is possibly-uninitialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs
index 7043cb3a164..17de40d5ba9 100644
--- a/src/test/ui/borrowck/disallow-possibly-uninitialized.rs
+++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.rs
@@ -4,19 +4,19 @@
 fn main() {
     let mut t: (u64, u64);
     t.0 = 1;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    //~^ ERROR E0381
     t.1 = 1;
 
     let mut t: (u64, u64);
     t.1 = 1;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    //~^ ERROR E0381
     t.0 = 1;
 
     let mut t: (u64, u64);
     t.0 = 1;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    //~^ ERROR E0381
 
     let mut t: (u64,);
     t.0 = 1;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    //~^ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr
index 8d5b39341c1..9a84c6fefae 100644
--- a/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr
+++ b/src/test/ui/borrowck/disallow-possibly-uninitialized.stderr
@@ -1,26 +1,42 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/disallow-possibly-uninitialized.rs:6:5
    |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
 LL |     t.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/disallow-possibly-uninitialized.rs:11:5
    |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
 LL |     t.1 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/disallow-possibly-uninitialized.rs:16:5
    |
+LL |     let mut t: (u64, u64);
+   |         ----- binding declared here but left uninitialized
 LL |     t.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/disallow-possibly-uninitialized.rs:20:5
    |
+LL |     let mut t: (u64,);
+   |         ----- binding declared here but left uninitialized
 LL |     t.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.rs b/src/test/ui/borrowck/issue-24267-flow-exit.rs
index d6809ee4143..c419c5840d9 100644
--- a/src/test/ui/borrowck/issue-24267-flow-exit.rs
+++ b/src/test/ui/borrowck/issue-24267-flow-exit.rs
@@ -9,11 +9,11 @@ pub fn main() {
 pub fn foo1() {
     let x: i32;
     loop { x = break; }
-    println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x`
+    println!("{}", x); //~ ERROR E0381
 }
 
 pub fn foo2() {
     let x: i32;
     for _ in 0..10 { x = continue; }
-    println!("{}", x); //~ ERROR borrow of possibly-uninitialized variable: `x`
+    println!("{}", x); //~ ERROR E0381
 }
diff --git a/src/test/ui/borrowck/issue-24267-flow-exit.stderr b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
index e29cf7a1a75..d436e8ff909 100644
--- a/src/test/ui/borrowck/issue-24267-flow-exit.stderr
+++ b/src/test/ui/borrowck/issue-24267-flow-exit.stderr
@@ -1,16 +1,22 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:12:20
    |
+LL |     let x: i32;
+   |         - binding declared here but left uninitialized
+LL |     loop { x = break; }
 LL |     println!("{}", x);
-   |                    ^ use of possibly-uninitialized `x`
+   |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-24267-flow-exit.rs:18:20
    |
+LL |     let x: i32;
+   |         - binding declared here but left uninitialized
+LL |     for _ in 0..10 { x = continue; }
 LL |     println!("{}", x);
-   |                    ^ use of possibly-uninitialized `x`
+   |                    ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
index a7c3b9eec73..d98b3bae4e0 100644
--- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
+++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
 LL |     let _action = move || {
    |                   -------
    |                   |     |
-   |                   |     return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]` contains a lifetime `'2`
+   |                   |     return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:11]` contains a lifetime `'2`
    |                   lifetime `'1` represents this closure's body
 LL |         || f() // The `nested` closure
    |         ^^^^^^ returning this value requires that `'1` must outlive `'2`
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
index f031a144443..205ea10c90b 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs
@@ -10,7 +10,7 @@ fn main() {
     {
         let mut t: Tuple;
         t.0 = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+        //~^ ERROR E0381
         t.1 = 2;
         println!("{:?} {:?}", t.0, t.1);
     }
@@ -18,7 +18,7 @@ fn main() {
     {
         let mut u: Tpair;
         u.0 = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381]
+        //~^ ERROR E0381
         u.1 = 2;
         println!("{:?} {:?}", u.0, u.1);
     }
@@ -26,7 +26,7 @@ fn main() {
     {
         let mut v: Spair;
         v.x = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381]
+        //~^ ERROR E0381
         v.y = 2;
         println!("{:?} {:?}", v.x, v.y);
     }
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr
index 22c6c3964ed..2a0eba396f1 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.stderr
@@ -1,20 +1,32 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:12:9
    |
+LL |         let mut t: Tuple;
+   |             ----- binding declared here but left uninitialized
 LL |         t.0 = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `t`
+   |         ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `u`
+error[E0381]: partially assigned binding `u` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:20:9
    |
+LL |         let mut u: Tpair;
+   |             ----- binding declared here but left uninitialized
 LL |         u.0 = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `u`
+   |         ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `v`
+error[E0381]: partially assigned binding `v` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-marks-mut-as-used.rs:28:9
    |
+LL |         let mut v: Spair;
+   |             ----- binding declared here but left uninitialized
 LL |         v.x = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `v`
+   |         ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
index 660d9e85ef5..50d0c40fdf6 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.rs
@@ -10,7 +10,7 @@ fn main() {
     {
         let t: Tuple;
         t.0 = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+        //~^ ERROR E0381
         t.1 = 2;
         println!("{:?} {:?}", t.0, t.1);
     }
@@ -18,7 +18,7 @@ fn main() {
     {
         let u: Tpair;
         u.0 = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `u` [E0381]
+        //~^ ERROR E0381
         u.1 = 2;
         println!("{:?} {:?}", u.0, u.1);
     }
@@ -26,7 +26,7 @@ fn main() {
     {
         let v: Spair;
         v.x = S(1);
-        //~^ ERROR assign to part of possibly-uninitialized variable: `v` [E0381]
+        //~^ ERROR E0381
         v.y = 2;
         println!("{:?} {:?}", v.x, v.y);
     }
diff --git a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr
index 5f9c978c342..67a62583057 100644
--- a/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr
+++ b/src/test/ui/borrowck/issue-54499-field-mutation-of-never-init.stderr
@@ -1,20 +1,32 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-of-never-init.rs:12:9
    |
+LL |         let t: Tuple;
+   |             - binding declared here but left uninitialized
 LL |         t.0 = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `t`
+   |         ^^^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `u`
+error[E0381]: partially assigned binding `u` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-of-never-init.rs:20:9
    |
+LL |         let u: Tpair;
+   |             - binding declared here but left uninitialized
 LL |         u.0 = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `u`
+   |         ^^^^^^^^^^ `u` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `v`
+error[E0381]: partially assigned binding `v` isn't fully initialized
   --> $DIR/issue-54499-field-mutation-of-never-init.rs:28:9
    |
+LL |         let v: Spair;
+   |             - binding declared here but left uninitialized
 LL |         v.x = S(1);
-   |         ^^^^^^^^^^ use of possibly-uninitialized `v`
+   |         ^^^^^^^^^^ `v` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs
index f8efa8c891e..93ce34d2fe5 100644
--- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs
+++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.rs
@@ -1,7 +1,7 @@
 fn main() {
     let e: i32;
     match e {
-        //~^ ERROR use of possibly-uninitialized variable
+        //~^ ERROR E0381
         ref u if true => {}
         ref v if true => {
             let tx = 0;
diff --git a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
index 0eca447b551..f5d2eecfa91 100644
--- a/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
+++ b/src/test/ui/borrowck/issue-62107-match-arm-scopes.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `e`
+error[E0381]: used binding `e` isn't initialized
   --> $DIR/issue-62107-match-arm-scopes.rs:3:11
    |
+LL |     let e: i32;
+   |         - binding declared here but left uninitialized
 LL |     match e {
-   |           ^ use of possibly-uninitialized `e`
+   |           ^ `e` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-81899.stderr b/src/test/ui/borrowck/issue-81899.stderr
index 29288be4934..1acabefb893 100644
--- a/src/test/ui/borrowck/issue-81899.stderr
+++ b/src/test/ui/borrowck/issue-81899.stderr
@@ -8,7 +8,7 @@ LL |     panic!()
    |     ^^^^^^^^
    |     |
    |     the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:12:5
-   |     inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr
index fd38ad7bb0a..039575a8d79 100644
--- a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr
+++ b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr
@@ -1,21 +1,17 @@
 error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure
   --> $DIR/issue-87456-point-to-closure.rs:10:28
    |
-LL |       let val = String::new();
-   |           --- captured outer variable
+LL |     let val = String::new();
+   |         --- captured outer variable
 LL |
-LL |       take_mut(|| {
-   |  ______________-
-LL | |
-LL | |         let _foo: String = val;
-   | |                            ^^^
-   | |                            |
-   | |                            move occurs because `val` has type `String`, which does not implement the `Copy` trait
-   | |                            help: consider borrowing here: `&val`
-LL | |
-LL | |
-LL | |     })
-   | |_____- captured by this `FnMut` closure
+LL |     take_mut(|| {
+   |              -- captured by this `FnMut` closure
+LL |
+LL |         let _foo: String = val;
+   |                            ^^^
+   |                            |
+   |                            move occurs because `val` has type `String`, which does not implement the `Copy` trait
+   |                            help: consider borrowing here: `&val`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-88434-minimal-example.stderr b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
index daded200bd9..c7b5d773e82 100644
--- a/src/test/ui/borrowck/issue-88434-minimal-example.stderr
+++ b/src/test/ui/borrowck/issue-88434-minimal-example.stderr
@@ -8,7 +8,7 @@ LL |     panic!()
    |     ^^^^^^^^
    |     |
    |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:11:5
-   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:28]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
index ce6a37ee418..f4bb895e6b5 100644
--- a/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
+++ b/src/test/ui/borrowck/issue-88434-removal-index-should-be-less.stderr
@@ -8,7 +8,7 @@ LL |     panic!()
    |     ^^^^^^^^
    |     |
    |     the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:11:5
-   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
+   |     inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:34]>` at $SRC_DIR/std/src/panic.rs:LL:COL
    |
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/borrowck/mutability-errors.stderr b/src/test/ui/borrowck/mutability-errors.stderr
index edab22569b3..dd29ae492d6 100644
--- a/src/test/ui/borrowck/mutability-errors.stderr
+++ b/src/test/ui/borrowck/mutability-errors.stderr
@@ -119,146 +119,112 @@ LL |     &mut (*f()).0;
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/mutability-errors.rs:40:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-   | |         ^^^^^^^^ cannot assign
-LL | |         x.0 = 1;
-LL | |         &mut x;
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
 
 error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables
   --> $DIR/mutability-errors.rs:41:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-   | |         ^^^^^^^ cannot assign
-LL | |         &mut x;
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/mutability-errors.rs:42:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-LL | |         &mut x;
-   | |         ^^^^^^ cannot borrow as mutable
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables
   --> $DIR/mutability-errors.rs:43:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-LL | |         &mut x;
-LL | |         &mut x.0;
-   | |         ^^^^^^^^ cannot borrow as mutable
-LL | |     });
-   | |_____- in this closure
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
 
 error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
   --> $DIR/mutability-errors.rs:46:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-   | |         ^^^^^^^^ cannot assign
-LL | |         x.0 = 1;
-LL | |         &mut x;
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+   |         ^^^^^^^^ cannot assign
 
 error[E0594]: cannot assign to `x.0`, as `Fn` closures cannot mutate their captured variables
   --> $DIR/mutability-errors.rs:47:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-   | |         ^^^^^^^ cannot assign
-LL | |         &mut x;
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         x = (1,);
+LL |         x.0 = 1;
+   |         ^^^^^^^ cannot assign
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/mutability-errors.rs:48:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-LL | |         &mut x;
-   | |         ^^^^^^ cannot borrow as mutable
-LL | |         &mut x.0;
-LL | |     });
-   | |_____- in this closure
+LL |         &mut x;
+   |         ^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x.0` as mutable, as `Fn` closures cannot mutate their captured variables
   --> $DIR/mutability-errors.rs:49:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
+...
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         x = (1,);
-LL | |         x.0 = 1;
-LL | |         &mut x;
-LL | |         &mut x.0;
-   | |         ^^^^^^^^ cannot borrow as mutable
-LL | |     });
-   | |_____- in this closure
+LL |         &mut x.0;
+   |         ^^^^^^^^ cannot borrow as mutable
 
 error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
   --> $DIR/mutability-errors.rs:54:5
diff --git a/src/test/ui/borrowck/reassignment_immutable_fields.stderr b/src/test/ui/borrowck/reassignment_immutable_fields.stderr
index f09db378a75..e6b25573e70 100644
--- a/src/test/ui/borrowck/reassignment_immutable_fields.stderr
+++ b/src/test/ui/borrowck/reassignment_immutable_fields.stderr
@@ -1,14 +1,22 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields.rs:7:5
    |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
 LL |     x.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields.rs:15:5
    |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
 LL |     x.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
index 0eae2c71e4a..a3885b5f5ca 100644
--- a/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
+++ b/src/test/ui/borrowck/reassignment_immutable_fields_overlapping.stderr
@@ -1,8 +1,12 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields_overlapping.rs:12:5
    |
+LL |     let x: Foo;
+   |         - binding declared here but left uninitialized
 LL |     x.a = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0594]: cannot assign to `x.b`, as `x` is not declared as mutable
   --> $DIR/reassignment_immutable_fields_overlapping.rs:13:5
diff --git a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
index f55e1a27f47..49c81adad49 100644
--- a/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
+++ b/src/test/ui/borrowck/reassignment_immutable_fields_twice.stderr
@@ -7,11 +7,15 @@ LL |     x = (22, 44);
 LL |     x.0 = 1;
    |     ^^^^^^^ cannot assign
 
-error[E0381]: assign to part of possibly-uninitialized variable: `x`
+error[E0381]: partially assigned binding `x` isn't fully initialized
   --> $DIR/reassignment_immutable_fields_twice.rs:12:5
    |
+LL |     let x: (u32, u32);
+   |         - binding declared here but left uninitialized
 LL |     x.0 = 1;
-   |     ^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^ `x` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
index 3ea72262003..0c151b09707 100644
--- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
+++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr
@@ -1,17 +1,14 @@
 error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure
   --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9
    |
-LL |       let y = vec![format!("World")];
-   |           - captured outer variable
-LL |       call(|| {
-   |  __________-
-LL | |         y.into_iter();
-   | |         ^ ----------- `y` moved due to this method call
-   | |         |
-   | |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
-LL | |
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let y = vec![format!("World")];
+   |         - captured outer variable
+LL |     call(|| {
+   |          -- captured by this `Fn` closure
+LL |         y.into_iter();
+   |         ^ ----------- `y` moved due to this method call
+   |         |
+   |         move occurs because `y` has type `Vec<String>`, which does not implement the `Copy` trait
    |
 note: this function takes ownership of the receiver `self`, which moves `y`
   --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs
index 0f288ffa95a..69cf920de94 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs
+++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.rs
@@ -6,14 +6,14 @@
 fn test1() {
     let x: !;
     let c1 = || match x { };
-    //~^ ERROR: use of possibly-uninitialized variable: `x`
+    //~^ ERROR E0381
 }
 
 // Should fake read the discriminant and throw an error
 fn test2() {
     let x: !;
     let c2 = || match x { _ => () };
-    //~^ ERROR: borrow of possibly-uninitialized variable: `x`
+    //~^ ERROR E0381
 }
 
 // Testing single variant patterns
@@ -25,7 +25,7 @@ enum SingleVariant {
 fn test3() {
     let variant: !;
     let c = || {
-    //~^ ERROR: borrow of possibly-uninitialized variable: `variant`
+    //~^ ERROR E0381
         match variant {
             SingleVariant::Points(_) => {}
         }
@@ -36,8 +36,7 @@ fn test3() {
 // Should fake read the discriminant and throw an error
 fn test4() {
     let variant: !;
-    let c = || {
-    //~^ ERROR: borrow of possibly-uninitialized variable: `variant`
+    let c = || { //~ ERROR E0381
         match variant {
             SingleVariant::Points(a) => {
                 println!("{:?}", a);
@@ -52,11 +51,9 @@ fn test5() {
     let g: !;
 
     let a = || {
-        match g { };
-        //~^ ERROR: use of possibly-uninitialized variable: `g`
+        match g { }; //~ ERROR E0381
         let c = ||  {
-            match t { };
-            //~^ ERROR: use of possibly-uninitialized variable: `t`
+            match t { }; //~ ERROR E0381
         };
 
         c();
@@ -68,7 +65,7 @@ fn test5() {
 fn test6() {
     let x: u8;
     let c1 = || match x { };
-    //~^ ERROR: use of possibly-uninitialized variable: `x`
+    //~^ ERROR E0381
     //~| ERROR: non-exhaustive patterns: type `u8` is non-empty
 }
 
diff --git a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
index e55fb7ce4bb..fea5441ec67 100644
--- a/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/match/pattern-matching-should-fail.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: type `u8` is non-empty
-  --> $DIR/pattern-matching-should-fail.rs:70:23
+  --> $DIR/pattern-matching-should-fail.rs:67:23
    |
 LL |     let c1 = || match x { };
    |                       ^
@@ -12,55 +12,70 @@ LL +         _ => todo!(),
 LL ~     };
    |
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:8:23
    |
+LL |     let x: !;
+   |         - binding declared here but left uninitialized
 LL |     let c1 = || match x { };
-   |                       ^ use of possibly-uninitialized `x`
+   |                       ^ `x` used here but it isn't initialized
 
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:15:14
    |
+LL |     let x: !;
+   |         - binding declared here but left uninitialized
 LL |     let c2 = || match x { _ => () };
    |              ^^       - borrow occurs due to use in closure
    |              |
-   |              use of possibly-uninitialized `x`
+   |              `x` used here but it isn't initialized
 
-error[E0381]: borrow of possibly-uninitialized variable: `variant`
+error[E0381]: used binding `variant` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:27:13
    |
+LL |     let variant: !;
+   |         ------- binding declared here but left uninitialized
 LL |     let c = || {
-   |             ^^ use of possibly-uninitialized `variant`
+   |             ^^ `variant` used here but it isn't initialized
 LL |
 LL |         match variant {
    |               ------- borrow occurs due to use in closure
 
-error[E0381]: borrow of possibly-uninitialized variable: `variant`
+error[E0381]: used binding `variant` isn't initialized
   --> $DIR/pattern-matching-should-fail.rs:39:13
    |
+LL |     let variant: !;
+   |         ------- binding declared here but left uninitialized
 LL |     let c = || {
-   |             ^^ use of possibly-uninitialized `variant`
-LL |
+   |             ^^ `variant` used here but it isn't initialized
 LL |         match variant {
    |               ------- borrow occurs due to use in closure
 
-error[E0381]: use of possibly-uninitialized variable: `g`
-  --> $DIR/pattern-matching-should-fail.rs:55:15
+error[E0381]: used binding `g` isn't initialized
+  --> $DIR/pattern-matching-should-fail.rs:54:15
    |
+LL |     let g: !;
+   |         - binding declared here but left uninitialized
+...
 LL |         match g { };
-   |               ^ use of possibly-uninitialized `g`
+   |               ^ `g` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `t`
-  --> $DIR/pattern-matching-should-fail.rs:58:19
+error[E0381]: used binding `t` isn't initialized
+  --> $DIR/pattern-matching-should-fail.rs:56:19
    |
+LL |     let t: !;
+   |         - binding declared here but left uninitialized
+...
 LL |             match t { };
-   |                   ^ use of possibly-uninitialized `t`
+   |                   ^ `t` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `x`
-  --> $DIR/pattern-matching-should-fail.rs:70:23
+error[E0381]: used binding `x` isn't initialized
+  --> $DIR/pattern-matching-should-fail.rs:67:23
    |
+LL |     let x: u8;
+   |         - binding declared here but left uninitialized
 LL |     let c1 = || match x { };
-   |                       ^ use of possibly-uninitialized `x`
+   |                       ^ `x` used here but it isn't initialized
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
index a3c43690f1f..d7104bafeb1 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
@@ -2,7 +2,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos
   --> $DIR/auto_traits.rs:22:19
    |
 LL |     thread::spawn(move || unsafe {
-   |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
+   |                   ^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
 ...
 LL |         *fptr.0 = 20;
    |         ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
@@ -26,7 +26,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos
   --> $DIR/auto_traits.rs:42:19
    |
 LL |     thread::spawn(move || unsafe {
-   |                   ^^^^^^^^^^^^^^
+   |                   ^^^^^^^
    |                   |
    |                   in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send`
    |                   in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
index 675ba0313d7..c611daf13fd 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
@@ -2,14 +2,10 @@ warning: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/closure-body-macro-fragment.rs:16:17
    |
 LL |           let f = || $body;
-   |  _________________^
-LL | |
-LL | |         f();
-LL | |     }};
-   | |     - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
-LL | |     ($body:block) => {{
-LL | |         m!(@ $body);
-   | |__________________^
+   |                   ^^
+...
+LL |       }};
+   |       - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
 ...
 LL | /     m!({
 LL | |
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
index 5046a4bcbb4..2d0c56aad8d 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
@@ -2,9 +2,7 @@ error: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/macro.rs:19:13
    |
 LL |     let _ = || dbg!(a.0);
-   |             ^^^^^^^^---^
-   |                     |
-   |                     in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
+   |             ^^      --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
 ...
 LL | }
    | - in Rust 2018, `a` is dropped here, but in Rust 2021, only `a.0` will be dropped here as part of the closure
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
index 3589a6150d0..12760cc7256 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/migrations_rustfix.stderr
@@ -26,9 +26,7 @@ error: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/migrations_rustfix.rs:33:13
    |
 LL |     let c = || t.0;
-   |             ^^^---
-   |                |
-   |                in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
+   |             ^^ --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
 ...
 LL | }
    | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
index fa6082cbb59..96d5c936fa5 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
@@ -92,7 +92,7 @@ error: changes to closure capture in Rust 2021 will affect which traits the clos
   --> $DIR/multi_diagnostics.rs:133:19
    |
 LL |     thread::spawn(move || unsafe {
-   |                   ^^^^^^^^^^^^^^
+   |                   ^^^^^^^
    |                   |
    |                   in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send`
    |                   in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync`
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
index fa1f83c3782..0d9f09ee354 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
@@ -199,9 +199,7 @@ error: changes to closure capture in Rust 2021 will affect drop order
   --> $DIR/significant_drop.rs:201:18
    |
 LL |         let _c = || tup.0;
-   |                  ^^^-----
-   |                     |
-   |                     in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+   |                  ^^ ----- in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
 ...
 LL | }
    | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr
index cbc4e2e5231..1086cfa2947 100644
--- a/src/test/ui/closures/closure-move-sync.stderr
+++ b/src/test/ui/closures/closure-move-sync.stderr
@@ -9,12 +9,8 @@ LL |     let t = thread::spawn(|| {
 note: required because it's used within this closure
   --> $DIR/closure-move-sync.rs:6:27
    |
-LL |       let t = thread::spawn(|| {
-   |  ___________________________^
-LL | |         recv.recv().unwrap();
-LL | |
-LL | |     });
-   | |_____^
+LL |     let t = thread::spawn(|| {
+   |                           ^^
 note: required by a bound in `spawn`
   --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
@@ -33,7 +29,7 @@ note: required because it's used within this closure
   --> $DIR/closure-move-sync.rs:18:19
    |
 LL |     thread::spawn(|| tx.send(()).unwrap());
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^
+   |                   ^^
 note: required by a bound in `spawn`
   --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
diff --git a/src/test/ui/closures/closure-no-fn-1.stderr b/src/test/ui/closures/closure-no-fn-1.stderr
index 2b53802fea7..eab7482e6c4 100644
--- a/src/test/ui/closures/closure-no-fn-1.stderr
+++ b/src/test/ui/closures/closure-no-fn-1.stderr
@@ -7,7 +7,7 @@ LL |     let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
    |              expected due to this
    |
    = note: expected fn pointer `fn(u8) -> u8`
-                 found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]`
+                 found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:36]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-no-fn-1.rs:6:39
    |
diff --git a/src/test/ui/closures/closure-no-fn-2.stderr b/src/test/ui/closures/closure-no-fn-2.stderr
index ed9f87a2c94..e1f0143abfe 100644
--- a/src/test/ui/closures/closure-no-fn-2.stderr
+++ b/src/test/ui/closures/closure-no-fn-2.stderr
@@ -7,7 +7,7 @@ LL |     let bar: fn() -> u8 = || { b };
    |              expected due to this
    |
    = note: expected fn pointer `fn() -> u8`
-                 found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]`
+                 found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:29]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-no-fn-2.rs:6:32
    |
diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr
index 95683a786ba..6009389b1bb 100644
--- a/src/test/ui/closures/closure-no-fn-3.stderr
+++ b/src/test/ui/closures/closure-no-fn-3.stderr
@@ -1,4 +1,4 @@
-error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37]` as `fn() -> u8`
+error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:28: 6:30]` as `fn() -> u8`
   --> $DIR/closure-no-fn-3.rs:6:27
    |
 LL |     let baz: fn() -> u8 = (|| { b }) as fn() -> u8;
diff --git a/src/test/ui/closures/closure-no-fn-4.stderr b/src/test/ui/closures/closure-no-fn-4.stderr
index 89798ec5dd3..d1b7048841a 100644
--- a/src/test/ui/closures/closure-no-fn-4.stderr
+++ b/src/test/ui/closures/closure-no-fn-4.stderr
@@ -12,7 +12,7 @@ LL | |     };
    | |_____- `match` arms have incompatible types
    |
    = note: expected fn pointer `fn(usize) -> usize`
-                 found closure `[closure@$DIR/closure-no-fn-4.rs:5:18: 5:27]`
+                 found closure `[closure@$DIR/closure-no-fn-4.rs:5:18: 5:21]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-no-fn-4.rs:5:26
    |
diff --git a/src/test/ui/closures/closure-no-fn-5.stderr b/src/test/ui/closures/closure-no-fn-5.stderr
index 1f373f10489..a33b847ea92 100644
--- a/src/test/ui/closures/closure-no-fn-5.stderr
+++ b/src/test/ui/closures/closure-no-fn-5.stderr
@@ -7,7 +7,7 @@ LL |     let bar: fn() -> u8 = || { a; b; c; d; e };
    |              expected due to this
    |
    = note: expected fn pointer `fn() -> u8`
-                 found closure `[closure@$DIR/closure-no-fn-5.rs:10:27: 10:47]`
+                 found closure `[closure@$DIR/closure-no-fn-5.rs:10:27: 10:29]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-no-fn-5.rs:10:32
    |
diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr
index 534828ab348..9dfff8499fd 100644
--- a/src/test/ui/closures/closure-reform-bad.stderr
+++ b/src/test/ui/closures/closure-reform-bad.stderr
@@ -2,14 +2,14 @@ error[E0308]: mismatched types
   --> $DIR/closure-reform-bad.rs:11:15
    |
 LL |     let f = |s: &str| println!("{}{}", s, string);
-   |             ------------------------------------- the found closure
+   |             --------- the found closure
 LL |     call_bare(f)
    |     --------- ^ expected fn pointer, found closure
    |     |
    |     arguments to this function are incorrect
    |
    = note: expected fn pointer `for<'r> fn(&'r str)`
-                 found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]`
+                 found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:22]`
 note: closures can only be coerced to `fn` types if they do not capture any variables
   --> $DIR/closure-reform-bad.rs:10:43
    |
diff --git a/src/test/ui/closures/closure-wrong-kind.stderr b/src/test/ui/closures/closure-wrong-kind.stderr
index 65026128ae6..35caf71a5e8 100644
--- a/src/test/ui/closures/closure-wrong-kind.stderr
+++ b/src/test/ui/closures/closure-wrong-kind.stderr
@@ -2,9 +2,8 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur
   --> $DIR/closure-wrong-kind.rs:10:19
    |
 LL |     let closure = |_| foo(x);
-   |                   ^^^^^^^^-^
-   |                   |       |
-   |                   |       closure is `FnOnce` because it moves the variable `x` out of its environment
+   |                   ^^^     - closure is `FnOnce` because it moves the variable `x` out of its environment
+   |                   |
    |                   this closure implements `FnOnce`, not `Fn`
 LL |     bar(closure);
    |     --- the requirement to implement `Fn` derives from here
diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
index e25b33bbcdb..ca8a43328a9 100644
--- a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
+++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr
@@ -12,7 +12,7 @@ LL | |     };
    | |_____- `match` arms have incompatible types
    |
    = note: expected fn item `fn(i32, i32) -> i32 {add}`
-              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:22]`
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/closure_cap_coerce_many_fail.rs:18:16
@@ -23,15 +23,15 @@ LL | |         "+" => |a, b| (a + b) as i32,
    | |                ---------------------
    | |                |
    | |                the expected closure
-   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:22]`
 LL | |         "-" => |a, b| (a - b + cap) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]`
-              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:22]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:22]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
@@ -44,15 +44,15 @@ LL | |         "+" => |a, b| (a + b + cap) as i32,
    | |                ---------------------------
    | |                |
    | |                the expected closure
-   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:22]`
 LL | |         "-" => |a, b| (a - b) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]`
-              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:22]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:22]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
@@ -65,15 +65,15 @@ LL | |         "+" => |a, b| (a + b + cap) as i32,
    | |                ---------------------------
    | |                |
    | |                the expected closure
-   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
+   | |                this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:22]`
 LL | |         "-" => |a, b| (a - b + cap) as i32,
    | |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure
 LL | |         _ => unimplemented!(),
 LL | |     };
    | |_____- `match` arms have incompatible types
    |
-   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]`
-              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]`
+   = note: expected closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:22]`
+              found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:22]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
diff --git a/src/test/ui/closures/print/closure-print-generic-1.stderr b/src/test/ui/closures/print/closure-print-generic-1.stderr
index 43a12f675f5..b21734f0257 100644
--- a/src/test/ui/closures/print/closure-print-generic-1.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-1.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `c`
   --> $DIR/closure-print-generic-1.rs:17:5
    |
 LL |     let c = to_fn_once(move || {
-   |         - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 14:6]`, which does not implement the `Copy` trait
+   |         - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 12:31]`, which does not implement the `Copy` trait
 ...
 LL |     c();
    |     --- `c` moved due to this call
diff --git a/src/test/ui/closures/print/closure-print-generic-2.stderr b/src/test/ui/closures/print/closure-print-generic-2.stderr
index 9c75d5a9023..e53277a9396 100644
--- a/src/test/ui/closures/print/closure-print-generic-2.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-2.stderr
@@ -2,14 +2,14 @@ error[E0308]: mismatched types
   --> $DIR/closure-print-generic-2.rs:6:22
    |
 LL |         let c = || println!("{} {}", t, x);
-   |                 -------------------------- the found closure
+   |                 -- the found closure
 LL |         let c1: () = c;
    |                 --   ^ expected `()`, found closure
    |                 |
    |                 expected due to this
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:43]`
+                found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:19]`
 help: use parentheses to call this closure
    |
 LL |         let c1: () = c();
diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
index aee782a1c5b..ff89dd34034 100644
--- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/closure-print-generic-trim-off-verbose-2.rs:9:23
    |
 LL |         let c = || println!("{} {}", t, x);
-   |                 -------------------------- the found closure
+   |                 -- the found closure
 LL |         let c1 : () = c;
    |                  --   ^ expected `()`, found closure
    |                  |
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
index 6a994ce718e..5bbf84f963d 100644
--- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/closure-print-generic-verbose-2.rs:9:23
    |
 LL |         let c = || println!("{} {}", t, x);
-   |                 -------------------------- the found closure
+   |                 -- the found closure
 LL |         let c1 : () = c;
    |                  --   ^ expected `()`, found closure
    |                  |
diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
index f0109f22a2b..9d614e610ad 100644
--- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
+++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr
@@ -32,7 +32,7 @@ LL |     let _ = box { |x| (x as u8) }: Box<dyn Fn(i32) -> _>;
    |             ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
-              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>`
+              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:22]>`
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:14:13
@@ -86,7 +86,7 @@ LL |     let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _;
    |             ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected reference `&dyn Fn(i32) -> u8`
-              found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:29]`
+              found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:19]`
 
 error[E0308]: mismatched types
   --> $DIR/coerce-expect-unsized-ascribed.rs:22:13
@@ -122,7 +122,7 @@ LL |     let _ = Box::new(|x| (x as u8)): Box<dyn Fn(i32) -> _>;
    |             ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure
    |
    = note: expected struct `Box<dyn Fn(i32) -> u8>`
-              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>`
+              found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:25]>`
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr
index 8e7d4589e61..b1ee0795b2e 100644
--- a/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr
+++ b/src/test/ui/coherence/coherence-projection-conflict-orphan.stderr
@@ -8,7 +8,6 @@ LL | impl<A:Iterator> Foo<A::Item> for A { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
    |
    = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions
-   = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `i32` in future versions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs
new file mode 100644
index 00000000000..5b11c78ab26
--- /dev/null
+++ b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.rs
@@ -0,0 +1,19 @@
+struct S;
+
+impl From<()> for S {
+    fn from(x: ()) -> Self {
+        S
+    }
+}
+
+impl<I> From<I> for S
+//~^ ERROR conflicting implementations of trait
+where
+    I: Iterator<Item = ()>,
+{
+    fn from(x: I) -> Self {
+        S
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr
new file mode 100644
index 00000000000..038a0199a8f
--- /dev/null
+++ b/src/test/ui/coherence/inter-crate-ambiguity-causes-notes.stderr
@@ -0,0 +1,14 @@
+error[E0119]: conflicting implementations of trait `std::convert::From<()>` for type `S`
+  --> $DIR/inter-crate-ambiguity-causes-notes.rs:9:1
+   |
+LL | impl From<()> for S {
+   | ------------------- first implementation here
+...
+LL | impl<I> From<I> for S
+   | ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `S`
+   |
+   = note: upstream crates may add a new impl of trait `std::iter::Iterator` for type `()` in future versions
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr
index a6d4e80a50c..1c9a6847ceb 100644
--- a/src/test/ui/confuse-field-and-method/issue-18343.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc
   --> $DIR/issue-18343.rs:7:7
    |
 LL | struct Obj<F> where F: FnMut() -> u32 {
-   |        --- method `closure` not found for this struct
+   | ------------- method `closure` not found for this struct
 ...
 LL |     o.closure();
    |       ^^^^^^^ field, not a method
diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr
index 795d0e286b3..440fbb27c00 100644
--- a/src/test/ui/confuse-field-and-method/issue-2392.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc
   --> $DIR/issue-2392.rs:36:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `closure` not found for this struct
+   | ------------- method `closure` not found for this struct
 ...
 LL |     o_closure.closure();
    |               ^^^^^^^ field, not a method
@@ -16,7 +16,7 @@ error[E0599]: no method named `not_closure` found for struct `Obj` in the curren
   --> $DIR/issue-2392.rs:38:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `not_closure` not found for this struct
+   | ------------- method `not_closure` not found for this struct
 ...
 LL |     o_closure.not_closure();
    |               ^^^^^^^^^^^-- help: remove the arguments
@@ -27,7 +27,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc
   --> $DIR/issue-2392.rs:42:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `closure` not found for this struct
+   | ------------- method `closure` not found for this struct
 ...
 LL |     o_func.closure();
    |            ^^^^^^^ field, not a method
@@ -41,7 +41,7 @@ error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the
   --> $DIR/issue-2392.rs:45:14
    |
 LL | struct BoxedObj {
-   |        -------- method `boxed_closure` not found for this struct
+   | --------------- method `boxed_closure` not found for this struct
 ...
 LL |     boxed_fn.boxed_closure();
    |              ^^^^^^^^^^^^^ field, not a method
@@ -55,7 +55,7 @@ error[E0599]: no method named `boxed_closure` found for struct `BoxedObj` in the
   --> $DIR/issue-2392.rs:48:19
    |
 LL | struct BoxedObj {
-   |        -------- method `boxed_closure` not found for this struct
+   | --------------- method `boxed_closure` not found for this struct
 ...
 LL |     boxed_closure.boxed_closure();
    |                   ^^^^^^^^^^^^^ field, not a method
@@ -69,7 +69,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc
   --> $DIR/issue-2392.rs:53:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `closure` not found for this struct
+   | ------------- method `closure` not found for this struct
 ...
 LL |     w.wrap.closure();
    |            ^^^^^^^ field, not a method
@@ -83,7 +83,7 @@ error[E0599]: no method named `not_closure` found for struct `Obj` in the curren
   --> $DIR/issue-2392.rs:55:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `not_closure` not found for this struct
+   | ------------- method `not_closure` not found for this struct
 ...
 LL |     w.wrap.not_closure();
    |            ^^^^^^^^^^^-- help: remove the arguments
@@ -94,7 +94,7 @@ error[E0599]: no method named `closure` found for struct `Obj` in the current sc
   --> $DIR/issue-2392.rs:58:24
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
-   |        --- method `closure` not found for this struct
+   | ------------- method `closure` not found for this struct
 ...
 LL |     check_expression().closure();
    |                        ^^^^^^^ field, not a method
@@ -108,7 +108,7 @@ error[E0599]: no method named `f1` found for struct `FuncContainer` in the curre
   --> $DIR/issue-2392.rs:64:31
    |
 LL | struct FuncContainer {
-   |        ------------- method `f1` not found for this struct
+   | -------------------- method `f1` not found for this struct
 ...
 LL |             (*self.container).f1(1);
    |                               ^^ field, not a method
@@ -122,7 +122,7 @@ error[E0599]: no method named `f2` found for struct `FuncContainer` in the curre
   --> $DIR/issue-2392.rs:65:31
    |
 LL | struct FuncContainer {
-   |        ------------- method `f2` not found for this struct
+   | -------------------- method `f2` not found for this struct
 ...
 LL |             (*self.container).f2(1);
    |                               ^^ field, not a method
@@ -136,7 +136,7 @@ error[E0599]: no method named `f3` found for struct `FuncContainer` in the curre
   --> $DIR/issue-2392.rs:66:31
    |
 LL | struct FuncContainer {
-   |        ------------- method `f3` not found for this struct
+   | -------------------- method `f3` not found for this struct
 ...
 LL |             (*self.container).f3(1);
    |                               ^^ field, not a method
diff --git a/src/test/ui/confuse-field-and-method/issue-32128.stderr b/src/test/ui/confuse-field-and-method/issue-32128.stderr
index cad2697b52e..4b96bce8d2e 100644
--- a/src/test/ui/confuse-field-and-method/issue-32128.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-32128.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `example` found for struct `Example` in the curren
   --> $DIR/issue-32128.rs:12:10
    |
 LL | struct Example {
-   |        ------- method `example` not found for this struct
+   | -------------- method `example` not found for this struct
 ...
 LL |     demo.example(1);
    |          ^^^^^^^ field, not a method
diff --git a/src/test/ui/confuse-field-and-method/issue-33784.stderr b/src/test/ui/confuse-field-and-method/issue-33784.stderr
index 7c2e6b01533..34debb68317 100644
--- a/src/test/ui/confuse-field-and-method/issue-33784.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-33784.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
+error[E0599]: no method named `closure` found for reference `&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
   --> $DIR/issue-33784.rs:27:7
    |
 LL |     p.closure();
@@ -9,7 +9,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (p.closure)();
    |     +         +
 
-error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:48]>` in the current scope
+error[E0599]: no method named `fn_ptr` found for reference `&&Obj<[closure@$DIR/issue-33784.rs:25:43: 25:45]>` in the current scope
   --> $DIR/issue-33784.rs:29:7
    |
 LL |     q.fn_ptr();
diff --git a/src/test/ui/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr
index 9e2f245597a..783378f8db5 100644
--- a/src/test/ui/confuse-field-and-method/private-field.stderr
+++ b/src/test/ui/confuse-field-and-method/private-field.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `dog_age` found for struct `Dog` in the current sc
   --> $DIR/private-field.rs:16:23
    |
 LL |     pub struct Dog {
-   |                --- method `dog_age` not found for this struct
+   |     -------------- method `dog_age` not found for this struct
 ...
 LL |     let dog_age = dog.dog_age();
    |                       ^^^^^^^ private field, not a method
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs b/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs
index bb5a2f1766f..e64adacac9f 100644
--- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs
+++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs
@@ -1,6 +1,5 @@
 struct X<const N: usize = {
-    let s: &'static str; s.len()
-    //~^ ERROR borrow of possibly-uninitialized variable
+    let s: &'static str; s.len() //~ ERROR E0381
 }>;
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
index 6c25019b0ce..c62f1d1d230 100644
--- a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
+++ b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `s`
+error[E0381]: used binding `s` isn't initialized
   --> $DIR/const-generic-default-wont-borrowck.rs:2:26
    |
 LL |     let s: &'static str; s.len()
-   |                          ^^^^^^^ use of possibly-uninitialized `*s`
+   |         -                ^^^^^^^ `*s` used here but it isn't initialized
+   |         |
+   |         binding declared here but left uninitialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/float-generic.adt_const_params.stderr b/src/test/ui/const-generics/float-generic.adt_const_params.stderr
new file mode 100644
index 00000000000..fef5ef0d1fa
--- /dev/null
+++ b/src/test/ui/const-generics/float-generic.adt_const_params.stderr
@@ -0,0 +1,11 @@
+error[E0741]: `f32` is forbidden as the type of a const generic parameter
+  --> $DIR/float-generic.rs:5:17
+   |
+LL | fn foo<const F: f32>() {}
+   |                 ^^^
+   |
+   = note: floats do not derive `Eq` or `Ord`, which are required for const parameters
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/float-generic.rs b/src/test/ui/const-generics/float-generic.rs
new file mode 100644
index 00000000000..b72059b5b1c
--- /dev/null
+++ b/src/test/ui/const-generics/float-generic.rs
@@ -0,0 +1,12 @@
+// revisions: simple adt_const_params
+#![cfg_attr(adt_const_params, feature(adt_const_params))]
+#![cfg_attr(adt_const_params, allow(incomplete_features))]
+
+fn foo<const F: f32>() {}
+//~^ ERROR `f32` is forbidden as the type of a const generic parameter
+
+const C: f32 = 1.0;
+
+fn main() {
+    foo::<C>();
+}
diff --git a/src/test/ui/const-generics/float-generic.simple.stderr b/src/test/ui/const-generics/float-generic.simple.stderr
new file mode 100644
index 00000000000..89ca36b0f63
--- /dev/null
+++ b/src/test/ui/const-generics/float-generic.simple.stderr
@@ -0,0 +1,11 @@
+error: `f32` is forbidden as the type of a const generic parameter
+  --> $DIR/float-generic.rs:5:17
+   |
+LL | fn foo<const F: f32>() {}
+   |                 ^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+   = help: more complex types are supported with `#![feature(adt_const_params)]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
index 576d037f339..77a3b77ad42 100644
--- a/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-69654.stderr
@@ -8,7 +8,7 @@ error[E0599]: the function or associated item `foo` exists for struct `Foo<{_: u
   --> $DIR/issue-69654.rs:17:10
    |
 LL | struct Foo<const N: usize> {}
-   |        --- function or associated item `foo` not found for this struct
+   | -------------------------- function or associated item `foo` not found for this struct
 ...
 LL |     Foo::foo();
    |          ^^^ function or associated item cannot be called on `Foo<{_: usize}>` due to unsatisfied trait bounds
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr
index 7bfc09387b8..1b502642eb7 100644
--- a/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-80742.stderr
@@ -16,7 +16,7 @@ error[E0599]: the function or associated item `new` exists for struct `Inline<dy
   --> $DIR/issue-80742.rs:30:36
    |
 LL | struct Inline<T>
-   |        ------ function or associated item `new` not found for this struct
+   | ---------------- function or associated item `new` not found for this struct
 ...
 LL |     let dst = Inline::<dyn Debug>::new(0);
    |                                    ^^^ function or associated item cannot be called on `Inline<dyn Debug>` due to unsatisfied trait bounds
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
new file mode 100644
index 00000000000..67e30232e2f
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+#![feature(adt_const_params, generic_const_exprs)]
+//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+pub struct Changes<const CHANGES: &'static [&'static str]>
+where
+    [(); CHANGES.len()]:,
+{
+    changes: [usize; CHANGES.len()],
+}
+
+impl<const CHANGES: &'static [&'static str]> Changes<CHANGES>
+where
+    [(); CHANGES.len()]:,
+{
+    pub const fn new() -> Self {
+        Self {
+            changes: [0; CHANGES.len()],
+        }
+    }
+}
+
+pub fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr
new file mode 100644
index 00000000000..b5b2b0e405a
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr
@@ -0,0 +1,19 @@
+warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-1.rs:3:12
+   |
+LL | #![feature(adt_const_params, generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-1.rs:3:30
+   |
+LL | #![feature(adt_const_params, generic_const_exprs)]
+   |                              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs
new file mode 100644
index 00000000000..00568a08944
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs
@@ -0,0 +1,23 @@
+// check-pass
+
+#![feature(adt_const_params, generic_const_exprs)]
+//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+//~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+pub struct Changes<const CHANGES: &'static [&'static str]>
+where
+    [(); CHANGES.len()]:,
+{
+    changes: [usize; CHANGES.len()],
+}
+
+impl<const CHANGES: &'static [&'static str]> Changes<CHANGES>
+where
+    [(); CHANGES.len()]:,
+{
+    pub fn combine(&mut self, other: &Self) {
+        for _change in &self.changes {}
+    }
+}
+
+pub fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr
new file mode 100644
index 00000000000..5dfbd87ccd4
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr
@@ -0,0 +1,19 @@
+warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-2.rs:3:12
+   |
+LL | #![feature(adt_const_params, generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-97047-ice-2.rs:3:30
+   |
+LL | #![feature(adt_const_params, generic_const_exprs)]
+   |                              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
index ab53d6cf09a..b1b359619dc 100644
--- a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
+++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr
@@ -16,7 +16,7 @@ error[E0599]: no method named `f` found for struct `S` in the current scope
   --> $DIR/invalid-const-arg-for-type-param.rs:9:7
    |
 LL | struct S;
-   |        - method `f` not found for this struct
+   | -------- method `f` not found for this struct
 ...
 LL |     S.f::<0>();
    |       ^ method not found in `S`
diff --git a/src/test/ui/const-generics/issue-70408.rs b/src/test/ui/const-generics/issue-70408.rs
new file mode 100644
index 00000000000..f7557cb492c
--- /dev/null
+++ b/src/test/ui/const-generics/issue-70408.rs
@@ -0,0 +1,13 @@
+// build-pass
+
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
+    BYTES
+}
+
+pub fn main() {
+    assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
+    assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
+}
diff --git a/src/test/ui/const-generics/issue-80471.rs b/src/test/ui/const-generics/issue-80471.rs
new file mode 100644
index 00000000000..d0af8a5eaa8
--- /dev/null
+++ b/src/test/ui/const-generics/issue-80471.rs
@@ -0,0 +1,13 @@
+#![feature(adt_const_params)]
+//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+#[derive(PartialEq, Eq)]
+enum Nat {
+    Z,
+    S(Box<Nat>),
+}
+
+fn foo<const N: Nat>() {}
+//~^ ERROR `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-80471.stderr b/src/test/ui/const-generics/issue-80471.stderr
new file mode 100644
index 00000000000..dbcc0b7b600
--- /dev/null
+++ b/src/test/ui/const-generics/issue-80471.stderr
@@ -0,0 +1,18 @@
+warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/issue-80471.rs:1:12
+   |
+LL | #![feature(adt_const_params)]
+   |            ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information
+
+error[E0741]: `Box<Nat>` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
+  --> $DIR/issue-80471.rs:10:17
+   |
+LL | fn foo<const N: Nat>() {}
+   |                 ^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-ptr/allowed_slices.rs b/src/test/ui/const-ptr/allowed_slices.rs
index 645283d8fe5..3f19cd4d804 100644
--- a/src/test/ui/const-ptr/allowed_slices.rs
+++ b/src/test/ui/const-ptr/allowed_slices.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(
-    const_slice_from_raw_parts,
     slice_from_ptr_range,
     const_slice_from_ptr_range,
     pointer_byte_offsets,
diff --git a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr
index ce281797e56..c2d22ca4917 100644
--- a/src/test/ui/const-ptr/forbidden_slices.32bit.stderr
+++ b/src/test/ui/const-ptr/forbidden_slices.32bit.stderr
@@ -4,13 +4,13 @@ error[E0080]: could not evaluate static initializer
 LL |         &*ptr::slice_from_raw_parts(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
    |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:19:34
+  ::: $DIR/forbidden_slices.rs:18:34
    |
 LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -18,13 +18,13 @@ error[E0080]: could not evaluate static initializer
 LL |         &*ptr::slice_from_raw_parts(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
    |         inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:20:33
+  ::: $DIR/forbidden_slices.rs:19:33
    |
 LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -35,13 +35,13 @@ LL |         &*ptr::slice_from_raw_parts(data, len)
    |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:23:34
+  ::: $DIR/forbidden_slices.rs:22:34
    |
 LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:26:1
+  --> $DIR/forbidden_slices.rs:25:1
    |
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
@@ -52,7 +52,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:28:1
+  --> $DIR/forbidden_slices.rs:27:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -63,7 +63,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:30:1
+  --> $DIR/forbidden_slices.rs:29:1
    |
 LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
@@ -74,7 +74,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:33:1
+  --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -93,10 +93,10 @@ LL |         &*ptr::slice_from_raw_parts(data, len)
    |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |         inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:44:5
+  ::: $DIR/forbidden_slices.rs:43:5
    |
 LL |     from_raw_parts(ptr, 1)
-   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -104,7 +104,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  out-of-bounds offset_from: null pointer is not a valid pointer
+   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -112,10 +112,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:47:34
+  ::: $DIR/forbidden_slices.rs:46:34
    |
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -131,10 +131,10 @@ LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:48:33
+  ::: $DIR/forbidden_slices.rs:47:33
    |
 LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33
    |
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -144,19 +144,19 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 ...
 LL |         unsafe { self.offset(count as isize) }
    |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:51:25
+  ::: $DIR/forbidden_slices.rs:50:25
    |
 LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:53:1
+  --> $DIR/forbidden_slices.rs:52:1
    |
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
@@ -167,7 +167,7 @@ LL | pub static R4: &[u8] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:58:1
+  --> $DIR/forbidden_slices.rs:57:1
    |
 LL | pub static R5: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -178,7 +178,7 @@ LL | pub static R5: &[u8] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:63:1
+  --> $DIR/forbidden_slices.rs:62:1
    |
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
@@ -189,7 +189,7 @@ LL | pub static R6: &[bool] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:68:1
+  --> $DIR/forbidden_slices.rs:67:1
    |
 LL | pub static R7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -205,16 +205,16 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 ...
 LL |         unsafe { self.offset(count as isize) }
    |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:75:25
+  ::: $DIR/forbidden_slices.rs:74:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -230,10 +230,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:80:34
+  ::: $DIR/forbidden_slices.rs:79:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -249,10 +249,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:81:35
+  ::: $DIR/forbidden_slices.rs:80:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35
 
 error: aborting due to 18 previous errors
 
diff --git a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr
index 6c484f7c95b..da9df1c63a4 100644
--- a/src/test/ui/const-ptr/forbidden_slices.64bit.stderr
+++ b/src/test/ui/const-ptr/forbidden_slices.64bit.stderr
@@ -4,13 +4,13 @@ error[E0080]: could not evaluate static initializer
 LL |         &*ptr::slice_from_raw_parts(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
    |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:19:34
+  ::: $DIR/forbidden_slices.rs:18:34
    |
 LL | pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:19:34
+   |                                  ------------------------------ inside `S0` at $DIR/forbidden_slices.rs:18:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -18,13 +18,13 @@ error[E0080]: could not evaluate static initializer
 LL |         &*ptr::slice_from_raw_parts(data, len)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |         |
-   |         dereferencing pointer failed: null pointer is not a valid pointer
+   |         dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance)
    |         inside `std::slice::from_raw_parts::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:20:33
+  ::: $DIR/forbidden_slices.rs:19:33
    |
 LL | pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
-   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:20:33
+   |                                 ------------------------------ inside `S1` at $DIR/forbidden_slices.rs:19:33
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -35,13 +35,13 @@ LL |         &*ptr::slice_from_raw_parts(data, len)
    |         dereferencing pointer failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |         inside `std::slice::from_raw_parts::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:23:34
+  ::: $DIR/forbidden_slices.rs:22:34
    |
 LL | pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 2) };
-   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:23:34
+   |                                  ---------------------- inside `S2` at $DIR/forbidden_slices.rs:22:34
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:26:1
+  --> $DIR/forbidden_slices.rs:25:1
    |
 LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
@@ -52,7 +52,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:28:1
+  --> $DIR/forbidden_slices.rs:27:1
    |
 LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size_of::<&u32>()) };
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -63,7 +63,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, size
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:30:1
+  --> $DIR/forbidden_slices.rs:29:1
    |
 LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
@@ -74,7 +74,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4)
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:33:1
+  --> $DIR/forbidden_slices.rs:32:1
    |
 LL | pub static S7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -93,10 +93,10 @@ LL |         &*ptr::slice_from_raw_parts(data, len)
    |         dereferencing pointer failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |         inside `std::slice::from_raw_parts::<u64>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:44:5
+  ::: $DIR/forbidden_slices.rs:43:5
    |
 LL |     from_raw_parts(ptr, 1)
-   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:44:5
+   |     ---------------------- inside `S8` at $DIR/forbidden_slices.rs:43:5
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -104,7 +104,7 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  out-of-bounds offset_from: null pointer is not a valid pointer
+   |                  out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
    |                  inside `ptr::const_ptr::<impl *const u32>::sub_ptr` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $SRC_DIR/core/src/slice/raw.rs:LL:COL
@@ -112,10 +112,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:47:34
+  ::: $DIR/forbidden_slices.rs:46:34
    |
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:47:34
+   |                                  ---------------------------------------- inside `R0` at $DIR/forbidden_slices.rs:46:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -131,10 +131,10 @@ LL |         assert!(0 < pointee_size && pointee_size <= isize::MAX as usize);
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<()>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:48:33
+  ::: $DIR/forbidden_slices.rs:47:33
    |
 LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:48:33
+   |                                 ---------------------------------------- inside `R1` at $DIR/forbidden_slices.rs:47:33
    |
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -144,19 +144,19 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 4, so pointer to 8 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u32>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 ...
 LL |         unsafe { self.offset(count as isize) }
    |                  --------------------------- inside `ptr::const_ptr::<impl *const u32>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:51:25
+  ::: $DIR/forbidden_slices.rs:50:25
    |
 LL |     from_ptr_range(ptr..ptr.add(2))
-   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:51:25
+   |                         ---------- inside `R2` at $DIR/forbidden_slices.rs:50:25
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:53:1
+  --> $DIR/forbidden_slices.rs:52:1
    |
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized bytes
@@ -167,7 +167,7 @@ LL | pub static R4: &[u8] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:58:1
+  --> $DIR/forbidden_slices.rs:57:1
    |
 LL | pub static R5: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>: encountered a pointer, but expected plain (non-pointer) bytes
@@ -178,7 +178,7 @@ LL | pub static R5: &[u8] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:63:1
+  --> $DIR/forbidden_slices.rs:62:1
    |
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
@@ -189,7 +189,7 @@ LL | pub static R6: &[bool] = unsafe {
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:68:1
+  --> $DIR/forbidden_slices.rs:67:1
    |
 LL | pub static R7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -205,16 +205,16 @@ error[E0080]: could not evaluate static initializer
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: ALLOC_ID has size 8, so pointer to 8 bytes starting at offset 1 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u64>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 ...
 LL |         unsafe { self.offset(count as isize) }
    |                  --------------------------- inside `ptr::const_ptr::<impl *const u64>::add` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:75:25
+  ::: $DIR/forbidden_slices.rs:74:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
-   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:75:25
+   |                         ---------- inside `R8` at $DIR/forbidden_slices.rs:74:25
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -230,10 +230,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:80:34
+  ::: $DIR/forbidden_slices.rs:79:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
-   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:80:34
+   |                                  ----------------------------------------------- inside `R9` at $DIR/forbidden_slices.rs:79:34
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -249,10 +249,10 @@ LL |         unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) }
 LL |     unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
    |                                          ------------------------------ inside `from_ptr_range::<u32>` at $SRC_DIR/core/src/slice/raw.rs:LL:COL
    |
-  ::: $DIR/forbidden_slices.rs:81:35
+  ::: $DIR/forbidden_slices.rs:80:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
-   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:81:35
+   |                                   ------------------------ inside `R10` at $DIR/forbidden_slices.rs:80:35
 
 error: aborting due to 18 previous errors
 
diff --git a/src/test/ui/const-ptr/forbidden_slices.rs b/src/test/ui/const-ptr/forbidden_slices.rs
index 4465da45468..e2184911f42 100644
--- a/src/test/ui/const-ptr/forbidden_slices.rs
+++ b/src/test/ui/const-ptr/forbidden_slices.rs
@@ -3,7 +3,6 @@
 // normalize-stderr-test "a[0-9]+\+0x" -> "A_ID+0x"
 // error-pattern: could not evaluate static initializer
 #![feature(
-    const_slice_from_raw_parts,
     slice_from_ptr_range,
     const_slice_from_ptr_range,
     pointer_byte_offsets,
diff --git a/src/test/ui/consts/const-deref-ptr.stderr b/src/test/ui/consts/const-deref-ptr.stderr
index 7606afdc4ff..22cb6451e87 100644
--- a/src/test/ui/consts/const-deref-ptr.stderr
+++ b/src/test/ui/consts/const-deref-ptr.stderr
@@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/const-deref-ptr.rs:4:29
    |
 LL |     static C: u64 = unsafe {*(0xdeadbeef as *const u64)};
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef is not a valid pointer
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0xdeadbeef[noalloc] is a dangling pointer (it has no provenance)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-enum-cast.rs b/src/test/ui/consts/const-enum-cast.rs
index a3255c2f601..39968495144 100644
--- a/src/test/ui/consts/const-enum-cast.rs
+++ b/src/test/ui/consts/const-enum-cast.rs
@@ -4,6 +4,19 @@
 enum A { A1, A2 }
 enum B { B1=4, B2=2 }
 
+#[allow(dead_code)]
+#[repr(align(8))]
+enum Aligned {
+    Zero = 0,
+    One = 1,
+}
+
+// regression test for https://github.com/rust-lang/rust/issues/96185
+const X: u8 = {
+    let aligned = Aligned::Zero;
+    aligned as u8
+};
+
 pub fn main () {
     static c1: isize = A::A2 as isize;
     static c2: isize = B::B2 as isize;
@@ -23,4 +36,6 @@ pub fn main () {
     assert_eq!(c2_2, 4);
     assert_eq!(a1_2, 0);
     assert_eq!(a2_2, 4);
+
+    assert_eq!(X, 0);
 }
diff --git a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr
index 94cf64fff19..f06dedc2298 100644
--- a/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr
+++ b/src/test/ui/consts/const-eval/const_panic_stability.e2018.stderr
@@ -5,9 +5,9 @@ LL |     panic!({ "foo" });
    |            ^^^^^^^^^
    |
    = note: `#[warn(non_fmt_panics)]` on by default
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", { "foo" });
    |            +++++
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
index c3f8b9f31ea..ec5508a1e90 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.rs
@@ -5,6 +5,6 @@ const Z: i32 = unsafe { *(&1 as *const i32) };
 
 // bad, will thus error in miri
 const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed
-//~| is not a valid pointer
+//~| is a dangling pointer
 const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed
-//~| is not a valid pointer
+//~| is a dangling pointer
diff --git a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
index df8a80be72c..e41dea873ac 100644
--- a/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
+++ b/src/test/ui/consts/const-eval/const_raw_ptr_ops2.stderr
@@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const_raw_ptr_ops2.rs:7:26
    |
 LL | const Z2: i32 = unsafe { *(42 as *const i32) };
-   |                          ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a is not a valid pointer
+   |                          ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_raw_ptr_ops2.rs:9:26
    |
 LL | const Z3: i32 = unsafe { *(44 as *const i32) };
-   |                          ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c is not a valid pointer
+   |                          ^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance)
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
index d5576ebfd02..e1f5e8ae145 100644
--- a/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
+++ b/src/test/ui/consts/const-eval/issue-91827-extern-types.rs
@@ -4,7 +4,6 @@
 // Regression test for issue #91827.
 
 #![feature(const_ptr_offset_from)]
-#![feature(const_slice_from_raw_parts)]
 #![feature(extern_types)]
 
 use std::ptr::addr_of;
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
index b60e3337b44..2cae35bc4d0 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.32bit.stderr
@@ -158,11 +158,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:62:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc43, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 4, align: 4) {
-               ╾─alloc43─╼                                     │ ╾──╼
+               ╾─alloc41─╼                                     │ ╾──╼
            }
 
 error: aborting due to 16 previous errors
diff --git a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
index 505ef2dd7d7..e2cd0e64db8 100644
--- a/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-ref-ptr.64bit.stderr
@@ -158,11 +158,11 @@ error[E0080]: it is undefined behavior to use this value
   --> $DIR/ub-ref-ptr.rs:62:1
    |
 LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc43, but expected a function pointer
+   | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 8) {
-               ╾───────alloc43───────╼                         │ ╾──────╼
+               ╾───────alloc41───────╼                         │ ╾──────╼
            }
 
 error: aborting due to 16 previous errors
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
index 74f21c7c34f..2fd98ea322b 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.32bit.stderr
@@ -319,7 +319,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:147:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:151:5
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
index 1775b0dc2ed..bae24907659 100644
--- a/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
+++ b/src/test/ui/consts/const-eval/ub-wide-ptr.64bit.stderr
@@ -319,7 +319,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:147:5
    |
 LL |     mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/ub-wide-ptr.rs:151:5
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
index e0704e24a2e..074beaab2c4 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.rs
@@ -11,7 +11,7 @@ const fn helper() -> Option<&'static mut i32> { unsafe {
     // Undefined behaviour (integer as pointer), who doesn't love tests like this.
     // This code never gets executed, because the static checks fail before that.
     Some(&mut *(42 as *mut i32)) //~ ERROR evaluation of constant value failed
-    //~| 0x2a is not a valid pointer
+    //~| 0x2a[noalloc] is a dangling pointer
 } }
 // The error is an evaluation error and not a validation error, so the error is reported
 // directly at the site where it occurs.
diff --git a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
index f2aec37a729..234e55e3a96 100644
--- a/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
+++ b/src/test/ui/consts/const-mut-refs/mut_ref_in_final_dynamic_check.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL |     Some(&mut *(42 as *mut i32))
    |          ^^^^^^^^^^^^^^^^^^^^^^
    |          |
-   |          dereferencing pointer failed: 0x2a is not a valid pointer
+   |          dereferencing pointer failed: 0x2a[noalloc] is a dangling pointer (it has no provenance)
    |          inside `helper` at $DIR/mut_ref_in_final_dynamic_check.rs:13:10
 ...
 LL | const A: Option<&mut i32> = helper();
diff --git a/src/test/ui/consts/const-needs_drop-monomorphic.stderr b/src/test/ui/consts/const-needs_drop-monomorphic.stderr
index 4399db11665..0874a70ce39 100644
--- a/src/test/ui/consts/const-needs_drop-monomorphic.stderr
+++ b/src/test/ui/consts/const-needs_drop-monomorphic.stderr
@@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `assert` found for struct `Bo
   --> $DIR/const-needs_drop-monomorphic.rs:11:46
    |
 LL | struct Bool<const B: bool> {}
-   |        ---- function or associated item `assert` not found for this struct
+   | -------------------------- function or associated item `assert` not found for this struct
 ...
 LL |     Bool::<{ std::mem::needs_drop::<T>() }>::assert();
    |                                              ^^^^^^ function or associated item cannot be called on `Bool<{ std::mem::needs_drop::<T>() }>` due to unsatisfied trait bounds
diff --git a/src/test/ui/consts/const-size_of_val-align_of_val.rs b/src/test/ui/consts/const-size_of_val-align_of_val.rs
index 5a78313c483..c3de6dc2075 100644
--- a/src/test/ui/consts/const-size_of_val-align_of_val.rs
+++ b/src/test/ui/consts/const-size_of_val-align_of_val.rs
@@ -2,7 +2,6 @@
 
 #![feature(const_size_of_val, const_align_of_val)]
 #![feature(const_size_of_val_raw, const_align_of_val_raw, layout_for_ptr)]
-#![feature(const_slice_from_raw_parts)]
 
 use std::{mem, ptr};
 
diff --git a/src/test/ui/consts/issue-50439.rs b/src/test/ui/consts/issue-50439.rs
new file mode 100644
index 00000000000..0be7c405473
--- /dev/null
+++ b/src/test/ui/consts/issue-50439.rs
@@ -0,0 +1,29 @@
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+pub trait ReflectDrop {
+    const REFLECT_DROP: bool = false;
+}
+
+impl<T> ReflectDrop for T where T: Clone {}
+
+pub trait PinDropInternal {
+    fn is_valid()
+    where
+        Self: ReflectDrop;
+}
+
+struct Bears<T>(T);
+
+default impl<T> ReflectDrop for Bears<T> {}
+
+impl<T: Sized> PinDropInternal for Bears<T> {
+    fn is_valid()
+    where
+        Self: ReflectDrop,
+    {
+        let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize]; //~ ERROR constant expression depends on a generic parameter
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-50439.stderr b/src/test/ui/consts/issue-50439.stderr
new file mode 100644
index 00000000000..3fbdf33b2d8
--- /dev/null
+++ b/src/test/ui/consts/issue-50439.stderr
@@ -0,0 +1,10 @@
+error: constant expression depends on a generic parameter
+  --> $DIR/issue-50439.rs:25:22
+   |
+LL |         let _ = [(); 0 - !!(<Bears<T> as ReflectDrop>::REFLECT_DROP) as usize];
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/consts/issue-78655.rs b/src/test/ui/consts/issue-78655.rs
index b85e6129925..82d2d7c21d8 100644
--- a/src/test/ui/consts/issue-78655.rs
+++ b/src/test/ui/consts/issue-78655.rs
@@ -1,6 +1,6 @@
 const FOO: *const u32 = {
     let x;
-    &x //~ ERROR borrow of possibly-uninitialized variable: `x`
+    &x //~ ERROR E0381
 };
 
 fn main() {
diff --git a/src/test/ui/consts/issue-78655.stderr b/src/test/ui/consts/issue-78655.stderr
index 734266a3453..f5b1123e7f3 100644
--- a/src/test/ui/consts/issue-78655.stderr
+++ b/src/test/ui/consts/issue-78655.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/issue-78655.rs:3:5
    |
+LL |     let x;
+   |         - binding declared here but left uninitialized
 LL |     &x
-   |     ^^ use of possibly-uninitialized `x`
+   |     ^^ `x` used here but it isn't initialized
 
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
diff --git a/src/test/ui/consts/issue-96169.rs b/src/test/ui/consts/issue-96169.rs
new file mode 100644
index 00000000000..14c0a1399a0
--- /dev/null
+++ b/src/test/ui/consts/issue-96169.rs
@@ -0,0 +1,18 @@
+// check-pass
+// compile-flags: -Zmir-opt-level=4 --emit=mir
+#![allow(unused)]
+fn a() -> usize { 0 }
+
+fn bar(_: u32) {}
+
+fn baz() -> *const dyn Fn(u32) { unimplemented!() }
+
+fn foo() {
+    match () {
+        _ if baz() == &bar as &dyn Fn(u32) => (),
+        () => (),
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/consts/offset_from_ub.rs b/src/test/ui/consts/offset_from_ub.rs
index 10e368ba133..db2d421427c 100644
--- a/src/test/ui/consts/offset_from_ub.rs
+++ b/src/test/ui/consts/offset_from_ub.rs
@@ -34,14 +34,14 @@ pub const NOT_MULTIPLE_OF_SIZE: isize = {
 pub const OFFSET_FROM_NULL: isize = {
     let ptr = 0 as *const u8;
     unsafe { ptr_offset_from(ptr, ptr) } //~ERROR evaluation of constant value failed
-    //~| null pointer is not a valid pointer
+    //~| null pointer is a dangling pointer
 };
 
 pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
     let ptr1 = 8 as *const u8;
     let ptr2 = 16 as *const u8;
     unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
-    //~| 0x8 is not a valid pointer
+    //~| 0x8[noalloc] is a dangling pointer
 };
 
 const OUT_OF_BOUNDS_1: isize = {
diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr
index eb7f1d7a6b2..94d778bc8a1 100644
--- a/src/test/ui/consts/offset_from_ub.stderr
+++ b/src/test/ui/consts/offset_from_ub.stderr
@@ -28,31 +28,31 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:36:14
    |
 LL |     unsafe { ptr_offset_from(ptr, ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is not a valid pointer
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:43:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8 is not a valid pointer
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: 0x8[noalloc] is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:52:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, start_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc20 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc18 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:61:14
    |
 LL |     unsafe { ptr_offset_from(start_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc23 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc21 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:69:14
    |
 LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc26 has size 4, so pointer at offset 10 is out-of-bounds
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: alloc24 has size 4, so pointer at offset 10 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:78:27
diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr
index 4d3e7ee2411..5a792bba50c 100644
--- a/src/test/ui/consts/offset_ub.stderr
+++ b/src/test/ui/consts/offset_ub.stderr
@@ -18,7 +18,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:8:43
@@ -32,7 +32,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: allocN has size 100, so pointer to 101 bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:9:45
@@ -102,7 +102,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: allocN has size 1, so pointer to 2 bytes starting at offset -4 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:15:49
@@ -116,7 +116,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: allocN has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:17:50
@@ -130,7 +130,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) as *mut T }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: 0x1 is not a valid pointer
+   |                  out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance)
    |                  inside `ptr::mut_ptr::<impl *mut u8>::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:18:42
@@ -144,7 +144,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: null pointer is not a valid pointer
+   |                  out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:21:50
@@ -158,7 +158,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: 0x7f..f is not a valid pointer
+   |                  out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
    |                  inside `ptr::const_ptr::<impl *const u8>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/offset_ub.rs:24:47
diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr
index 69936ee6c13..67b9fec4a0e 100644
--- a/src/test/ui/consts/ptr_comparisons.stderr
+++ b/src/test/ui/consts/ptr_comparisons.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL |         unsafe { intrinsics::offset(self, count) }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                  |
-   |                  pointer arithmetic failed: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
+   |                  out-of-bounds pointer arithmetic: alloc3 has size $WORD, so pointer to $TWO_WORDS bytes starting at offset 0 is out-of-bounds
    |                  inside `ptr::const_ptr::<impl *const usize>::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
   ::: $DIR/ptr_comparisons.rs:58:34
diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr
index 3909862ff1c..128087f1e37 100644
--- a/src/test/ui/copy-a-resource.stderr
+++ b/src/test/ui/copy-a-resource.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Foo` in the current scop
   --> $DIR/copy-a-resource.rs:18:16
    |
 LL | struct Foo {
-   |        --- method `clone` not found for this struct
+   | ---------- method `clone` not found for this struct
 ...
 LL |     let _y = x.clone();
    |                ^^^^^ method not found in `Foo`
diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr
index 60bfbe94a8a..cfe1e62d931 100644
--- a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr
+++ b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr
@@ -17,12 +17,6 @@ LL |     #[rustc_then_this_would_need(trait_def)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:32:9
-   |
-LL |         #[rustc_then_this_would_need(fn_sig)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
   --> $DIR/dep-graph-struct-signature.rs:36:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
@@ -53,36 +47,12 @@ LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:48:9
-   |
-LL |         #[rustc_then_this_would_need(fn_sig)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
-  --> $DIR/dep-graph-struct-signature.rs:49:9
-   |
-LL |         #[rustc_then_this_would_need(typeck)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
   --> $DIR/dep-graph-struct-signature.rs:53:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:55:9
-   |
-LL |         #[rustc_then_this_would_need(fn_sig)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
-  --> $DIR/dep-graph-struct-signature.rs:56:9
-   |
-LL |         #[rustc_then_this_would_need(typeck)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
   --> $DIR/dep-graph-struct-signature.rs:61:9
    |
 LL |         #[rustc_then_this_would_need(type_of)]
@@ -107,12 +77,6 @@ LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `fn_sig`
-  --> $DIR/dep-graph-struct-signature.rs:77:9
-   |
-LL |         #[rustc_then_this_would_need(fn_sig)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: no path from `WillChange` to `fn_sig`
   --> $DIR/dep-graph-struct-signature.rs:81:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
@@ -130,5 +94,41 @@ error: no path from `WillChange` to `typeck`
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: OK
+  --> $DIR/dep-graph-struct-signature.rs:32:9
+   |
+LL |         #[rustc_then_this_would_need(fn_sig)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: no path from `WillChange` to `fn_sig`
+  --> $DIR/dep-graph-struct-signature.rs:77:9
+   |
+LL |         #[rustc_then_this_would_need(fn_sig)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-struct-signature.rs:48:9
+   |
+LL |         #[rustc_then_this_would_need(fn_sig)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-struct-signature.rs:49:9
+   |
+LL |         #[rustc_then_this_would_need(typeck)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-struct-signature.rs:55:9
+   |
+LL |         #[rustc_then_this_would_need(fn_sig)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-struct-signature.rs:56:9
+   |
+LL |         #[rustc_then_this_would_need(typeck)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.stderr b/src/test/ui/dep-graph/dep-graph-type-alias.stderr
index c59cf8014c3..42ac803b22e 100644
--- a/src/test/ui/dep-graph/dep-graph-type-alias.stderr
+++ b/src/test/ui/dep-graph/dep-graph-type-alias.stderr
@@ -28,12 +28,6 @@ error: no path from `TypeAlias` to `type_of`
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: OK
-  --> $DIR/dep-graph-type-alias.rs:36:5
-   |
-LL |     #[rustc_then_this_would_need(fn_sig)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: no path from `TypeAlias` to `type_of`
   --> $DIR/dep-graph-type-alias.rs:42:1
    |
@@ -41,18 +35,6 @@ LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:44:5
-   |
-LL |     #[rustc_then_this_would_need(fn_sig)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
-  --> $DIR/dep-graph-type-alias.rs:45:5
-   |
-LL |     #[rustc_then_this_would_need(typeck)]
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: OK
   --> $DIR/dep-graph-type-alias.rs:49:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
@@ -70,5 +52,23 @@ error: OK
 LL | #[rustc_then_this_would_need(typeck)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: OK
+  --> $DIR/dep-graph-type-alias.rs:36:5
+   |
+LL |     #[rustc_then_this_would_need(fn_sig)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-type-alias.rs:44:5
+   |
+LL |     #[rustc_then_this_would_need(fn_sig)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: OK
+  --> $DIR/dep-graph-type-alias.rs:45:5
+   |
+LL |     #[rustc_then_this_would_need(typeck)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr
index 55847aeec55..c4fddcf5f24 100644
--- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr
+++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr
@@ -3,8 +3,8 @@ error[E0599]: the method `clone` exists for struct `Bar<NotClone>`, but its trai
    |
 LL | struct Bar<T: Foo> {
    | ------------------
-   | |      |
-   | |      method `clone` not found for this struct
+   | |
+   | method `clone` not found for this struct
    | doesn't satisfy `Bar<NotClone>: Clone`
 ...
 LL | struct NotClone;
diff --git a/src/test/ui/derives/issue-91492.stderr b/src/test/ui/derives/issue-91492.stderr
index 5b4feaeb52a..fbd48336d91 100644
--- a/src/test/ui/derives/issue-91492.stderr
+++ b/src/test/ui/derives/issue-91492.stderr
@@ -37,7 +37,7 @@ LL | pub struct NoDerives;
    | -------------------- doesn't satisfy `NoDerives: Clone`
 ...
 LL | struct Object<T, A>(T, A);
-   |        ------ method `use_clone` not found for this struct
+   | ------------------- method `use_clone` not found for this struct
 ...
 LL |     foo.use_clone();
    |         ^^^^^^^^^ method cannot be called on `Object<NoDerives, SomeDerives>` due to unsatisfied trait bounds
diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr
index 3608052e2ff..12be269565d 100644
--- a/src/test/ui/derives/issue-91550.stderr
+++ b/src/test/ui/derives/issue-91550.stderr
@@ -25,7 +25,7 @@ LL | pub struct NoDerives;
    | -------------------- doesn't satisfy `NoDerives: Eq`
 LL |
 LL | struct Object<T>(T);
-   |        ------ method `use_eq` not found for this struct
+   | ---------------- method `use_eq` not found for this struct
 ...
 LL |     foo.use_eq();
    |         ^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
@@ -44,7 +44,7 @@ LL | pub struct NoDerives;
    | -------------------- doesn't satisfy `NoDerives: Ord`
 LL |
 LL | struct Object<T>(T);
-   |        ------ method `use_ord` not found for this struct
+   | ---------------- method `use_ord` not found for this struct
 ...
 LL |     foo.use_ord();
    |         ^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
@@ -66,7 +66,7 @@ LL | pub struct NoDerives;
    | doesn't satisfy `NoDerives: PartialOrd`
 LL |
 LL | struct Object<T>(T);
-   |        ------ method `use_ord_and_partial_ord` not found for this struct
+   | ---------------- method `use_ord_and_partial_ord` not found for this struct
 ...
 LL |     foo.use_ord_and_partial_ord();
    |         ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
diff --git a/src/test/ui/deriving/deriving-all-codegen.rs b/src/test/ui/deriving/deriving-all-codegen.rs
index 2f6ef74ac49..1a651b2074c 100644
--- a/src/test/ui/deriving/deriving-all-codegen.rs
+++ b/src/test/ui/deriving/deriving-all-codegen.rs
@@ -28,12 +28,27 @@ struct Point {
     y: u32,
 }
 
-// A long struct.
+// A large struct.
 #[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Big {
     b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8:u32,
 }
 
+// A packed tuple struct.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(packed)]
+struct Packed(u32);
+
+// An empty enum.
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+enum Enum0 {}
+
+// A single-variant enum.
+#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+enum Enum1 {
+    Single { x: u32 }
+}
+
 // A C-like, fieldless enum.
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 enum Fieldless {
@@ -61,3 +76,11 @@ enum Fielded {
     Y(bool),
     Z(Option<i32>),
 }
+
+// A union. Most builtin traits are not derivable for unions.
+#[derive(Clone, Copy)]
+pub union Union {
+    pub b: bool,
+    pub u: u32,
+    pub i: i32,
+}
diff --git a/src/test/ui/deriving/deriving-all-codegen.stdout b/src/test/ui/deriving/deriving-all-codegen.stdout
index faa5a3c3ddf..9b10192d75a 100644
--- a/src/test/ui/deriving/deriving-all-codegen.stdout
+++ b/src/test/ui/deriving/deriving-all-codegen.stdout
@@ -28,7 +28,7 @@ struct Empty;
 #[allow(unused_qualifications)]
 impl ::core::clone::Clone for Empty {
     #[inline]
-    fn clone(&self) -> Empty { { *self } }
+    fn clone(&self) -> Empty { *self }
 }
 #[automatically_derived]
 #[allow(unused_qualifications)]
@@ -37,7 +37,7 @@ impl ::core::marker::Copy for Empty { }
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Empty {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match *self { Self => ::core::fmt::Formatter::write_str(f, "Empty"), }
+        ::core::fmt::Formatter::write_str(f, "Empty")
     }
 }
 #[automatically_derived]
@@ -49,18 +49,14 @@ impl ::core::default::Default for Empty {
 #[automatically_derived]
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Empty {
-    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match *self { Self => {} }
-    }
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {}
 }
 impl ::core::marker::StructuralPartialEq for Empty {}
 #[automatically_derived]
 #[allow(unused_qualifications)]
 impl ::core::cmp::PartialEq for Empty {
     #[inline]
-    fn eq(&self, other: &Empty) -> bool {
-        match *other { Self => match *self { Self => true, }, }
-    }
+    fn eq(&self, other: &Empty) -> bool { true }
 }
 impl ::core::marker::StructuralEq for Empty {}
 #[automatically_derived]
@@ -69,7 +65,7 @@ impl ::core::cmp::Eq for Empty {
     #[inline]
     #[doc(hidden)]
     #[no_coverage]
-    fn assert_receiver_is_total_eq(&self) -> () { {} }
+    fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
 #[allow(unused_qualifications)]
@@ -77,13 +73,7 @@ impl ::core::cmp::PartialOrd for Empty {
     #[inline]
     fn partial_cmp(&self, other: &Empty)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        match *other {
-            Self =>
-                match *self {
-                    Self =>
-                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                },
-        }
+        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
     }
 }
 #[automatically_derived]
@@ -91,9 +81,7 @@ impl ::core::cmp::PartialOrd for Empty {
 impl ::core::cmp::Ord for Empty {
     #[inline]
     fn cmp(&self, other: &Empty) -> ::core::cmp::Ordering {
-        match *other {
-            Self => match *self { Self => ::core::cmp::Ordering::Equal, },
-        }
+        ::core::cmp::Ordering::Equal
     }
 }
 
@@ -107,11 +95,8 @@ struct Point {
 impl ::core::clone::Clone for Point {
     #[inline]
     fn clone(&self) -> Point {
-        {
-            let _: ::core::clone::AssertParamIsClone<u32>;
-            let _: ::core::clone::AssertParamIsClone<u32>;
-            *self
-        }
+        let _: ::core::clone::AssertParamIsClone<u32>;
+        *self
     }
 }
 #[automatically_derived]
@@ -121,11 +106,8 @@ impl ::core::marker::Copy for Point { }
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Point {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match *self {
-            Self { x: ref __self_0_0, y: ref __self_0_1 } =>
-                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point",
-                    "x", &&(*__self_0_0), "y", &&(*__self_0_1)),
-        }
+        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Point", "x",
+            &&self.x, "y", &&self.y)
     }
 }
 #[automatically_derived]
@@ -143,12 +125,8 @@ impl ::core::default::Default for Point {
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Point {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match *self {
-            Self { x: ref __self_0_0, y: ref __self_0_1 } => {
-                ::core::hash::Hash::hash(&(*__self_0_0), state);
-                ::core::hash::Hash::hash(&(*__self_0_1), state)
-            }
-        }
+        ::core::hash::Hash::hash(&self.x, state);
+        ::core::hash::Hash::hash(&self.y, state)
     }
 }
 impl ::core::marker::StructuralPartialEq for Point {}
@@ -157,25 +135,11 @@ impl ::core::marker::StructuralPartialEq for Point {}
 impl ::core::cmp::PartialEq for Point {
     #[inline]
     fn eq(&self, other: &Point) -> bool {
-        match *other {
-            Self { x: ref __self_1_0, y: ref __self_1_1 } =>
-                match *self {
-                    Self { x: ref __self_0_0, y: ref __self_0_1 } =>
-                        (*__self_0_0) == (*__self_1_0) &&
-                            (*__self_0_1) == (*__self_1_1),
-                },
-        }
+        self.x == other.x && self.y == other.y
     }
     #[inline]
     fn ne(&self, other: &Point) -> bool {
-        match *other {
-            Self { x: ref __self_1_0, y: ref __self_1_1 } =>
-                match *self {
-                    Self { x: ref __self_0_0, y: ref __self_0_1 } =>
-                        (*__self_0_0) != (*__self_1_0) ||
-                            (*__self_0_1) != (*__self_1_1),
-                },
-        }
+        self.x != other.x || self.y != other.y
     }
 }
 impl ::core::marker::StructuralEq for Point {}
@@ -186,10 +150,7 @@ impl ::core::cmp::Eq for Point {
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        {
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-        }
+        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]
@@ -198,24 +159,10 @@ impl ::core::cmp::PartialOrd for Point {
     #[inline]
     fn partial_cmp(&self, other: &Point)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        match *other {
-            Self { x: ref __self_1_0, y: ref __self_1_1 } =>
-                match *self {
-                    Self { x: ref __self_0_0, y: ref __self_0_1 } =>
-                        match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_0),
-                                &(*__self_1_0)) {
-                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                =>
-                                match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_1),
-                                        &(*__self_1_1)) {
-                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                        =>
-                                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                    cmp => cmp,
-                                },
-                            cmp => cmp,
-                        },
-                },
+        match ::core::cmp::PartialOrd::partial_cmp(&self.x, &other.x) {
+            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+                ::core::cmp::PartialOrd::partial_cmp(&self.y, &other.y),
+            cmp => cmp,
         }
     }
 }
@@ -224,27 +171,15 @@ impl ::core::cmp::PartialOrd for Point {
 impl ::core::cmp::Ord for Point {
     #[inline]
     fn cmp(&self, other: &Point) -> ::core::cmp::Ordering {
-        match *other {
-            Self { x: ref __self_1_0, y: ref __self_1_1 } =>
-                match *self {
-                    Self { x: ref __self_0_0, y: ref __self_0_1 } =>
-                        match ::core::cmp::Ord::cmp(&(*__self_0_0), &(*__self_1_0))
-                            {
-                            ::core::cmp::Ordering::Equal =>
-                                match ::core::cmp::Ord::cmp(&(*__self_0_1), &(*__self_1_1))
-                                    {
-                                    ::core::cmp::Ordering::Equal =>
-                                        ::core::cmp::Ordering::Equal,
-                                    cmp => cmp,
-                                },
-                            cmp => cmp,
-                        },
-                },
+        match ::core::cmp::Ord::cmp(&self.x, &other.x) {
+            ::core::cmp::Ordering::Equal =>
+                ::core::cmp::Ord::cmp(&self.y, &other.y),
+            cmp => cmp,
         }
     }
 }
 
-// A long struct.
+// A large struct.
 struct Big {
     b1: u32,
     b2: u32,
@@ -260,26 +195,15 @@ struct Big {
 impl ::core::clone::Clone for Big {
     #[inline]
     fn clone(&self) -> Big {
-        match *self {
-            Self {
-                b1: ref __self_0_0,
-                b2: ref __self_0_1,
-                b3: ref __self_0_2,
-                b4: ref __self_0_3,
-                b5: ref __self_0_4,
-                b6: ref __self_0_5,
-                b7: ref __self_0_6,
-                b8: ref __self_0_7 } =>
-                Big {
-                    b1: ::core::clone::Clone::clone(&(*__self_0_0)),
-                    b2: ::core::clone::Clone::clone(&(*__self_0_1)),
-                    b3: ::core::clone::Clone::clone(&(*__self_0_2)),
-                    b4: ::core::clone::Clone::clone(&(*__self_0_3)),
-                    b5: ::core::clone::Clone::clone(&(*__self_0_4)),
-                    b6: ::core::clone::Clone::clone(&(*__self_0_5)),
-                    b7: ::core::clone::Clone::clone(&(*__self_0_6)),
-                    b8: ::core::clone::Clone::clone(&(*__self_0_7)),
-                },
+        Big {
+            b1: ::core::clone::Clone::clone(&self.b1),
+            b2: ::core::clone::Clone::clone(&self.b2),
+            b3: ::core::clone::Clone::clone(&self.b3),
+            b4: ::core::clone::Clone::clone(&self.b4),
+            b5: ::core::clone::Clone::clone(&self.b5),
+            b6: ::core::clone::Clone::clone(&self.b6),
+            b7: ::core::clone::Clone::clone(&self.b7),
+            b8: ::core::clone::Clone::clone(&self.b8),
         }
     }
 }
@@ -287,26 +211,13 @@ impl ::core::clone::Clone for Big {
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Big {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match *self {
-            Self {
-                b1: ref __self_0_0,
-                b2: ref __self_0_1,
-                b3: ref __self_0_2,
-                b4: ref __self_0_3,
-                b5: ref __self_0_4,
-                b6: ref __self_0_5,
-                b7: ref __self_0_6,
-                b8: ref __self_0_7 } => {
-                let names: &'static _ =
-                    &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"];
-                let values: &[&dyn ::core::fmt::Debug] =
-                    &[&&(*__self_0_0), &&(*__self_0_1), &&(*__self_0_2),
-                                &&(*__self_0_3), &&(*__self_0_4), &&(*__self_0_5),
-                                &&(*__self_0_6), &&(*__self_0_7)];
-                ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big",
-                    names, values)
-            }
-        }
+        let names: &'static _ =
+            &["b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8"];
+        let values: &[&dyn ::core::fmt::Debug] =
+            &[&&self.b1, &&self.b2, &&self.b3, &&self.b4, &&self.b5,
+                        &&self.b6, &&self.b7, &&self.b8];
+        ::core::fmt::Formatter::debug_struct_fields_finish(f, "Big", names,
+            values)
     }
 }
 #[automatically_derived]
@@ -330,26 +241,14 @@ impl ::core::default::Default for Big {
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Big {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match *self {
-            Self {
-                b1: ref __self_0_0,
-                b2: ref __self_0_1,
-                b3: ref __self_0_2,
-                b4: ref __self_0_3,
-                b5: ref __self_0_4,
-                b6: ref __self_0_5,
-                b7: ref __self_0_6,
-                b8: ref __self_0_7 } => {
-                ::core::hash::Hash::hash(&(*__self_0_0), state);
-                ::core::hash::Hash::hash(&(*__self_0_1), state);
-                ::core::hash::Hash::hash(&(*__self_0_2), state);
-                ::core::hash::Hash::hash(&(*__self_0_3), state);
-                ::core::hash::Hash::hash(&(*__self_0_4), state);
-                ::core::hash::Hash::hash(&(*__self_0_5), state);
-                ::core::hash::Hash::hash(&(*__self_0_6), state);
-                ::core::hash::Hash::hash(&(*__self_0_7), state)
-            }
-        }
+        ::core::hash::Hash::hash(&self.b1, state);
+        ::core::hash::Hash::hash(&self.b2, state);
+        ::core::hash::Hash::hash(&self.b3, state);
+        ::core::hash::Hash::hash(&self.b4, state);
+        ::core::hash::Hash::hash(&self.b5, state);
+        ::core::hash::Hash::hash(&self.b6, state);
+        ::core::hash::Hash::hash(&self.b7, state);
+        ::core::hash::Hash::hash(&self.b8, state)
     }
 }
 impl ::core::marker::StructuralPartialEq for Big {}
@@ -358,69 +257,17 @@ impl ::core::marker::StructuralPartialEq for Big {}
 impl ::core::cmp::PartialEq for Big {
     #[inline]
     fn eq(&self, other: &Big) -> bool {
-        match *other {
-            Self {
-                b1: ref __self_1_0,
-                b2: ref __self_1_1,
-                b3: ref __self_1_2,
-                b4: ref __self_1_3,
-                b5: ref __self_1_4,
-                b6: ref __self_1_5,
-                b7: ref __self_1_6,
-                b8: ref __self_1_7 } =>
-                match *self {
-                    Self {
-                        b1: ref __self_0_0,
-                        b2: ref __self_0_1,
-                        b3: ref __self_0_2,
-                        b4: ref __self_0_3,
-                        b5: ref __self_0_4,
-                        b6: ref __self_0_5,
-                        b7: ref __self_0_6,
-                        b8: ref __self_0_7 } =>
-                        (*__self_0_0) == (*__self_1_0) &&
-                                                    (*__self_0_1) == (*__self_1_1) &&
-                                                (*__self_0_2) == (*__self_1_2) &&
-                                            (*__self_0_3) == (*__self_1_3) &&
-                                        (*__self_0_4) == (*__self_1_4) &&
-                                    (*__self_0_5) == (*__self_1_5) &&
-                                (*__self_0_6) == (*__self_1_6) &&
-                            (*__self_0_7) == (*__self_1_7),
-                },
-        }
+        self.b1 == other.b1 && self.b2 == other.b2 && self.b3 == other.b3 &&
+                            self.b4 == other.b4 && self.b5 == other.b5 &&
+                    self.b6 == other.b6 && self.b7 == other.b7 &&
+            self.b8 == other.b8
     }
     #[inline]
     fn ne(&self, other: &Big) -> bool {
-        match *other {
-            Self {
-                b1: ref __self_1_0,
-                b2: ref __self_1_1,
-                b3: ref __self_1_2,
-                b4: ref __self_1_3,
-                b5: ref __self_1_4,
-                b6: ref __self_1_5,
-                b7: ref __self_1_6,
-                b8: ref __self_1_7 } =>
-                match *self {
-                    Self {
-                        b1: ref __self_0_0,
-                        b2: ref __self_0_1,
-                        b3: ref __self_0_2,
-                        b4: ref __self_0_3,
-                        b5: ref __self_0_4,
-                        b6: ref __self_0_5,
-                        b7: ref __self_0_6,
-                        b8: ref __self_0_7 } =>
-                        (*__self_0_0) != (*__self_1_0) ||
-                                                    (*__self_0_1) != (*__self_1_1) ||
-                                                (*__self_0_2) != (*__self_1_2) ||
-                                            (*__self_0_3) != (*__self_1_3) ||
-                                        (*__self_0_4) != (*__self_1_4) ||
-                                    (*__self_0_5) != (*__self_1_5) ||
-                                (*__self_0_6) != (*__self_1_6) ||
-                            (*__self_0_7) != (*__self_1_7),
-                },
-        }
+        self.b1 != other.b1 || self.b2 != other.b2 || self.b3 != other.b3 ||
+                            self.b4 != other.b4 || self.b5 != other.b5 ||
+                    self.b6 != other.b6 || self.b7 != other.b7 ||
+            self.b8 != other.b8
     }
 }
 impl ::core::marker::StructuralEq for Big {}
@@ -431,16 +278,7 @@ impl ::core::cmp::Eq for Big {
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        {
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-        }
+        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]
@@ -449,65 +287,33 @@ impl ::core::cmp::PartialOrd for Big {
     #[inline]
     fn partial_cmp(&self, other: &Big)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        match *other {
-            Self {
-                b1: ref __self_1_0,
-                b2: ref __self_1_1,
-                b3: ref __self_1_2,
-                b4: ref __self_1_3,
-                b5: ref __self_1_4,
-                b6: ref __self_1_5,
-                b7: ref __self_1_6,
-                b8: ref __self_1_7 } =>
-                match *self {
-                    Self {
-                        b1: ref __self_0_0,
-                        b2: ref __self_0_1,
-                        b3: ref __self_0_2,
-                        b4: ref __self_0_3,
-                        b5: ref __self_0_4,
-                        b6: ref __self_0_5,
-                        b7: ref __self_0_6,
-                        b8: ref __self_0_7 } =>
-                        match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_0),
-                                &(*__self_1_0)) {
+        match ::core::cmp::PartialOrd::partial_cmp(&self.b1, &other.b1) {
+            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+                match ::core::cmp::PartialOrd::partial_cmp(&self.b2,
+                        &other.b2) {
+                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                        =>
+                        match ::core::cmp::PartialOrd::partial_cmp(&self.b3,
+                                &other.b3) {
                             ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                 =>
-                                match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_1),
-                                        &(*__self_1_1)) {
+                                match ::core::cmp::PartialOrd::partial_cmp(&self.b4,
+                                        &other.b4) {
                                     ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                         =>
-                                        match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_2),
-                                                &(*__self_1_2)) {
+                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b5,
+                                                &other.b5) {
                                             ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                 =>
-                                                match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_3),
-                                                        &(*__self_1_3)) {
+                                                match ::core::cmp::PartialOrd::partial_cmp(&self.b6,
+                                                        &other.b6) {
                                                     ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                         =>
-                                                        match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_4),
-                                                                &(*__self_1_4)) {
+                                                        match ::core::cmp::PartialOrd::partial_cmp(&self.b7,
+                                                                &other.b7) {
                                                             ::core::option::Option::Some(::core::cmp::Ordering::Equal)
                                                                 =>
-                                                                match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_5),
-                                                                        &(*__self_1_5)) {
-                                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                                                        =>
-                                                                        match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_6),
-                                                                                &(*__self_1_6)) {
-                                                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                                                                =>
-                                                                                match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0_7),
-                                                                                        &(*__self_1_7)) {
-                                                                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                                                                        =>
-                                                                                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                                                                    cmp => cmp,
-                                                                                },
-                                                                            cmp => cmp,
-                                                                        },
-                                                                    cmp => cmp,
-                                                                },
+                                                                ::core::cmp::PartialOrd::partial_cmp(&self.b8, &other.b8),
                                                             cmp => cmp,
                                                         },
                                                     cmp => cmp,
@@ -518,7 +324,9 @@ impl ::core::cmp::PartialOrd for Big {
                                 },
                             cmp => cmp,
                         },
+                    cmp => cmp,
                 },
+            cmp => cmp,
         }
     }
 }
@@ -527,57 +335,21 @@ impl ::core::cmp::PartialOrd for Big {
 impl ::core::cmp::Ord for Big {
     #[inline]
     fn cmp(&self, other: &Big) -> ::core::cmp::Ordering {
-        match *other {
-            Self {
-                b1: ref __self_1_0,
-                b2: ref __self_1_1,
-                b3: ref __self_1_2,
-                b4: ref __self_1_3,
-                b5: ref __self_1_4,
-                b6: ref __self_1_5,
-                b7: ref __self_1_6,
-                b8: ref __self_1_7 } =>
-                match *self {
-                    Self {
-                        b1: ref __self_0_0,
-                        b2: ref __self_0_1,
-                        b3: ref __self_0_2,
-                        b4: ref __self_0_3,
-                        b5: ref __self_0_4,
-                        b6: ref __self_0_5,
-                        b7: ref __self_0_6,
-                        b8: ref __self_0_7 } =>
-                        match ::core::cmp::Ord::cmp(&(*__self_0_0), &(*__self_1_0))
-                            {
+        match ::core::cmp::Ord::cmp(&self.b1, &other.b1) {
+            ::core::cmp::Ordering::Equal =>
+                match ::core::cmp::Ord::cmp(&self.b2, &other.b2) {
+                    ::core::cmp::Ordering::Equal =>
+                        match ::core::cmp::Ord::cmp(&self.b3, &other.b3) {
                             ::core::cmp::Ordering::Equal =>
-                                match ::core::cmp::Ord::cmp(&(*__self_0_1), &(*__self_1_1))
-                                    {
+                                match ::core::cmp::Ord::cmp(&self.b4, &other.b4) {
                                     ::core::cmp::Ordering::Equal =>
-                                        match ::core::cmp::Ord::cmp(&(*__self_0_2), &(*__self_1_2))
-                                            {
+                                        match ::core::cmp::Ord::cmp(&self.b5, &other.b5) {
                                             ::core::cmp::Ordering::Equal =>
-                                                match ::core::cmp::Ord::cmp(&(*__self_0_3), &(*__self_1_3))
-                                                    {
+                                                match ::core::cmp::Ord::cmp(&self.b6, &other.b6) {
                                                     ::core::cmp::Ordering::Equal =>
-                                                        match ::core::cmp::Ord::cmp(&(*__self_0_4), &(*__self_1_4))
-                                                            {
+                                                        match ::core::cmp::Ord::cmp(&self.b7, &other.b7) {
                                                             ::core::cmp::Ordering::Equal =>
-                                                                match ::core::cmp::Ord::cmp(&(*__self_0_5), &(*__self_1_5))
-                                                                    {
-                                                                    ::core::cmp::Ordering::Equal =>
-                                                                        match ::core::cmp::Ord::cmp(&(*__self_0_6), &(*__self_1_6))
-                                                                            {
-                                                                            ::core::cmp::Ordering::Equal =>
-                                                                                match ::core::cmp::Ord::cmp(&(*__self_0_7), &(*__self_1_7))
-                                                                                    {
-                                                                                    ::core::cmp::Ordering::Equal =>
-                                                                                        ::core::cmp::Ordering::Equal,
-                                                                                    cmp => cmp,
-                                                                                },
-                                                                            cmp => cmp,
-                                                                        },
-                                                                    cmp => cmp,
-                                                                },
+                                                                ::core::cmp::Ord::cmp(&self.b8, &other.b8),
                                                             cmp => cmp,
                                                         },
                                                     cmp => cmp,
@@ -588,7 +360,253 @@ impl ::core::cmp::Ord for Big {
                                 },
                             cmp => cmp,
                         },
+                    cmp => cmp,
                 },
+            cmp => cmp,
+        }
+    }
+}
+
+// A packed tuple struct.
+#[repr(packed)]
+struct Packed(u32);
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::clone::Clone for Packed {
+    #[inline]
+    fn clone(&self) -> Packed {
+        let _: ::core::clone::AssertParamIsClone<u32>;
+        *self
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::marker::Copy for Packed { }
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::fmt::Debug for Packed {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        let Self(__self_0_0) = *self;
+        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Packed",
+            &&__self_0_0)
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::default::Default for Packed {
+    #[inline]
+    fn default() -> Packed { Packed(::core::default::Default::default()) }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::hash::Hash for Packed {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        let Self(__self_0_0) = *self;
+        ::core::hash::Hash::hash(&__self_0_0, state)
+    }
+}
+impl ::core::marker::StructuralPartialEq for Packed {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialEq for Packed {
+    #[inline]
+    fn eq(&self, other: &Packed) -> bool {
+        let Self(__self_0_0) = *self;
+        let Self(__self_1_0) = *other;
+        __self_0_0 == __self_1_0
+    }
+    #[inline]
+    fn ne(&self, other: &Packed) -> bool {
+        let Self(__self_0_0) = *self;
+        let Self(__self_1_0) = *other;
+        __self_0_0 != __self_1_0
+    }
+}
+impl ::core::marker::StructuralEq for Packed {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Eq for Packed {
+    #[inline]
+    #[doc(hidden)]
+    #[no_coverage]
+    fn assert_receiver_is_total_eq(&self) -> () {
+        let _: ::core::cmp::AssertParamIsEq<u32>;
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialOrd for Packed {
+    #[inline]
+    fn partial_cmp(&self, other: &Packed)
+        -> ::core::option::Option<::core::cmp::Ordering> {
+        let Self(__self_0_0) = *self;
+        let Self(__self_1_0) = *other;
+        ::core::cmp::PartialOrd::partial_cmp(&__self_0_0, &__self_1_0)
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Ord for Packed {
+    #[inline]
+    fn cmp(&self, other: &Packed) -> ::core::cmp::Ordering {
+        let Self(__self_0_0) = *self;
+        let Self(__self_1_0) = *other;
+        ::core::cmp::Ord::cmp(&__self_0_0, &__self_1_0)
+    }
+}
+
+// An empty enum.
+enum Enum0 {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::clone::Clone for Enum0 {
+    #[inline]
+    fn clone(&self) -> Enum0 { *self }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::marker::Copy for Enum0 { }
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::fmt::Debug for Enum0 {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        unsafe { ::core::intrinsics::unreachable() }
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::hash::Hash for Enum0 {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        unsafe { ::core::intrinsics::unreachable() }
+    }
+}
+impl ::core::marker::StructuralPartialEq for Enum0 {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialEq for Enum0 {
+    #[inline]
+    fn eq(&self, other: &Enum0) -> bool {
+        unsafe { ::core::intrinsics::unreachable() }
+    }
+}
+impl ::core::marker::StructuralEq for Enum0 {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Eq for Enum0 {
+    #[inline]
+    #[doc(hidden)]
+    #[no_coverage]
+    fn assert_receiver_is_total_eq(&self) -> () {}
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialOrd for Enum0 {
+    #[inline]
+    fn partial_cmp(&self, other: &Enum0)
+        -> ::core::option::Option<::core::cmp::Ordering> {
+        unsafe { ::core::intrinsics::unreachable() }
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Ord for Enum0 {
+    #[inline]
+    fn cmp(&self, other: &Enum0) -> ::core::cmp::Ordering {
+        unsafe { ::core::intrinsics::unreachable() }
+    }
+}
+
+// A single-variant enum.
+enum Enum1 {
+    Single {
+        x: u32,
+    },
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::clone::Clone for Enum1 {
+    #[inline]
+    fn clone(&self) -> Enum1 {
+        match &*self {
+            &Enum1::Single { x: ref __self_0 } =>
+                Enum1::Single { x: ::core::clone::Clone::clone(&*__self_0) },
+        }
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::fmt::Debug for Enum1 {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        match &*self {
+            &Enum1::Single { x: ref __self_0 } =>
+                ::core::fmt::Formatter::debug_struct_field1_finish(f,
+                    "Single", "x", &&*__self_0),
+        }
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::hash::Hash for Enum1 {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        match &*self {
+            &Enum1::Single { x: ref __self_0 } => {
+                ::core::hash::Hash::hash(&*__self_0, state)
+            }
+        }
+    }
+}
+impl ::core::marker::StructuralPartialEq for Enum1 {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialEq for Enum1 {
+    #[inline]
+    fn eq(&self, other: &Enum1) -> bool {
+        match (&*self, &*other) {
+            (&Enum1::Single { x: ref __self_0 }, &Enum1::Single {
+                x: ref __arg_1_0 }) => *__self_0 == *__arg_1_0,
+        }
+    }
+    #[inline]
+    fn ne(&self, other: &Enum1) -> bool {
+        match (&*self, &*other) {
+            (&Enum1::Single { x: ref __self_0 }, &Enum1::Single {
+                x: ref __arg_1_0 }) => *__self_0 != *__arg_1_0,
+        }
+    }
+}
+impl ::core::marker::StructuralEq for Enum1 {}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Eq for Enum1 {
+    #[inline]
+    #[doc(hidden)]
+    #[no_coverage]
+    fn assert_receiver_is_total_eq(&self) -> () {
+        let _: ::core::cmp::AssertParamIsEq<u32>;
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::PartialOrd for Enum1 {
+    #[inline]
+    fn partial_cmp(&self, other: &Enum1)
+        -> ::core::option::Option<::core::cmp::Ordering> {
+        match (&*self, &*other) {
+            (&Enum1::Single { x: ref __self_0 }, &Enum1::Single {
+                x: ref __arg_1_0 }) =>
+                ::core::cmp::PartialOrd::partial_cmp(&*__self_0, &*__arg_1_0),
+        }
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::cmp::Ord for Enum1 {
+    #[inline]
+    fn cmp(&self, other: &Enum1) -> ::core::cmp::Ordering {
+        match (&*self, &*other) {
+            (&Enum1::Single { x: ref __self_0 }, &Enum1::Single {
+                x: ref __arg_1_0 }) =>
+                ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
         }
     }
 }
@@ -605,7 +623,7 @@ enum Fieldless {
 #[allow(unused_qualifications)]
 impl ::core::clone::Clone for Fieldless {
     #[inline]
-    fn clone(&self) -> Fieldless { { *self } }
+    fn clone(&self) -> Fieldless { *self }
 }
 #[automatically_derived]
 #[allow(unused_qualifications)]
@@ -614,10 +632,10 @@ impl ::core::marker::Copy for Fieldless { }
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Fieldless {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match (&*self,) {
-            (&Fieldless::A,) => ::core::fmt::Formatter::write_str(f, "A"),
-            (&Fieldless::B,) => ::core::fmt::Formatter::write_str(f, "B"),
-            (&Fieldless::C,) => ::core::fmt::Formatter::write_str(f, "C"),
+        match &*self {
+            &Fieldless::A => ::core::fmt::Formatter::write_str(f, "A"),
+            &Fieldless::B => ::core::fmt::Formatter::write_str(f, "B"),
+            &Fieldless::C => ::core::fmt::Formatter::write_str(f, "C"),
         }
     }
 }
@@ -631,7 +649,7 @@ impl ::core::default::Default for Fieldless {
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Fieldless {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match (&*self,) {
+        match &*self {
             _ => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state)
@@ -645,13 +663,11 @@ impl ::core::marker::StructuralPartialEq for Fieldless {}
 impl ::core::cmp::PartialEq for Fieldless {
     #[inline]
     fn eq(&self, other: &Fieldless) -> bool {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) { _ => true, }
-                } else { false }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) { _ => true, }
+            } else { false }
     }
 }
 impl ::core::marker::StructuralEq for Fieldless {}
@@ -661,7 +677,7 @@ impl ::core::cmp::Eq for Fieldless {
     #[inline]
     #[doc(hidden)]
     #[no_coverage]
-    fn assert_receiver_is_total_eq(&self) -> () { {} }
+    fn assert_receiver_is_total_eq(&self) -> () {}
 }
 #[automatically_derived]
 #[allow(unused_qualifications)]
@@ -669,19 +685,16 @@ impl ::core::cmp::PartialOrd for Fieldless {
     #[inline]
     fn partial_cmp(&self, other: &Fieldless)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        _ =>
-                            ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                    }
-                } else {
-                   ::core::cmp::PartialOrd::partial_cmp(&__self_vi,
-                       &__arg_1_vi)
-               }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    _ =>
+                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
+                }
+            } else {
+               ::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
+           }
     }
 }
 #[automatically_derived]
@@ -689,15 +702,11 @@ impl ::core::cmp::PartialOrd for Fieldless {
 impl ::core::cmp::Ord for Fieldless {
     #[inline]
     fn cmp(&self, other: &Fieldless) -> ::core::cmp::Ordering {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        _ => ::core::cmp::Ordering::Equal,
-                    }
-                } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) { _ => ::core::cmp::Ordering::Equal, }
+            } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
     }
 }
 
@@ -718,12 +727,8 @@ enum Mixed {
 impl ::core::clone::Clone for Mixed {
     #[inline]
     fn clone(&self) -> Mixed {
-        {
-            let _: ::core::clone::AssertParamIsClone<u32>;
-            let _: ::core::clone::AssertParamIsClone<u32>;
-            let _: ::core::clone::AssertParamIsClone<u32>;
-            *self
-        }
+        let _: ::core::clone::AssertParamIsClone<u32>;
+        *self
     }
 }
 #[automatically_derived]
@@ -733,15 +738,15 @@ impl ::core::marker::Copy for Mixed { }
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Mixed {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match (&*self,) {
-            (&Mixed::P,) => ::core::fmt::Formatter::write_str(f, "P"),
-            (&Mixed::Q,) => ::core::fmt::Formatter::write_str(f, "Q"),
-            (&Mixed::R(ref __self_0),) =>
+        match &*self {
+            &Mixed::P => ::core::fmt::Formatter::write_str(f, "P"),
+            &Mixed::Q => ::core::fmt::Formatter::write_str(f, "Q"),
+            &Mixed::R(ref __self_0) =>
                 ::core::fmt::Formatter::debug_tuple_field1_finish(f, "R",
-                    &&(*__self_0)),
-            (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },) =>
+                    &&*__self_0),
+            &Mixed::S { d1: ref __self_0, d2: ref __self_1 } =>
                 ::core::fmt::Formatter::debug_struct_field2_finish(f, "S",
-                    "d1", &&(*__self_0), "d2", &&(*__self_1)),
+                    "d1", &&*__self_0, "d2", &&*__self_1),
         }
     }
 }
@@ -755,17 +760,17 @@ impl ::core::default::Default for Mixed {
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Mixed {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match (&*self,) {
-            (&Mixed::R(ref __self_0),) => {
+        match &*self {
+            &Mixed::R(ref __self_0) => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state);
-                ::core::hash::Hash::hash(&(*__self_0), state)
+                ::core::hash::Hash::hash(&*__self_0, state)
             }
-            (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },) => {
+            &Mixed::S { d1: ref __self_0, d2: ref __self_1 } => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state);
-                ::core::hash::Hash::hash(&(*__self_0), state);
-                ::core::hash::Hash::hash(&(*__self_1), state)
+                ::core::hash::Hash::hash(&*__self_0, state);
+                ::core::hash::Hash::hash(&*__self_1, state)
             }
             _ => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
@@ -780,37 +785,33 @@ impl ::core::marker::StructuralPartialEq for Mixed {}
 impl ::core::cmp::PartialEq for Mixed {
     #[inline]
     fn eq(&self, other: &Mixed) -> bool {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
-                            (*__self_0) == (*__arg_1_0),
-                        (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
-                            &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
-                            (*__self_0) == (*__arg_1_0) && (*__self_1) == (*__arg_1_1),
-                        _ => true,
-                    }
-                } else { false }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
+                        *__self_0 == *__arg_1_0,
+                    (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
+                        &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
+                        *__self_0 == *__arg_1_0 && *__self_1 == *__arg_1_1,
+                    _ => true,
+                }
+            } else { false }
     }
     #[inline]
     fn ne(&self, other: &Mixed) -> bool {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
-                            (*__self_0) != (*__arg_1_0),
-                        (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
-                            &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
-                            (*__self_0) != (*__arg_1_0) || (*__self_1) != (*__arg_1_1),
-                        _ => false,
-                    }
-                } else { true }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
+                        *__self_0 != *__arg_1_0,
+                    (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
+                        &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
+                        *__self_0 != *__arg_1_0 || *__self_1 != *__arg_1_1,
+                    _ => false,
+                }
+            } else { true }
     }
 }
 impl ::core::marker::StructuralEq for Mixed {}
@@ -821,11 +822,7 @@ impl ::core::cmp::Eq for Mixed {
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        {
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-        }
+        let _: ::core::cmp::AssertParamIsEq<u32>;
     }
 }
 #[automatically_derived]
@@ -834,42 +831,29 @@ impl ::core::cmp::PartialOrd for Mixed {
     #[inline]
     fn partial_cmp(&self, other: &Mixed)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
-                            match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0),
-                                    &(*__arg_1_0)) {
-                                ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                    =>
-                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                cmp => cmp,
-                            },
-                        (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
-                            &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
-                            match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0),
-                                    &(*__arg_1_0)) {
-                                ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                    =>
-                                    match ::core::cmp::PartialOrd::partial_cmp(&(*__self_1),
-                                            &(*__arg_1_1)) {
-                                        ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                            =>
-                                            ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                        cmp => cmp,
-                                    },
-                                cmp => cmp,
-                            },
-                        _ =>
-                            ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                    }
-                } else {
-                   ::core::cmp::PartialOrd::partial_cmp(&__self_vi,
-                       &__arg_1_vi)
-               }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
+                        ::core::cmp::PartialOrd::partial_cmp(&*__self_0,
+                            &*__arg_1_0),
+                    (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
+                        &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
+                        match ::core::cmp::PartialOrd::partial_cmp(&*__self_0,
+                                &*__arg_1_0) {
+                            ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                                =>
+                                ::core::cmp::PartialOrd::partial_cmp(&*__self_1,
+                                    &*__arg_1_1),
+                            cmp => cmp,
+                        },
+                    _ =>
+                        ::core::option::Option::Some(::core::cmp::Ordering::Equal),
+                }
+            } else {
+               ::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
+           }
     }
 }
 #[automatically_derived]
@@ -877,32 +861,22 @@ impl ::core::cmp::PartialOrd for Mixed {
 impl ::core::cmp::Ord for Mixed {
     #[inline]
     fn cmp(&self, other: &Mixed) -> ::core::cmp::Ordering {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
-                            match ::core::cmp::Ord::cmp(&(*__self_0), &(*__arg_1_0)) {
-                                ::core::cmp::Ordering::Equal =>
-                                    ::core::cmp::Ordering::Equal,
-                                cmp => cmp,
-                            },
-                        (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
-                            &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
-                            match ::core::cmp::Ord::cmp(&(*__self_0), &(*__arg_1_0)) {
-                                ::core::cmp::Ordering::Equal =>
-                                    match ::core::cmp::Ord::cmp(&(*__self_1), &(*__arg_1_1)) {
-                                        ::core::cmp::Ordering::Equal =>
-                                            ::core::cmp::Ordering::Equal,
-                                        cmp => cmp,
-                                    },
-                                cmp => cmp,
-                            },
-                        _ => ::core::cmp::Ordering::Equal,
-                    }
-                } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Mixed::R(ref __self_0), &Mixed::R(ref __arg_1_0)) =>
+                        ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
+                    (&Mixed::S { d1: ref __self_0, d2: ref __self_1 },
+                        &Mixed::S { d1: ref __arg_1_0, d2: ref __arg_1_1 }) =>
+                        match ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0) {
+                            ::core::cmp::Ordering::Equal =>
+                                ::core::cmp::Ord::cmp(&*__self_1, &*__arg_1_1),
+                            cmp => cmp,
+                        },
+                    _ => ::core::cmp::Ordering::Equal,
+                }
+            } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
     }
 }
 
@@ -914,13 +888,13 @@ enum Fielded { X(u32), Y(bool), Z(Option<i32>), }
 impl ::core::clone::Clone for Fielded {
     #[inline]
     fn clone(&self) -> Fielded {
-        match (&*self,) {
-            (&Fielded::X(ref __self_0),) =>
-                Fielded::X(::core::clone::Clone::clone(&(*__self_0))),
-            (&Fielded::Y(ref __self_0),) =>
-                Fielded::Y(::core::clone::Clone::clone(&(*__self_0))),
-            (&Fielded::Z(ref __self_0),) =>
-                Fielded::Z(::core::clone::Clone::clone(&(*__self_0))),
+        match &*self {
+            &Fielded::X(ref __self_0) =>
+                Fielded::X(::core::clone::Clone::clone(&*__self_0)),
+            &Fielded::Y(ref __self_0) =>
+                Fielded::Y(::core::clone::Clone::clone(&*__self_0)),
+            &Fielded::Z(ref __self_0) =>
+                Fielded::Z(::core::clone::Clone::clone(&*__self_0)),
         }
     }
 }
@@ -928,16 +902,16 @@ impl ::core::clone::Clone for Fielded {
 #[allow(unused_qualifications)]
 impl ::core::fmt::Debug for Fielded {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        match (&*self,) {
-            (&Fielded::X(ref __self_0),) =>
+        match &*self {
+            &Fielded::X(ref __self_0) =>
                 ::core::fmt::Formatter::debug_tuple_field1_finish(f, "X",
-                    &&(*__self_0)),
-            (&Fielded::Y(ref __self_0),) =>
+                    &&*__self_0),
+            &Fielded::Y(ref __self_0) =>
                 ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Y",
-                    &&(*__self_0)),
-            (&Fielded::Z(ref __self_0),) =>
+                    &&*__self_0),
+            &Fielded::Z(ref __self_0) =>
                 ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Z",
-                    &&(*__self_0)),
+                    &&*__self_0),
         }
     }
 }
@@ -945,21 +919,21 @@ impl ::core::fmt::Debug for Fielded {
 #[allow(unused_qualifications)]
 impl ::core::hash::Hash for Fielded {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        match (&*self,) {
-            (&Fielded::X(ref __self_0),) => {
+        match &*self {
+            &Fielded::X(ref __self_0) => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state);
-                ::core::hash::Hash::hash(&(*__self_0), state)
+                ::core::hash::Hash::hash(&*__self_0, state)
             }
-            (&Fielded::Y(ref __self_0),) => {
+            &Fielded::Y(ref __self_0) => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state);
-                ::core::hash::Hash::hash(&(*__self_0), state)
+                ::core::hash::Hash::hash(&*__self_0, state)
             }
-            (&Fielded::Z(ref __self_0),) => {
+            &Fielded::Z(ref __self_0) => {
                 ::core::hash::Hash::hash(&::core::intrinsics::discriminant_value(self),
                     state);
-                ::core::hash::Hash::hash(&(*__self_0), state)
+                ::core::hash::Hash::hash(&*__self_0, state)
             }
         }
     }
@@ -970,39 +944,35 @@ impl ::core::marker::StructuralPartialEq for Fielded {}
 impl ::core::cmp::PartialEq for Fielded {
     #[inline]
     fn eq(&self, other: &Fielded) -> bool {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
-                            (*__self_0) == (*__arg_1_0),
-                        (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
-                            (*__self_0) == (*__arg_1_0),
-                        (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
-                            (*__self_0) == (*__arg_1_0),
-                        _ => unsafe { ::core::intrinsics::unreachable() }
-                    }
-                } else { false }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
+                        *__self_0 == *__arg_1_0,
+                    (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
+                        *__self_0 == *__arg_1_0,
+                    (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
+                        *__self_0 == *__arg_1_0,
+                    _ => unsafe { ::core::intrinsics::unreachable() }
+                }
+            } else { false }
     }
     #[inline]
     fn ne(&self, other: &Fielded) -> bool {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
-                            (*__self_0) != (*__arg_1_0),
-                        (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
-                            (*__self_0) != (*__arg_1_0),
-                        (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
-                            (*__self_0) != (*__arg_1_0),
-                        _ => unsafe { ::core::intrinsics::unreachable() }
-                    }
-                } else { true }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
+                        *__self_0 != *__arg_1_0,
+                    (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
+                        *__self_0 != *__arg_1_0,
+                    (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
+                        *__self_0 != *__arg_1_0,
+                    _ => unsafe { ::core::intrinsics::unreachable() }
+                }
+            } else { true }
     }
 }
 impl ::core::marker::StructuralEq for Fielded {}
@@ -1013,11 +983,9 @@ impl ::core::cmp::Eq for Fielded {
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        {
-            let _: ::core::cmp::AssertParamIsEq<u32>;
-            let _: ::core::cmp::AssertParamIsEq<bool>;
-            let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
-        }
+        let _: ::core::cmp::AssertParamIsEq<u32>;
+        let _: ::core::cmp::AssertParamIsEq<bool>;
+        let _: ::core::cmp::AssertParamIsEq<Option<i32>>;
     }
 }
 #[automatically_derived]
@@ -1026,42 +994,24 @@ impl ::core::cmp::PartialOrd for Fielded {
     #[inline]
     fn partial_cmp(&self, other: &Fielded)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
-                            match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0),
-                                    &(*__arg_1_0)) {
-                                ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                    =>
-                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                cmp => cmp,
-                            },
-                        (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
-                            match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0),
-                                    &(*__arg_1_0)) {
-                                ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                    =>
-                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                cmp => cmp,
-                            },
-                        (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
-                            match ::core::cmp::PartialOrd::partial_cmp(&(*__self_0),
-                                    &(*__arg_1_0)) {
-                                ::core::option::Option::Some(::core::cmp::Ordering::Equal)
-                                    =>
-                                    ::core::option::Option::Some(::core::cmp::Ordering::Equal),
-                                cmp => cmp,
-                            },
-                        _ => unsafe { ::core::intrinsics::unreachable() }
-                    }
-                } else {
-                   ::core::cmp::PartialOrd::partial_cmp(&__self_vi,
-                       &__arg_1_vi)
-               }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
+                        ::core::cmp::PartialOrd::partial_cmp(&*__self_0,
+                            &*__arg_1_0),
+                    (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
+                        ::core::cmp::PartialOrd::partial_cmp(&*__self_0,
+                            &*__arg_1_0),
+                    (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
+                        ::core::cmp::PartialOrd::partial_cmp(&*__self_0,
+                            &*__arg_1_0),
+                    _ => unsafe { ::core::intrinsics::unreachable() }
+                }
+            } else {
+               ::core::cmp::PartialOrd::partial_cmp(&__self_vi, &__arg_1_vi)
+           }
     }
 }
 #[automatically_derived]
@@ -1069,32 +1019,37 @@ impl ::core::cmp::PartialOrd for Fielded {
 impl ::core::cmp::Ord for Fielded {
     #[inline]
     fn cmp(&self, other: &Fielded) -> ::core::cmp::Ordering {
-        {
-            let __self_vi = ::core::intrinsics::discriminant_value(&*self);
-            let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
-            if __self_vi == __arg_1_vi {
-                    match (&*self, &*other) {
-                        (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
-                            match ::core::cmp::Ord::cmp(&(*__self_0), &(*__arg_1_0)) {
-                                ::core::cmp::Ordering::Equal =>
-                                    ::core::cmp::Ordering::Equal,
-                                cmp => cmp,
-                            },
-                        (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
-                            match ::core::cmp::Ord::cmp(&(*__self_0), &(*__arg_1_0)) {
-                                ::core::cmp::Ordering::Equal =>
-                                    ::core::cmp::Ordering::Equal,
-                                cmp => cmp,
-                            },
-                        (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
-                            match ::core::cmp::Ord::cmp(&(*__self_0), &(*__arg_1_0)) {
-                                ::core::cmp::Ordering::Equal =>
-                                    ::core::cmp::Ordering::Equal,
-                                cmp => cmp,
-                            },
-                        _ => unsafe { ::core::intrinsics::unreachable() }
-                    }
-                } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
-        }
+        let __self_vi = ::core::intrinsics::discriminant_value(&*self);
+        let __arg_1_vi = ::core::intrinsics::discriminant_value(&*other);
+        if __self_vi == __arg_1_vi {
+                match (&*self, &*other) {
+                    (&Fielded::X(ref __self_0), &Fielded::X(ref __arg_1_0)) =>
+                        ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
+                    (&Fielded::Y(ref __self_0), &Fielded::Y(ref __arg_1_0)) =>
+                        ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
+                    (&Fielded::Z(ref __self_0), &Fielded::Z(ref __arg_1_0)) =>
+                        ::core::cmp::Ord::cmp(&*__self_0, &*__arg_1_0),
+                    _ => unsafe { ::core::intrinsics::unreachable() }
+                }
+            } else { ::core::cmp::Ord::cmp(&__self_vi, &__arg_1_vi) }
     }
 }
+
+// A union. Most builtin traits are not derivable for unions.
+pub union Union {
+    pub b: bool,
+    pub u: u32,
+    pub i: i32,
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::clone::Clone for Union {
+    #[inline]
+    fn clone(&self) -> Union {
+        let _: ::core::clone::AssertParamIsCopy<Self>;
+        *self
+    }
+}
+#[automatically_derived]
+#[allow(unused_qualifications)]
+impl ::core::marker::Copy for Union { }
diff --git a/src/test/ui/diagnostic-width/flag-human.rs b/src/test/ui/diagnostic-width/flag-human.rs
new file mode 100644
index 00000000000..289bfbabd94
--- /dev/null
+++ b/src/test/ui/diagnostic-width/flag-human.rs
@@ -0,0 +1,9 @@
+// compile-flags: --diagnostic-width=20
+
+// This test checks that `-Z output-width` effects the human error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/terminal-width/flag-human.stderr b/src/test/ui/diagnostic-width/flag-human.stderr
index 393dcf2b828..393dcf2b828 100644
--- a/src/test/ui/terminal-width/flag-human.stderr
+++ b/src/test/ui/diagnostic-width/flag-human.stderr
diff --git a/src/test/ui/diagnostic-width/flag-json.rs b/src/test/ui/diagnostic-width/flag-json.rs
new file mode 100644
index 00000000000..51a1fb447c7
--- /dev/null
+++ b/src/test/ui/diagnostic-width/flag-json.rs
@@ -0,0 +1,9 @@
+// compile-flags: --diagnostic-width=20 --error-format=json
+
+// This test checks that `-Z output-width` effects the JSON error output by restricting it to an
+// arbitrarily low value so that the effect is visible.
+
+fn main() {
+    let _: () = 42;
+    //~^ ERROR arguments to this function are incorrect
+}
diff --git a/src/test/ui/terminal-width/flag-json.stderr b/src/test/ui/diagnostic-width/flag-json.stderr
index 93c246cb3f5..b21391d1640 100644
--- a/src/test/ui/terminal-width/flag-json.stderr
+++ b/src/test/ui/diagnostic-width/flag-json.stderr
@@ -24,7 +24,7 @@ This error occurs when an expression was used in a place where the compiler
 expected an expression of a different type. It can occur in several cases, the
 most common being when calling a function and passing an argument which has a
 different type than the matching type in the function declaration.
-"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":"    let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":239,"byte_end":241,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":"    let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
+"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":243,"byte_end":245,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":"    let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":238,"byte_end":240,"line_start":7,"line_end":7,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":"    let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types
   --> $DIR/flag-json.rs:7:17
    |
 LL | ..._: () = 42;
diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
index 1989ea88635..1989ea88635 100644
--- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.rs
+++ b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.rs
diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr
index bf277362dba..bf277362dba 100644
--- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
+++ b/src/test/ui/diagnostic-width/non-1-width-unicode-multiline-label.stderr
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.rs
index abd9e189a75..abd9e189a75 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming-2.rs
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.rs
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.stderr
index 5dbb9ce45ee..5dbb9ce45ee 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming-2.stderr
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming-2.stderr
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.rs
index 8d4d1b16279..8d4d1b16279 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.rs
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.rs
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr
index 1e5ff939832..1e5ff939832 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming-unicode.stderr
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming-unicode.stderr
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.rs b/src/test/ui/diagnostic-width/non-whitespace-trimming.rs
index f6c8d345c65..f6c8d345c65 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming.rs
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming.rs
diff --git a/src/test/ui/terminal-width/non-whitespace-trimming.stderr b/src/test/ui/diagnostic-width/non-whitespace-trimming.stderr
index c4ff0e16890..c4ff0e16890 100644
--- a/src/test/ui/terminal-width/non-whitespace-trimming.stderr
+++ b/src/test/ui/diagnostic-width/non-whitespace-trimming.stderr
diff --git a/src/test/ui/terminal-width/tabs-trimming.rs b/src/test/ui/diagnostic-width/tabs-trimming.rs
index ade21753b45..ade21753b45 100644
--- a/src/test/ui/terminal-width/tabs-trimming.rs
+++ b/src/test/ui/diagnostic-width/tabs-trimming.rs
diff --git a/src/test/ui/terminal-width/tabs-trimming.stderr b/src/test/ui/diagnostic-width/tabs-trimming.stderr
index 6c8d9afc73b..6c8d9afc73b 100644
--- a/src/test/ui/terminal-width/tabs-trimming.stderr
+++ b/src/test/ui/diagnostic-width/tabs-trimming.stderr
diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.rs b/src/test/ui/diagnostic-width/whitespace-trimming-2.rs
index c68f678aab3..c68f678aab3 100644
--- a/src/test/ui/terminal-width/whitespace-trimming-2.rs
+++ b/src/test/ui/diagnostic-width/whitespace-trimming-2.rs
diff --git a/src/test/ui/terminal-width/whitespace-trimming-2.stderr b/src/test/ui/diagnostic-width/whitespace-trimming-2.stderr
index 97a64e603b7..97a64e603b7 100644
--- a/src/test/ui/terminal-width/whitespace-trimming-2.stderr
+++ b/src/test/ui/diagnostic-width/whitespace-trimming-2.stderr
diff --git a/src/test/ui/terminal-width/whitespace-trimming.rs b/src/test/ui/diagnostic-width/whitespace-trimming.rs
index f747bcf17e0..f747bcf17e0 100644
--- a/src/test/ui/terminal-width/whitespace-trimming.rs
+++ b/src/test/ui/diagnostic-width/whitespace-trimming.rs
diff --git a/src/test/ui/terminal-width/whitespace-trimming.stderr b/src/test/ui/diagnostic-width/whitespace-trimming.stderr
index e296d48893c..e296d48893c 100644
--- a/src/test/ui/terminal-width/whitespace-trimming.stderr
+++ b/src/test/ui/diagnostic-width/whitespace-trimming.stderr
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
index bd5b9f4b49e..bdbfa4dd713 100644
--- a/src/test/ui/did_you_mean/issue-40006.stderr
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -88,7 +88,7 @@ error[E0599]: no method named `hello_method` found for struct `S` in the current
   --> $DIR/issue-40006.rs:38:7
    |
 LL | struct S;
-   |        - method `hello_method` not found for this struct
+   | -------- method `hello_method` not found for this struct
 ...
 LL |     S.hello_method();
    |       ^^^^^^^^^^^^ method not found in `S`
diff --git a/src/test/ui/dont-suggest-private-trait-method.stderr b/src/test/ui/dont-suggest-private-trait-method.stderr
index d85fd526d52..1492670dc63 100644
--- a/src/test/ui/dont-suggest-private-trait-method.stderr
+++ b/src/test/ui/dont-suggest-private-trait-method.stderr
@@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `new` found for struct `T` in
   --> $DIR/dont-suggest-private-trait-method.rs:4:8
    |
 LL | struct T;
-   |        - function or associated item `new` not found for this struct
+   | -------- function or associated item `new` not found for this struct
 ...
 LL |     T::new();
    |        ^^^ function or associated item not found in `T`
diff --git a/src/test/ui/drop/repeat-drop-2.rs b/src/test/ui/drop/repeat-drop-2.rs
index 2e7855328ec..59d5ef20205 100644
--- a/src/test/ui/drop/repeat-drop-2.rs
+++ b/src/test/ui/drop/repeat-drop-2.rs
@@ -9,7 +9,7 @@ const _: [String; 0] = [String::new(); 0];
 
 fn must_be_init() {
     let x: u8;
-    let _ = [x; 0]; //~ ERROR: use of possibly-uninitialized variable: `x`
+    let _ = [x; 0]; //~ ERROR E0381
 }
 
 fn main() {}
diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr
index cdc58180c37..48fa2bfa975 100644
--- a/src/test/ui/drop/repeat-drop-2.stderr
+++ b/src/test/ui/drop/repeat-drop-2.stderr
@@ -17,11 +17,13 @@ LL | const _: [String; 0] = [String::new(); 0];
    |                        |constants cannot evaluate destructors
    |                        value is dropped here
 
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/repeat-drop-2.rs:12:14
    |
+LL |     let x: u8;
+   |         - binding declared here but left uninitialized
 LL |     let _ = [x; 0];
-   |              ^ use of possibly-uninitialized `x`
+   |              ^ `x` used here but it isn't initialized
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs
index 6ca5f5e3c5f..43c1c775978 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.rs
@@ -23,5 +23,4 @@ enum FingerTree<T:'static> {
 fn main() {
     let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
         FingerTree::Single(1);
-    //~^ ERROR overflow while adding drop-check rules for FingerTree
 }
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
index 5df69e4649d..c447e2f7987 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_1.stderr
@@ -6,13 +6,5 @@ LL |     let ft =
    |
    = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
-error[E0320]: overflow while adding drop-check rules for FingerTree<i32>
-  --> $DIR/dropck_no_diverge_on_nonregular_1.rs:25:9
-   |
-LL |         FingerTree::Single(1);
-   |         ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs
index d34f7e326d1..edd07652e53 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.rs
@@ -22,5 +22,4 @@ enum FingerTree<T:'static> {
 fn main() {
     let ft = //~ ERROR overflow while adding drop-check rules for FingerTree
         FingerTree::Single(1);
-    //~^ ERROR overflow while adding drop-check rules for FingerTree
 }
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
index d34097d4010..cd4706dd903 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_2.stderr
@@ -6,13 +6,5 @@ LL |     let ft =
    |
    = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
-error[E0320]: overflow while adding drop-check rules for FingerTree<i32>
-  --> $DIR/dropck_no_diverge_on_nonregular_2.rs:24:9
-   |
-LL |         FingerTree::Single(1);
-   |         ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<i32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs
index 558b4342da7..af7402ca4a1 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs
@@ -31,6 +31,5 @@ enum Wrapper<T:'static> {
 fn main() {
     let w = //~ ERROR overflow while adding drop-check rules for Option
         Some(Wrapper::Simple::<u32>);
-    //~^ ERROR overflow while adding drop-check rules for Option
-    //~| ERROR overflow while adding drop-check rules for Wrapper
+    //~^ ERROR overflow while adding drop-check rules for Wrapper
 }
diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
index b24e1d1bf79..18cd1b6cd41 100644
--- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
+++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr
@@ -6,14 +6,6 @@ LL |     let w =
    |
    = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
-error[E0320]: overflow while adding drop-check rules for Option<Wrapper<u32>>
-  --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9
-   |
-LL |         Some(Wrapper::Simple::<u32>);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
-
 error[E0320]: overflow while adding drop-check rules for Wrapper<u32>
   --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:14
    |
@@ -22,5 +14,5 @@ LL |         Some(Wrapper::Simple::<u32>);
    |
    = note: overflowed on FingerTree<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<Node<u32>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/empty/empty-struct-braces-pat-3.stderr b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
index 60266bb3580..615e7fb4aae 100644
--- a/src/test/ui/empty/empty-struct-braces-pat-3.stderr
+++ b/src/test/ui/empty/empty-struct-braces-pat-3.stderr
@@ -19,7 +19,7 @@ LL |     XEmpty3 {},
    |     ------- `XE::XEmpty3` defined here
 LL |     XEmpty4,
 LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |     ------- similarly named tuple variant `XEmpty5` defined here
    |
 help: use struct pattern syntax instead
    |
@@ -51,7 +51,7 @@ LL |     XEmpty3 {},
    |     ------- `XE::XEmpty3` defined here
 LL |     XEmpty4,
 LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |     ------- similarly named tuple variant `XEmpty5` defined here
    |
 help: use struct pattern syntax instead
    |
diff --git a/src/test/ui/empty/empty-struct-tuple-pat.stderr b/src/test/ui/empty/empty-struct-tuple-pat.stderr
index e696b85c6cc..8d0f75d204c 100644
--- a/src/test/ui/empty/empty-struct-tuple-pat.stderr
+++ b/src/test/ui/empty/empty-struct-tuple-pat.stderr
@@ -5,7 +5,10 @@ LL | struct Empty2();
    | ---------------- the tuple struct `Empty2` is defined here
 ...
 LL |         Empty2 => ()
-   |         ^^^^^^ cannot be named the same as a tuple struct
+   |         ^^^^^^
+   |         |
+   |         cannot be named the same as a tuple struct
+   |         help: try specify the pattern arguments: `Empty2(..)`
 
 error[E0530]: match bindings cannot shadow tuple structs
   --> $DIR/empty-struct-tuple-pat.rs:25:9
@@ -14,7 +17,10 @@ LL | use empty_struct::*;
    |     --------------- the tuple struct `XEmpty6` is imported here
 ...
 LL |         XEmpty6 => ()
-   |         ^^^^^^^ cannot be named the same as a tuple struct
+   |         ^^^^^^^
+   |         |
+   |         cannot be named the same as a tuple struct
+   |         help: try specify the pattern arguments: `XEmpty6(..)`
 
 error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::Empty4`
   --> $DIR/empty-struct-tuple-pat.rs:29:9
@@ -36,7 +42,7 @@ LL |         XE::XEmpty5 => (),
 LL |     XEmpty4,
    |     ------- similarly named unit variant `XEmpty4` defined here
 LL |     XEmpty5(),
-   |     --------- `XE::XEmpty5` defined here
+   |     ------- `XE::XEmpty5` defined here
    |
 help: use the tuple variant pattern syntax instead
    |
diff --git a/src/test/ui/empty/empty-struct-unit-pat.stderr b/src/test/ui/empty/empty-struct-unit-pat.stderr
index acd1070d5d6..5c0b4cffa94 100644
--- a/src/test/ui/empty/empty-struct-unit-pat.stderr
+++ b/src/test/ui/empty/empty-struct-unit-pat.stderr
@@ -108,7 +108,7 @@ LL |         XE::XEmpty4() => (),
 LL |     XEmpty4,
    |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |     ------- similarly named tuple variant `XEmpty5` defined here
    |
 help: use this syntax instead
    |
@@ -139,7 +139,7 @@ LL |         XE::XEmpty4(..) => (),
 LL |     XEmpty4,
    |     ------- `XE::XEmpty4` defined here
 LL |     XEmpty5(),
-   |     --------- similarly named tuple variant `XEmpty5` defined here
+   |     ------- similarly named tuple variant `XEmpty5` defined here
    |
 help: use this syntax instead
    |
diff --git a/src/test/ui/enum/suggest-default-attribute.rs b/src/test/ui/enum/suggest-default-attribute.rs
new file mode 100644
index 00000000000..1d7567e60a5
--- /dev/null
+++ b/src/test/ui/enum/suggest-default-attribute.rs
@@ -0,0 +1,8 @@
+pub enum Test { //~ HELP consider adding a derive
+    #[default]
+    //~^ ERROR cannot find attribute `default` in this scope
+    First,
+    Second,
+}
+
+fn main() {}
diff --git a/src/test/ui/enum/suggest-default-attribute.stderr b/src/test/ui/enum/suggest-default-attribute.stderr
new file mode 100644
index 00000000000..fb830d3f78b
--- /dev/null
+++ b/src/test/ui/enum/suggest-default-attribute.stderr
@@ -0,0 +1,14 @@
+error: cannot find attribute `default` in this scope
+  --> $DIR/suggest-default-attribute.rs:2:7
+   |
+LL |     #[default]
+   |       ^^^^^^^
+   |
+help: consider adding a derive
+   |
+LL + #[derive(Default)]
+LL ~ pub enum Test {
+   |
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/error-codes/E0396-fixed.stderr b/src/test/ui/error-codes/E0396-fixed.stderr
index 3eb291f0f70..2efbd6989ad 100644
--- a/src/test/ui/error-codes/E0396-fixed.stderr
+++ b/src/test/ui/error-codes/E0396-fixed.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/E0396-fixed.rs:5:28
    |
 LL | const VALUE: u8 = unsafe { *REG_ADDR };
-   |                            ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df is not a valid pointer
+   |                            ^^^^^^^^^ dereferencing pointer failed: 0x5f3759df[noalloc] is a dangling pointer (it has no provenance)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0599.stderr b/src/test/ui/error-codes/E0599.stderr
index 49ca1d6353d..a1fb58f483f 100644
--- a/src/test/ui/error-codes/E0599.stderr
+++ b/src/test/ui/error-codes/E0599.stderr
@@ -2,7 +2,7 @@ error[E0599]: no associated item named `NotEvenReal` found for struct `Foo` in t
   --> $DIR/E0599.rs:4:20
    |
 LL | struct Foo;
-   |        --- associated item `NotEvenReal` not found for this struct
+   | ---------- associated item `NotEvenReal` not found for this struct
 ...
 LL |     || if let Foo::NotEvenReal() = Foo {};
    |                    ^^^^^^^^^^^ associated item not found in `Foo`
diff --git a/src/test/ui/extern/not-in-block.rs b/src/test/ui/extern/not-in-block.rs
new file mode 100644
index 00000000000..d3bcafdef7b
--- /dev/null
+++ b/src/test/ui/extern/not-in-block.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+
+extern fn none_fn(x: bool) -> i32;
+//~^ ERROR free function without a body
+extern "C" fn c_fn(x: bool) -> i32;
+//~^ ERROR free function without a body
diff --git a/src/test/ui/extern/not-in-block.stderr b/src/test/ui/extern/not-in-block.stderr
new file mode 100644
index 00000000000..2544949ab17
--- /dev/null
+++ b/src/test/ui/extern/not-in-block.stderr
@@ -0,0 +1,32 @@
+error: free function without a body
+  --> $DIR/not-in-block.rs:3:1
+   |
+LL | extern fn none_fn(x: bool) -> i32;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: provide a definition for the function
+   |
+LL | extern fn none_fn(x: bool) -> i32 { <body> }
+   |                                   ~~~~~~~~~~
+help: if you meant to declare an externally defined function, use an `extern` block
+   |
+LL | extern { fn none_fn(x: bool) -> i32; }
+   | ~~~~~~~~                             +
+
+error: free function without a body
+  --> $DIR/not-in-block.rs:5:1
+   |
+LL | extern "C" fn c_fn(x: bool) -> i32;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: provide a definition for the function
+   |
+LL | extern "C" fn c_fn(x: bool) -> i32 { <body> }
+   |                                    ~~~~~~~~~~
+help: if you meant to declare an externally defined function, use an `extern` block
+   |
+LL | extern "C" { fn c_fn(x: bool) -> i32; }
+   | ~~~~~~~~~~~~                          +
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/fn/fn-closure-mutable-capture.rs b/src/test/ui/fn/fn-closure-mutable-capture.rs
index 0e427b9cf31..97141886fe7 100644
--- a/src/test/ui/fn/fn-closure-mutable-capture.rs
+++ b/src/test/ui/fn/fn-closure-mutable-capture.rs
@@ -6,6 +6,7 @@ pub fn foo() {
     //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure
     //~| NOTE cannot assign
     //~| NOTE expects `Fn` instead of `FnMut`
+    //~| NOTE in this closure
 }
 
 fn main() {}
diff --git a/src/test/ui/fn/fn-closure-mutable-capture.stderr b/src/test/ui/fn/fn-closure-mutable-capture.stderr
index d23c363ae15..03e3d545a99 100644
--- a/src/test/ui/fn/fn-closure-mutable-capture.stderr
+++ b/src/test/ui/fn/fn-closure-mutable-capture.stderr
@@ -5,8 +5,9 @@ LL | pub fn bar<F: Fn()>(_f: F) {}
    |                         - change this to accept `FnMut` instead of `Fn`
 ...
 LL |     bar(move || x = 1);
-   |     ---         ^^^^^ cannot assign
-   |     |
+   |     --- ------- ^^^^^ cannot assign
+   |     |   |
+   |     |   in this closure
    |     expects `Fn` instead of `FnMut`
 
 error: aborting due to previous error
diff --git a/src/test/ui/functions-closures/fn-help-with-err.stderr b/src/test/ui/functions-closures/fn-help-with-err.stderr
index 3e42cb1fb6e..06e29daef45 100644
--- a/src/test/ui/functions-closures/fn-help-with-err.stderr
+++ b/src/test/ui/functions-closures/fn-help-with-err.stderr
@@ -10,11 +10,11 @@ error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the curre
 LL |     arc.blablabla();
    |         ^^^^^^^^^ method not found in `Arc<_>`
 
-error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` in the current scope
+error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>` in the current scope
   --> $DIR/fn-help-with-err.rs:12:10
    |
 LL |     arc2.blablabla();
-   |     ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
+   |     ---- ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:38]>`
    |     |
    |     this is a function, perhaps you wish to call it
 
diff --git a/src/test/ui/generator/drop-yield-twice.stderr b/src/test/ui/generator/drop-yield-twice.stderr
index f821f2f4005..5bc6ea5600f 100644
--- a/src/test/ui/generator/drop-yield-twice.stderr
+++ b/src/test/ui/generator/drop-yield-twice.stderr
@@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely
 LL |     assert_send(|| {
    |     ^^^^^^^^^^^ generator is not `Send`
    |
-   = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 12:6]`, the trait `Send` is not implemented for `Foo`
+   = help: within `[generator@$DIR/drop-yield-twice.rs:7:17: 7:19]`, the trait `Send` is not implemented for `Foo`
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/drop-yield-twice.rs:9:9
    |
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
index 62a7b37a5a3..2a39a08ee39 100644
--- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 15:36]`
   --> $DIR/generator-yielding-or-returning-itself.rs:15:5
    |
 LL |     want_cyclic_generator_return(|| {
@@ -16,7 +16,7 @@ LL | pub fn want_cyclic_generator_return<T>(_: T)
 LL |     where T: Generator<Yield = (), Return = T>
    |                                    ^^^^^^^^^^ required by this bound in `want_cyclic_generator_return`
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 28:35]`
   --> $DIR/generator-yielding-or-returning-itself.rs:28:5
    |
 LL |     want_cyclic_generator_yield(|| {
diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr
index 83f068c2076..1d5b97e984f 100644
--- a/src/test/ui/generator/issue-68112.stderr
+++ b/src/test/ui/generator/issue-68112.stderr
@@ -33,11 +33,8 @@ LL |     require_send(send_gen);
 note: required because it's used within this generator
   --> $DIR/issue-68112.rs:48:5
    |
-LL | /     || {
-LL | |         yield;
-LL | |         t
-LL | |     }
-   | |_____^
+LL |     || {
+   |     ^^
 note: required because it appears within the type `impl Generator<Return = Arc<RefCell<i32>>>`
   --> $DIR/issue-68112.rs:45:30
    |
@@ -52,12 +49,8 @@ LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>>
 note: required because it's used within this generator
   --> $DIR/issue-68112.rs:59:20
    |
-LL |       let send_gen = || {
-   |  ____________________^
-LL | |         let _non_send_gen = make_non_send_generator2();
-LL | |         yield;
-LL | |     };
-   | |_____^
+LL |     let send_gen = || {
+   |                    ^^
 note: required by a bound in `require_send`
   --> $DIR/issue-68112.rs:22:25
    |
diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr
index edf9ee628a2..0b31bb4fdb1 100644
--- a/src/test/ui/generator/not-send-sync.stderr
+++ b/src/test/ui/generator/not-send-sync.stderr
@@ -9,13 +9,8 @@ LL |     assert_send(|| {
 note: required because it's used within this generator
   --> $DIR/not-send-sync.rs:16:17
    |
-LL |       assert_send(|| {
-   |  _________________^
-LL | |
-LL | |         drop(&a);
-LL | |         yield;
-LL | |     });
-   | |_____^
+LL |     assert_send(|| {
+   |                 ^^
 note: required by a bound in `assert_send`
   --> $DIR/not-send-sync.rs:7:23
    |
@@ -28,7 +23,7 @@ error: generator cannot be shared between threads safely
 LL |     assert_sync(|| {
    |     ^^^^^^^^^^^ generator is not `Sync`
    |
-   = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6]`, the trait `Sync` is not implemented for `Cell<i32>`
+   = help: within `[generator@$DIR/not-send-sync.rs:9:17: 9:19]`, the trait `Sync` is not implemented for `Cell<i32>`
 note: generator is not `Sync` as this value is used across a yield
   --> $DIR/not-send-sync.rs:12:9
    |
diff --git a/src/test/ui/generator/partial-drop.stderr b/src/test/ui/generator/partial-drop.stderr
index 16b34c917ec..1004fc64da9 100644
--- a/src/test/ui/generator/partial-drop.stderr
+++ b/src/test/ui/generator/partial-drop.stderr
@@ -4,7 +4,7 @@ error: generator cannot be sent between threads safely
 LL |     assert_send(|| {
    |     ^^^^^^^^^^^ generator is not `Send`
    |
-   = help: within `[generator@$DIR/partial-drop.rs:14:17: 20:6]`, the trait `Send` is not implemented for `Foo`
+   = help: within `[generator@$DIR/partial-drop.rs:14:17: 14:19]`, the trait `Send` is not implemented for `Foo`
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/partial-drop.rs:19:9
    |
@@ -27,7 +27,7 @@ error: generator cannot be sent between threads safely
 LL |     assert_send(|| {
    |     ^^^^^^^^^^^ generator is not `Send`
    |
-   = help: within `[generator@$DIR/partial-drop.rs:22:17: 30:6]`, the trait `Send` is not implemented for `Foo`
+   = help: within `[generator@$DIR/partial-drop.rs:22:17: 22:19]`, the trait `Send` is not implemented for `Foo`
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/partial-drop.rs:29:9
    |
@@ -50,7 +50,7 @@ error: generator cannot be sent between threads safely
 LL |     assert_send(|| {
    |     ^^^^^^^^^^^ generator is not `Send`
    |
-   = help: within `[generator@$DIR/partial-drop.rs:32:17: 39:6]`, the trait `Send` is not implemented for `Foo`
+   = help: within `[generator@$DIR/partial-drop.rs:32:17: 32:19]`, the trait `Send` is not implemented for `Foo`
 note: generator is not `Send` as this value is used across a yield
   --> $DIR/partial-drop.rs:38:9
    |
diff --git a/src/test/ui/generator/partial-initialization-across-yield.rs b/src/test/ui/generator/partial-initialization-across-yield.rs
index 8b757214203..65d9e6d39ca 100644
--- a/src/test/ui/generator/partial-initialization-across-yield.rs
+++ b/src/test/ui/generator/partial-initialization-across-yield.rs
@@ -9,8 +9,7 @@ struct T(i32, i32);
 fn test_tuple() {
     let _ = || {
         let mut t: (i32, i32);
-        t.0 = 42;
-        //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+        t.0 = 42; //~ ERROR E0381
         yield;
         t.1 = 88;
         let _ = t;
@@ -20,8 +19,7 @@ fn test_tuple() {
 fn test_tuple_struct() {
     let _ = || {
         let mut t: T;
-        t.0 = 42;
-        //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+        t.0 = 42; //~ ERROR E0381
         yield;
         t.1 = 88;
         let _ = t;
@@ -31,8 +29,7 @@ fn test_tuple_struct() {
 fn test_struct() {
     let _ = || {
         let mut t: S;
-        t.x = 42;
-        //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+        t.x = 42; //~ ERROR E0381
         yield;
         t.y = 88;
         let _ = t;
diff --git a/src/test/ui/generator/partial-initialization-across-yield.stderr b/src/test/ui/generator/partial-initialization-across-yield.stderr
index 66b86488eae..3f9f1c046ba 100644
--- a/src/test/ui/generator/partial-initialization-across-yield.stderr
+++ b/src/test/ui/generator/partial-initialization-across-yield.stderr
@@ -1,20 +1,32 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
+error[E0381]: partially assigned binding `t` isn't fully initialized
   --> $DIR/partial-initialization-across-yield.rs:12:9
    |
+LL |         let mut t: (i32, i32);
+   |             ----- binding declared here but left uninitialized
 LL |         t.0 = 42;
-   |         ^^^^^^^^ use of possibly-uninitialized `t`
+   |         ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/partial-initialization-across-yield.rs:23:9
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/partial-initialization-across-yield.rs:22:9
    |
+LL |         let mut t: T;
+   |             ----- binding declared here but left uninitialized
 LL |         t.0 = 42;
-   |         ^^^^^^^^ use of possibly-uninitialized `t`
+   |         ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/partial-initialization-across-yield.rs:34:9
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/partial-initialization-across-yield.rs:32:9
    |
+LL |         let mut t: S;
+   |             ----- binding declared here but left uninitialized
 LL |         t.x = 42;
-   |         ^^^^^^^^ use of possibly-uninitialized `t`
+   |         ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
index 3ee4c1458ba..5b61f1e8f2d 100644
--- a/src/test/ui/generator/print/generator-print-verbose-1.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -31,11 +31,8 @@ LL |     require_send(send_gen);
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:42:5
    |
-LL | /     || {
-LL | |         yield;
-LL | |         t
-LL | |     }
-   | |_____^
+LL |     || {
+   |     ^^
 note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
   --> $DIR/generator-print-verbose-1.rs:41:30
    |
@@ -50,12 +47,8 @@ LL | fn make_non_send_generator2() -> impl Generator<Return = Arc<RefCell<i32>>>
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-1.rs:52:20
    |
-LL |       let send_gen = || {
-   |  ____________________^
-LL | |         let _non_send_gen = make_non_send_generator2();
-LL | |         yield;
-LL | |     };
-   | |_____^
+LL |     let send_gen = || {
+   |                    ^^
 note: required by a bound in `require_send`
   --> $DIR/generator-print-verbose-1.rs:26:25
    |
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr
index 1356fa5f152..eb79d2e6eed 100644
--- a/src/test/ui/generator/print/generator-print-verbose-2.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr
@@ -9,13 +9,8 @@ LL |     assert_send(|| {
 note: required because it's used within this generator
   --> $DIR/generator-print-verbose-2.rs:19:17
    |
-LL |       assert_send(|| {
-   |  _________________^
-LL | |
-LL | |         drop(&a);
-LL | |         yield;
-LL | |     });
-   | |_____^
+LL |     assert_send(|| {
+   |                 ^^
 note: required by a bound in `assert_send`
   --> $DIR/generator-print-verbose-2.rs:10:23
    |
diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr
index 4ae745b0ffe..e3859595fd2 100644
--- a/src/test/ui/generator/static-not-unpin.stderr
+++ b/src/test/ui/generator/static-not-unpin.stderr
@@ -1,8 +1,8 @@
-error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned
+error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]` cannot be unpinned
   --> $DIR/static-not-unpin.rs:14:18
    |
 LL |     assert_unpin(generator);
-   |     ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]`
+   |     ------------ ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 11:34]`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index d78a5929a89..7938fc8097c 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -12,7 +12,7 @@ note: return type inferred to be `Result<{integer}, _>` here
 LL |             return Ok(6);
    |                    ^^^^^
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 15:6] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs
index 092fa939c30..40eef11f058 100644
--- a/src/test/ui/generic-associated-types/issue-91139.rs
+++ b/src/test/ui/generic-associated-types/issue-91139.rs
@@ -22,6 +22,7 @@ fn foo<T>() {
     //~| ERROR `T` does not live long enough
     //~| ERROR `T` does not live long enough
     //~| ERROR `T` does not live long enough
+    //~| ERROR `T` may not live long enough
     //
     // FIXME: This error is bogus, but it arises because we try to validate
     // that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
diff --git a/src/test/ui/generic-associated-types/issue-91139.stderr b/src/test/ui/generic-associated-types/issue-91139.stderr
index 6c5092978c8..b789b3a42f3 100644
--- a/src/test/ui/generic-associated-types/issue-91139.stderr
+++ b/src/test/ui/generic-associated-types/issue-91139.stderr
@@ -34,6 +34,17 @@ error: `T` does not live long enough
 LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
    |                                                          ^^^^^^^^^
 
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-91139.rs:16:58
+   |
+LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+   |                                                          ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn foo<T: 'static>() {
+   |         +++++++++
+
 error: `T` does not live long enough
   --> $DIR/issue-91139.rs:16:58
    |
@@ -46,5 +57,6 @@ error: `T` does not live long enough
 LL |     let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
    |                                                          ^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
index 2804364890f..d9dc77ac8eb 100644
--- a/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
+++ b/src/test/ui/generic-associated-types/method-unsatified-assoc-type-predicate.stderr
@@ -3,8 +3,8 @@ error[E0599]: the method `f` exists for struct `S`, but its trait bounds were no
    |
 LL | struct S;
    | --------
-   | |      |
-   | |      method `f` not found for this struct
+   | |
+   | method `f` not found for this struct
    | doesn't satisfy `<S as X>::Y<i32> = i32`
    | doesn't satisfy `S: M`
 ...
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
index 43e609cc59e..c01ab8e347c 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     v.t(|| {});
    |     ^^^^^^^^^^
    |
-   = note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed`
+   = note: could not prove `[closure@$DIR/issue-59311.rs:17:9: 17:11] well-formed`
 
 error: higher-ranked lifetime error
   --> $DIR/issue-59311.rs:17:9
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
index 0bfa7b3cc7c..eebce827d1c 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-71955.stderr
@@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |                        ^^^^^^^^^^^^^^^^
+   |                        ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-71955.rs:25:9
    |
@@ -29,7 +29,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:45:24
    |
 LL |     foo(bar, "string", |s| s.len() == 5);
-   |                        ^^^^^^^^^^^^^^^^
+   |                        ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-71955.rs:25:44
    |
@@ -48,7 +48,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |                        ^^^^^^^^^^^^^^^^^^
+   |                        ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-71955.rs:25:9
    |
@@ -67,7 +67,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-71955.rs:48:24
    |
 LL |     foo(baz, "string", |s| s.0.len() == 5);
-   |                        ^^^^^^^^^^^^^^^^^^
+   |                        ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-71955.rs:25:44
    |
diff --git a/src/test/ui/hrtb/issue-30786.stderr b/src/test/ui/hrtb/issue-30786.stderr
index 5a10a38d08e..bc7b5e914e1 100644
--- a/src/test/ui/hrtb/issue-30786.stderr
+++ b/src/test/ui/hrtb/issue-30786.stderr
@@ -1,19 +1,19 @@
-error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>`, but its trait bounds were not satisfied
+error[E0599]: the method `filterx` exists for struct `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:118:22
    |
 LL | pub struct Map<S, F> {
    | --------------------
-   | |          |
-   | |          method `filterx` not found for this struct
+   | |
+   | method `filterx` not found for this struct
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let filter = map.filterx(|x: &_| true);
-   |                      ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>` due to unsatisfied trait bounds
+   |                      ^^^^^^^ method cannot be called on `Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>` due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
-      `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream`
-      `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream`
-      `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:36]>: Stream`
+      `&'a mut &Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
+      `&'a mut &mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
+      `&'a mut Map<Repeat, [closure@$DIR/issue-30786.rs:117:27: 117:34]>: Stream`
   --> $DIR/issue-30786.rs:96:50
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
@@ -23,22 +23,22 @@ help: one of the expressions' fields has a method of the same name
 LL |     let filter = map.stream.filterx(|x: &_| true);
    |                      +++++++
 
-error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>`, but its trait bounds were not satisfied
+error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
    |
 LL | pub struct Filter<S, F> {
    | -----------------------
-   | |          |
-   | |          method `countx` not found for this struct
+   | |
+   | method `countx` not found for this struct
    | doesn't satisfy `_: StreamExt`
 ...
 LL |     let count = filter.countx();
-   |                        ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>` due to unsatisfied trait bounds
+   |                        ^^^^^^ method cannot be called on `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>` due to unsatisfied trait bounds
    |
 note: the following trait bounds were not satisfied:
-      `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream`
-      `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream`
-      `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:42]>: Stream`
+      `&'a mut &Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+      `&'a mut &mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
+      `&'a mut Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>: Stream`
   --> $DIR/issue-30786.rs:96:50
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
index 0ebba37e4ec..79ef56b9fa5 100644
--- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
+++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr
@@ -1,8 +1,8 @@
-error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+error[E0271]: type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:38:19
    |
 LL |     let v = Unit2.m(
-   |                   ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
+   |                   ^ type mismatch resolving `for<'r> <L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]> as T0<'r, (&'r u8,)>>::O == <_ as Ty<'r>>::V`
    |
 note: expected this to be `<_ as Ty<'_>>::V`
   --> $DIR/issue-62203-hrtb-ice.rs:21:14
@@ -22,7 +22,7 @@ LL |     where
 LL |         F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
    |                                                   ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
 
-error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&'r u8,),)>>::Output == Unit3`
+error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20] as FnOnce<((&'r u8,),)>>::Output == Unit3`
   --> $DIR/issue-62203-hrtb-ice.rs:40:9
    |
 LL |       let v = Unit2.m(
@@ -34,7 +34,7 @@ LL | |             f : |x| { drop(x); Unit4 }
 LL | |         });
    | |_________^ expected struct `Unit3`, found struct `Unit4`
    |
-note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>`
+note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:20]>`
   --> $DIR/issue-62203-hrtb-ice.rs:17:16
    |
 LL | impl<'a, A, T> T0<'a, A> for L<T>
diff --git a/src/test/ui/impl-trait/auto-trait-leak.rs b/src/test/ui/impl-trait/auto-trait-leak.rs
index d2452abab02..c2fbbf94fd6 100644
--- a/src/test/ui/impl-trait/auto-trait-leak.rs
+++ b/src/test/ui/impl-trait/auto-trait-leak.rs
@@ -11,7 +11,6 @@ fn main() {
 // return type, which can't depend on the obligation.
 fn cycle1() -> impl Clone {
     //~^ ERROR cycle detected
-    //~| ERROR cycle detected
     send(cycle2().clone());
 
     Rc::new(Cell::new(5))
diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr
index 14db864f1c2..634ff14869e 100644
--- a/src/test/ui/impl-trait/auto-trait-leak.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak.stderr
@@ -30,129 +30,47 @@ note: ...which requires building MIR for `cycle1`...
 LL | fn cycle1() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires type-checking `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires computing type of `cycle2::{opaque#0}`...
-  --> $DIR/auto-trait-leak.rs:20:16
-   |
-LL | fn cycle2() -> impl Clone {
-   |                ^^^^^^^^^^
-note: ...which requires borrow-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires unsafety-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires building MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires type-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
-   |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/auto-trait-leak.rs:1:1
-   |
-LL | / use std::cell::Cell;
-LL | | use std::rc::Rc;
-LL | |
-LL | | fn send<T: Send>(_: T) {}
-...  |
-LL | |     Rc::new(String::from("foo"))
-LL | | }
-   | |_^
-
-error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}`
-  --> $DIR/auto-trait-leak.rs:12:16
+  --> $DIR/auto-trait-leak.rs:14:5
    |
-LL | fn cycle1() -> impl Clone {
-   |                ^^^^^^^^^^
-   |
-note: ...which requires borrow-checking `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires processing MIR for `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires unsafety-checking `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires building MIR for `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires type-checking `cycle1`...
-  --> $DIR/auto-trait-leak.rs:12:1
-   |
-LL | fn cycle1() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     send(cycle2().clone());
+   |     ^^^^
+   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
 note: ...which requires computing type of `cycle2::{opaque#0}`...
-  --> $DIR/auto-trait-leak.rs:20:16
+  --> $DIR/auto-trait-leak.rs:19:16
    |
 LL | fn cycle2() -> impl Clone {
    |                ^^^^^^^^^^
 note: ...which requires borrow-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires processing MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires unsafety-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires building MIR for `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:19:1
    |
 LL | fn cycle2() -> impl Clone {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires type-checking `cycle2`...
-  --> $DIR/auto-trait-leak.rs:20:1
+  --> $DIR/auto-trait-leak.rs:20:5
    |
-LL | fn cycle2() -> impl Clone {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     send(cycle1().clone());
+   |     ^^^^
+   = note: ...which requires evaluating trait selection obligation `impl core::clone::Clone: core::marker::Send`...
    = note: ...which again requires computing type of `cycle1::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/auto-trait-leak.rs:1:1
@@ -166,6 +84,6 @@ LL | |     Rc::new(String::from("foo"))
 LL | | }
    | |_^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr
index d825843492d..52fa28145d6 100644
--- a/src/test/ui/impl-trait/auto-trait-leak2.stderr
+++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr
@@ -14,7 +14,7 @@ note: required because it's used within this closure
   --> $DIR/auto-trait-leak2.rs:10:5
    |
 LL |     move |x| p.set(x)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^
 note: required because it appears within the type `impl Fn(i32)`
   --> $DIR/auto-trait-leak2.rs:5:16
    |
@@ -42,7 +42,7 @@ note: required because it's used within this closure
   --> $DIR/auto-trait-leak2.rs:38:5
    |
 LL |     move |x| p.set(x)
-   |     ^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^
 note: required because it appears within the type `impl Fn(i32)`
   --> $DIR/auto-trait-leak2.rs:33:15
    |
diff --git a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
index 8b671e7dbb3..9150d957db7 100644
--- a/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
+++ b/src/test/ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `foo` found for struct `Bar` in the current scope
   --> $DIR/issue-21659-show-relevant-trait-impls-3.rs:20:8
    |
 LL | struct Bar;
-   |        --- method `foo` not found for this struct
+   | ---------- method `foo` not found for this struct
 ...
 LL |     f1.foo(1usize);
    |        ^^^ method not found in `Bar`
diff --git a/src/test/ui/impl-trait/issues/issue-62742.stderr b/src/test/ui/impl-trait/issues/issue-62742.stderr
index 2d14faf7677..34f4dc2cef3 100644
--- a/src/test/ui/impl-trait/issues/issue-62742.stderr
+++ b/src/test/ui/impl-trait/issues/issue-62742.stderr
@@ -21,7 +21,7 @@ LL | pub struct RawImpl<T>(PhantomData<T>);
    | --------------------- doesn't satisfy `RawImpl<()>: Raw<()>`
 ...
 LL | pub struct SafeImpl<T: ?Sized, A: Raw<T>>(PhantomData<(A, T)>);
-   |            -------- function or associated item `foo` not found for this struct
+   | ----------------------------------------- function or associated item `foo` not found for this struct
    |
    = note: the following trait bounds were not satisfied:
            `RawImpl<()>: Raw<()>`
diff --git a/src/test/ui/impl-trait/issues/issue-74282.stderr b/src/test/ui/impl-trait/issues/issue-74282.stderr
index 0f855ef5792..5b05fb2810d 100644
--- a/src/test/ui/impl-trait/issues/issue-74282.stderr
+++ b/src/test/ui/impl-trait/issues/issue-74282.stderr
@@ -13,7 +13,7 @@ LL | |     })
    | |_____^ expected closure, found a different closure
    |
    = note: expected opaque type `Closure`
-                  found closure `[closure@$DIR/issue-74282.rs:8:15: 10:6]`
+                  found closure `[closure@$DIR/issue-74282.rs:8:15: 8:17]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 note: tuple struct defined here
diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
index abd57d12d9e..b727b2ca0cc 100644
--- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
+++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `is_empty` found for struct `Foo` in the current s
   --> $DIR/method-suggestion-no-duplication.rs:7:15
    |
 LL | struct Foo;
-   |        --- method `is_empty` not found for this struct
+   | ---------- method `is_empty` not found for this struct
 ...
 LL |     foo(|s| s.is_empty());
    |               ^^^^^^^^ method not found in `Foo`
diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index f8ff2177bf5..586563c3906 100644
--- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -100,7 +100,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/must_outlive_least_region_or_bound.rs:38:5
    |
 LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
-   |                              -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:31]` captures the lifetime `'b` as defined here
+   |                              -- hidden type `[closure@$DIR/must_outlive_least_region_or_bound.rs:38:5: 38:13]` captures the lifetime `'b` as defined here
 LL |     move |_| println!("{}", y)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait.stderr b/src/test/ui/impl-trait/nested-return-type2-tait.stderr
index 359fb909e54..1079a86ce9e 100644
--- a/src/test/ui/impl-trait/nested-return-type2-tait.stderr
+++ b/src/test/ui/impl-trait/nested-return-type2-tait.stderr
@@ -5,7 +5,7 @@ LL | fn foo() -> impl Trait<Assoc = Sendable> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `Sendable`
    |
    = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:27:5: 27:10]`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait.rs:27:5: 27:7]`
   --> $DIR/nested-return-type2-tait.rs:14:31
    |
 LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait2.stderr b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr
index 3e19ad7b5c6..847b9400085 100644
--- a/src/test/ui/impl-trait/nested-return-type2-tait2.stderr
+++ b/src/test/ui/impl-trait/nested-return-type2-tait2.stderr
@@ -5,7 +5,7 @@ LL | fn foo() -> Traitable {
    |             ^^^^^^^^^ the trait `Duh` is not implemented for `Sendable`
    |
    = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait2.rs:28:5: 28:10]`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait2.rs:28:5: 28:7]`
   --> $DIR/nested-return-type2-tait2.rs:14:31
    |
 LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
diff --git a/src/test/ui/impl-trait/nested-return-type2-tait3.stderr b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr
index 6185e4872a5..7b7f06b8e13 100644
--- a/src/test/ui/impl-trait/nested-return-type2-tait3.stderr
+++ b/src/test/ui/impl-trait/nested-return-type2-tait3.stderr
@@ -5,7 +5,7 @@ LL | fn foo() -> Traitable {
    |             ^^^^^^^^^ the trait `Duh` is not implemented for `impl Send`
    |
    = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait3.rs:27:5: 27:10]`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2-tait3.rs:27:5: 27:7]`
   --> $DIR/nested-return-type2-tait3.rs:14:31
    |
 LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
diff --git a/src/test/ui/impl-trait/nested-return-type2.stderr b/src/test/ui/impl-trait/nested-return-type2.stderr
index f996e99de07..f28a084af89 100644
--- a/src/test/ui/impl-trait/nested-return-type2.stderr
+++ b/src/test/ui/impl-trait/nested-return-type2.stderr
@@ -5,7 +5,7 @@ LL | fn foo() -> impl Trait<Assoc = impl Send> {
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Duh` is not implemented for `impl Send`
    |
    = help: the trait `Duh` is implemented for `i32`
-note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2.rs:23:5: 23:10]`
+note: required because of the requirements on the impl of `Trait` for `[closure@$DIR/nested-return-type2.rs:23:5: 23:7]`
   --> $DIR/nested-return-type2.rs:12:31
    |
 LL | impl<R: Duh, F: FnMut() -> R> Trait for F {
diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
index 1d24f428fb1..3d4ae11e576 100644
--- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr
+++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr
@@ -94,7 +94,7 @@ error[E0599]: no method named `method` found for struct `Foo` in the current sco
   --> $DIR/no-method-suggested-traits.rs:40:9
    |
 LL | struct Foo;
-   |        --- method `method` not found for this struct
+   | ---------- method `method` not found for this struct
 ...
 LL |     Foo.method();
    |         ^^^^^^ method not found in `Foo`
@@ -201,7 +201,7 @@ error[E0599]: no method named `method3` found for struct `Foo` in the current sc
   --> $DIR/no-method-suggested-traits.rs:59:9
    |
 LL | struct Foo;
-   |        --- method `method3` not found for this struct
+   | ---------- method `method3` not found for this struct
 ...
 LL |     Foo.method3();
    |         ^^^^^^^ method not found in `Foo`
@@ -224,7 +224,7 @@ error[E0599]: no method named `method3` found for enum `Bar` in the current scop
   --> $DIR/no-method-suggested-traits.rs:63:12
    |
 LL | enum Bar { X }
-   |      --- method `method3` not found for this enum
+   | -------- method `method3` not found for this enum
 ...
 LL |     Bar::X.method3();
    |            ^^^^^^^ method not found in `Bar`
diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
index b9b2ce249f7..2e34d3d4275 100644
--- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
+++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
@@ -54,7 +54,7 @@ LL |   fn closure_capture() -> impl Sized {
 LL | /     move || {
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6]`
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:40:29
@@ -65,7 +65,7 @@ LL |   fn closure_ref_capture() -> impl Sized {
 LL | /     move || {
 LL | |         &x;
 LL | |     }
-   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6]`
+   | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:48:21
@@ -74,7 +74,7 @@ LL | fn closure_sig() -> impl Sized {
    |                     ^^^^^^^^^^ recursive opaque type
 LL |
 LL |     || closure_sig()
-   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
+   |     ---------------- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:7]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:53:23
@@ -83,7 +83,7 @@ LL | fn generator_sig() -> impl Sized {
    |                       ^^^^^^^^^^ recursive opaque type
 LL |
 LL |     || generator_sig()
-   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
+   |     ------------------ returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:7]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:58:27
@@ -95,7 +95,7 @@ LL | /     move || {
 LL | |         yield;
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6]`
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:67:35
@@ -117,7 +117,7 @@ LL | |         let x = generator_hold();
 LL | |         yield;
 LL | |         x;
 LL | |     }
-   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6]`
+   | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 74:12]`
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:86:26
diff --git a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
index bc8e39f9c50..951abb127c1 100644
--- a/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
+++ b/src/test/ui/impl-trait/static-return-lifetime-infered.stderr
@@ -2,7 +2,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -15,7 +15,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/static-return-lifetime-infered.rs:7:9
    |
 LL |     fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
-   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:34]>` captures the anonymous lifetime defined here
+   |                         ----- hidden type `Map<std::slice::Iter<'_, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:7:27: 7:30]>` captures the anonymous lifetime defined here
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -28,7 +28,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
@@ -41,7 +41,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/static-return-lifetime-infered.rs:12:9
    |
 LL |     fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
-   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:34]>` captures the lifetime `'a` as defined here
+   |                    -- hidden type `Map<std::slice::Iter<'a, (u32, u32)>, [closure@$DIR/static-return-lifetime-infered.rs:12:27: 12:30]>` captures the lifetime `'a` as defined here
 LL |         self.x.iter().map(|a| a.0)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
diff --git a/src/test/ui/imports/inaccessible_type_aliases.rs b/src/test/ui/imports/inaccessible_type_aliases.rs
new file mode 100644
index 00000000000..c3d4214e282
--- /dev/null
+++ b/src/test/ui/imports/inaccessible_type_aliases.rs
@@ -0,0 +1,14 @@
+mod a {
+    type Foo = u64;
+    type Bar = u64;
+}
+
+mod b {
+    type Foo = u64;
+}
+
+fn main() {
+    let x: Foo = 100; //~ ERROR: cannot find type `Foo` in this scope
+    let y: Bar = 100; //~ ERROR: cannot find type `Bar` in this scope
+    println!("x: {}, y: {}", x, y);
+}
diff --git a/src/test/ui/imports/inaccessible_type_aliases.stderr b/src/test/ui/imports/inaccessible_type_aliases.stderr
new file mode 100644
index 00000000000..ef224246061
--- /dev/null
+++ b/src/test/ui/imports/inaccessible_type_aliases.stderr
@@ -0,0 +1,30 @@
+error[E0412]: cannot find type `Foo` in this scope
+  --> $DIR/inaccessible_type_aliases.rs:11:12
+   |
+LL |     let x: Foo = 100;
+   |            ^^^ not found in this scope
+   |
+note: these type aliases exist but are inaccessible
+  --> $DIR/inaccessible_type_aliases.rs:2:5
+   |
+LL |     type Foo = u64;
+   |     ^^^^^^^^^^^^^^^ `a::Foo`: not accessible
+...
+LL |     type Foo = u64;
+   |     ^^^^^^^^^^^^^^^ `b::Foo`: not accessible
+
+error[E0412]: cannot find type `Bar` in this scope
+  --> $DIR/inaccessible_type_aliases.rs:12:12
+   |
+LL |     let y: Bar = 100;
+   |            ^^^ not found in this scope
+   |
+note: type alias `a::Bar` exists but is inaccessible
+  --> $DIR/inaccessible_type_aliases.rs:3:5
+   |
+LL |     type Bar = u64;
+   |     ^^^^^^^^^^^^^^^ not accessible
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/inference/ambiguous_type_parameter.stderr b/src/test/ui/inference/ambiguous_type_parameter.stderr
index a08342371b3..9cbe221de13 100644
--- a/src/test/ui/inference/ambiguous_type_parameter.stderr
+++ b/src/test/ui/inference/ambiguous_type_parameter.stderr
@@ -2,7 +2,12 @@ error[E0282]: type annotations needed
   --> $DIR/ambiguous_type_parameter.rs:16:19
    |
 LL |     InMemoryStore.get_raw(&String::default());
-   |                   ^^^^^^^ cannot infer type for type parameter `K`
+   |                   ^^^^^^^
+   |
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <InMemoryStore as Store<String, HashMap<K, String>>>::get_raw(&InMemoryStore, &String::default());
+   |     +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++             ~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.rs b/src/test/ui/inference/cannot-infer-partial-try-return.rs
index 976827a4478..b555697dc34 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.rs
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.rs
@@ -16,8 +16,8 @@ fn infallible() -> Result<(), std::convert::Infallible> {
 
 fn main() {
     let x = || -> Result<_, QualifiedError<_>> {
-        //~^ ERROR type annotations needed for `Result<(), QualifiedError<_>>`
         infallible()?;
         Ok(())
+        //~^ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
index c1e43f0b721..2a56aaa44fe 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
@@ -1,16 +1,15 @@
-error[E0282]: type annotations needed for `Result<(), QualifiedError<_>>`
-  --> $DIR/cannot-infer-partial-try-return.rs:18:13
+error[E0282]: type annotations needed
+  --> $DIR/cannot-infer-partial-try-return.rs:20:9
    |
-LL |     let x = || -> Result<_, QualifiedError<_>> {
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
 LL |         infallible()?;
    |         ------------- type must be known at this point
+LL |         Ok(())
+   |         ^^ cannot infer type of the type parameter `E` declared on the enum `Result`
    |
-help: try giving this closure an explicit return type
+help: consider specifying the generic arguments
    |
-LL |     let x = || -> Result<(), QualifiedError<_>> {
-   |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL |         Ok::<(), QualifiedError<_>>(())
+   |           +++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/need_type_info/channel.rs b/src/test/ui/inference/need_type_info/channel.rs
new file mode 100644
index 00000000000..e2ba5a94171
--- /dev/null
+++ b/src/test/ui/inference/need_type_info/channel.rs
@@ -0,0 +1,19 @@
+// Test that we suggest specifying the generic argument of `channel`
+// instead of the return type of that function, which is a lot more
+// complex.
+use std::sync::mpsc::channel;
+
+fn no_tuple() {
+    let _data =
+        channel(); //~ ERROR type annotations needed
+}
+
+fn tuple() {
+    let (_sender, _receiver) =
+        channel(); //~ ERROR type annotations needed
+}
+
+fn main() {
+    no_tuple();
+    tuple();
+}
diff --git a/src/test/ui/inference/need_type_info/channel.stderr b/src/test/ui/inference/need_type_info/channel.stderr
new file mode 100644
index 00000000000..e33ace0338d
--- /dev/null
+++ b/src/test/ui/inference/need_type_info/channel.stderr
@@ -0,0 +1,25 @@
+error[E0282]: type annotations needed
+  --> $DIR/channel.rs:8:9
+   |
+LL |         channel();
+   |         ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
+   |
+help: consider specifying the generic argument
+   |
+LL |         channel::<T>();
+   |                +++++
+
+error[E0282]: type annotations needed
+  --> $DIR/channel.rs:13:9
+   |
+LL |         channel();
+   |         ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
+   |
+help: consider specifying the generic argument
+   |
+LL |         channel::<T>();
+   |                +++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/infinite/infinite-autoderef.stderr b/src/test/ui/infinite/infinite-autoderef.stderr
index edf8a44b7e4..51b61e3a66b 100644
--- a/src/test/ui/infinite/infinite-autoderef.stderr
+++ b/src/test/ui/infinite/infinite-autoderef.stderr
@@ -43,7 +43,7 @@ error[E0599]: no method named `bar` found for struct `Foo` in the current scope
   --> $DIR/infinite-autoderef.rs:25:9
    |
 LL | struct Foo;
-   |        --- method `bar` not found for this struct
+   | ---------- method `bar` not found for this struct
 ...
 LL |     Foo.bar();
    |         ^^^ method not found in `Foo`
diff --git a/src/test/ui/infinite/infinite-struct.rs b/src/test/ui/infinite/infinite-struct.rs
index 70a203ea6e8..74185dc597b 100644
--- a/src/test/ui/infinite/infinite-struct.rs
+++ b/src/test/ui/infinite/infinite-struct.rs
@@ -1,6 +1,5 @@
 struct Take(Take);
 //~^ ERROR has infinite size
-//~| ERROR cycle detected
 
 // check that we don't hang trying to find the tail of a recursive struct (#79437)
 fn foo() -> Take {
diff --git a/src/test/ui/infinite/infinite-struct.stderr b/src/test/ui/infinite/infinite-struct.stderr
index 214be091cce..5a6d13786d1 100644
--- a/src/test/ui/infinite/infinite-struct.stderr
+++ b/src/test/ui/infinite/infinite-struct.stderr
@@ -11,16 +11,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Take` repre
 LL | struct Take(Box<Take>);
    |             ++++    +
 
-error[E0391]: cycle detected when computing drop-check constraints for `Take`
-  --> $DIR/infinite-struct.rs:1:1
-   |
-LL | struct Take(Take);
-   | ^^^^^^^^^^^
-   |
-   = note: ...which immediately requires computing drop-check constraints for `Take` again
-   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: Take } }`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0072, E0391.
-For more information about an error, try `rustc --explain E0072`.
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.rs b/src/test/ui/infinite/infinite-tag-type-recursion.rs
index 8578c5545bc..87a9e08dd38 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.rs
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.rs
@@ -1,5 +1,4 @@
 enum MList { Cons(isize, MList), Nil }
 //~^ ERROR recursive type `MList` has infinite size
-//~| ERROR cycle detected when computing drop-check constraints for `MList`
 
 fn main() { let a = MList::Cons(10, MList::Cons(11, MList::Nil)); }
diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
index 1802c7599a3..d2dad4b9178 100644
--- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr
+++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr
@@ -11,16 +11,6 @@ help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `MList` repr
 LL | enum MList { Cons(isize, Box<MList>), Nil }
    |                          ++++     +
 
-error[E0391]: cycle detected when computing drop-check constraints for `MList`
-  --> $DIR/infinite-tag-type-recursion.rs:1:1
-   |
-LL | enum MList { Cons(isize, MList), Nil }
-   | ^^^^^^^^^^
-   |
-   = note: ...which immediately requires computing drop-check constraints for `MList` again
-   = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing, constness: NotConst }, value: MList } }`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0072, E0391.
-For more information about an error, try `rustc --explain E0072`.
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr
index 66fe3c74e2c..349fb6dafa3 100644
--- a/src/test/ui/interior-mutability/interior-mutability.stderr
+++ b/src/test/ui/interior-mutability/interior-mutability.stderr
@@ -11,7 +11,7 @@ note: required because it's used within this closure
   --> $DIR/interior-mutability.rs:5:18
    |
 LL |     catch_unwind(|| { x.set(23); });
-   |                  ^^^^^^^^^^^^^^^^^
+   |                  ^^
 note: required by a bound in `catch_unwind`
   --> $SRC_DIR/std/src/panic.rs:LL:COL
    |
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr
index 79f6a5850b5..1d3bff3a724 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.stderr
+++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr
@@ -1,18 +1,18 @@
-error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]: ~const FnOnce<()>` is not satisfied
+error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]: ~const FnOnce<()>` is not satisfied
   --> $DIR/const-eval-select-bad.rs:6:27
    |
 LL |     const_eval_select((), || {}, || {});
-   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+   |     -----------------     ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
-note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`, but that implementation is not `const`
+   = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`
+note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]`, but that implementation is not `const`
   --> $DIR/const-eval-select-bad.rs:6:27
    |
 LL |     const_eval_select((), || {}, || {});
    |                           ^^^^^
-   = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }`
+   = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:29]` in a closure with no arguments: `|| { /* code */ }`
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
    |
diff --git a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr
index ff78c252731..9322654b292 100644
--- a/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr
+++ b/src/test/ui/intrinsics/intrinsic-raw_eq-const-padding.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/intrinsic-raw_eq-const-padding.rs:6:5
    |
 LL |     std::intrinsics::raw_eq(&(1_u8, 2_u16), &(1_u8, 2_u16))
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 4 bytes of memory starting at alloc3, but 1 byte is uninitialized starting at alloc3+0x1, and this operation requires initialized memory
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at alloc3[0x0..0x4], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr
index e1559ab2fea..2c451b07fbe 100644
--- a/src/test/ui/issues/issue-12127.stderr
+++ b/src/test/ui/issues/issue-12127.stderr
@@ -11,7 +11,7 @@ note: this value implements `FnOnce`, which causes it to be moved when called
    |
 LL |         f();
    |         ^
-   = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41]`, which does not implement the `Copy` trait
+   = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:30]`, which does not implement the `Copy` trait
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-19692.stderr b/src/test/ui/issues/issue-19692.stderr
index 7a72a5ff11a..9e888ed758a 100644
--- a/src/test/ui/issues/issue-19692.stderr
+++ b/src/test/ui/issues/issue-19692.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `kaname` found for struct `Homura` in the current
   --> $DIR/issue-19692.rs:4:40
    |
 LL | struct Homura;
-   |        ------ method `kaname` not found for this struct
+   | ------------- method `kaname` not found for this struct
 ...
 LL |     let Some(ref madoka) = Some(homura.kaname());
    |                                        ^^^^^^ method not found in `Homura`
diff --git a/src/test/ui/issues/issue-21600.stderr b/src/test/ui/issues/issue-21600.stderr
index dab3c3d1797..ea304f9367b 100644
--- a/src/test/ui/issues/issue-21600.stderr
+++ b/src/test/ui/issues/issue-21600.stderr
@@ -5,29 +5,26 @@ LL | fn call_it<F>(f: F) where F: Fn() { f(); }
    |                  - change this to accept `FnMut` instead of `Fn`
 ...
 LL |         call_it(|| x.gen_mut());
-   |         -------    ^^^^^^^^^^^ cannot borrow as mutable
-   |         |
+   |         ------- -- ^^^^^^^^^^^ cannot borrow as mutable
+   |         |       |
+   |         |       in this closure
    |         expects `Fn` instead of `FnMut`
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/issue-21600.rs:14:17
    |
-LL |   fn call_it<F>(f: F) where F: Fn() { f(); }
-   |                    - change this to accept `FnMut` instead of `Fn`
+LL | fn call_it<F>(f: F) where F: Fn() { f(); }
+   |                  - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       call_it(|| {
-   |  _____-------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         call_it(|| x.gen());
-LL | |         call_it(|| x.gen_mut());
-   | |                 ^^ - mutable borrow occurs due to use of `x` in closure
-   | |                 |
-   | |                 cannot borrow as mutable
-LL | |
-LL | |
-LL | |     });
-   | |_____- in this closure
+LL |     call_it(|| {
+   |     ------- -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         call_it(|| x.gen());
+LL |         call_it(|| x.gen_mut());
+   |                 ^^ - mutable borrow occurs due to use of `x` in closure
+   |                 |
+   |                 cannot borrow as mutable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-21974.stderr b/src/test/ui/issues/issue-21974.stderr
index 4e010a13653..2d60b18b1f2 100644
--- a/src/test/ui/issues/issue-21974.stderr
+++ b/src/test/ui/issues/issue-21974.stderr
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
 LL |     where &'a T : Foo,
    |                   ^^^
    |
-   = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+  --> $DIR/issue-21974.rs:11:19
+   |
+LL |     where &'a T : Foo,
+   |                   ^^^
+LL |           &'b T : Foo
+   |                   ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-22933-2.stderr b/src/test/ui/issues/issue-22933-2.stderr
index 648912a9690..1a0e87e15d6 100644
--- a/src/test/ui/issues/issue-22933-2.stderr
+++ b/src/test/ui/issues/issue-22933-2.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `PIE` found for enum `Deliciou
   --> $DIR/issue-22933-2.rs:4:55
    |
 LL | enum Delicious {
-   |      --------- variant or associated item `PIE` not found for this enum
+   | -------------- variant or associated item `PIE` not found for this enum
 ...
 LL |     ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
    |                                                       ^^^
diff --git a/src/test/ui/issues/issue-23041.stderr b/src/test/ui/issues/issue-23041.stderr
index 401086b2044..7b9a1634a0d 100644
--- a/src/test/ui/issues/issue-23041.stderr
+++ b/src/test/ui/issues/issue-23041.stderr
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-23041.rs:6:22
+  --> $DIR/issue-23041.rs:6:7
    |
 LL |     b.downcast_ref::<fn(_)->_>();
-   |                      ^^^^^^^^ cannot infer type
+   |       ^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the associated function `downcast_ref`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     b.downcast_ref::<fn(_) -> _>();
+   |                   ~~~~~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-23173.stderr b/src/test/ui/issues/issue-23173.stderr
index 052ccd07d41..d07d1a7caaf 100644
--- a/src/test/ui/issues/issue-23173.stderr
+++ b/src/test/ui/issues/issue-23173.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Homura` found for enum `Token
   --> $DIR/issue-23173.rs:9:23
    |
 LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
-   |      ----- variant or associated item `Homura` not found for this enum
+   | ---------- variant or associated item `Homura` not found for this enum
 ...
 LL |     use_token(&Token::Homura);
    |                       ^^^^^^ variant or associated item not found in `Token`
@@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `method` found for struct `St
   --> $DIR/issue-23173.rs:10:13
    |
 LL | struct Struct {
-   |        ------ function or associated item `method` not found for this struct
+   | ------------- function or associated item `method` not found for this struct
 ...
 LL |     Struct::method();
    |             ^^^^^^ function or associated item not found in `Struct`
@@ -20,7 +20,7 @@ error[E0599]: no function or associated item named `method` found for struct `St
   --> $DIR/issue-23173.rs:11:13
    |
 LL | struct Struct {
-   |        ------ function or associated item `method` not found for this struct
+   | ------------- function or associated item `method` not found for this struct
 ...
 LL |     Struct::method;
    |             ^^^^^^ function or associated item not found in `Struct`
@@ -29,7 +29,7 @@ error[E0599]: no associated item named `Assoc` found for struct `Struct` in the
   --> $DIR/issue-23173.rs:12:13
    |
 LL | struct Struct {
-   |        ------ associated item `Assoc` not found for this struct
+   | ------------- associated item `Assoc` not found for this struct
 ...
 LL |     Struct::Assoc;
    |             ^^^^^ associated item not found in `Struct`
diff --git a/src/test/ui/issues/issue-23217.stderr b/src/test/ui/issues/issue-23217.stderr
index c5906b8805d..5d3d8a4f808 100644
--- a/src/test/ui/issues/issue-23217.stderr
+++ b/src/test/ui/issues/issue-23217.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `A` found for enum `SomeEnum`
   --> $DIR/issue-23217.rs:2:19
    |
 LL | pub enum SomeEnum {
-   |          -------- variant or associated item `A` not found for this enum
+   | ----------------- variant or associated item `A` not found for this enum
 LL |     B = SomeEnum::A,
    |                   ^
    |                   |
diff --git a/src/test/ui/issues/issue-24013.stderr b/src/test/ui/issues/issue-24013.stderr
index 4e3cb88297d..863993f4509 100644
--- a/src/test/ui/issues/issue-24013.stderr
+++ b/src/test/ui/issues/issue-24013.stderr
@@ -1,8 +1,13 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-24013.rs:5:20
+  --> $DIR/issue-24013.rs:5:13
    |
 LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
-   |                    ^^^^^^ cannot infer type
+   |             ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `swap`
+   |
+help: consider specifying the generic arguments
+   |
+LL |     unsafe {swap::<&mut _>(transmute(&a), transmute(&b))};
+   |                 ~~~~~~~~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-24036.stderr b/src/test/ui/issues/issue-24036.stderr
index 4622501f33e..a42e35c4cad 100644
--- a/src/test/ui/issues/issue-24036.stderr
+++ b/src/test/ui/issues/issue-24036.stderr
@@ -2,12 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/issue-24036.rs:3:9
    |
 LL |     let mut x = |c| c + 1;
-   |                 --------- the expected closure
+   |                 --- the expected closure
 LL |     x = |c| c + 1;
    |         ^^^^^^^^^ expected closure, found a different closure
    |
-   = note: expected closure `[closure@$DIR/issue-24036.rs:2:17: 2:26]`
-              found closure `[closure@$DIR/issue-24036.rs:3:9: 3:18]`
+   = note: expected closure `[closure@$DIR/issue-24036.rs:2:17: 2:20]`
+              found closure `[closure@$DIR/issue-24036.rs:3:9: 3:12]`
    = note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
 
diff --git a/src/test/ui/issues/issue-24424.stderr b/src/test/ui/issues/issue-24424.stderr
index 8f3b2ac7319..50d7f988e19 100644
--- a/src/test/ui/issues/issue-24424.stderr
+++ b/src/test/ui/issues/issue-24424.stderr
@@ -4,7 +4,11 @@ error[E0283]: type annotations needed: cannot satisfy `T0: Trait0<'l0>`
 LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
    |                                                         ^^^^^^^^^^^
    |
-   = note: cannot satisfy `T0: Trait0<'l0>`
+note: multiple `impl`s or `where` clauses satisfying `T0: Trait0<'l0>` found
+  --> $DIR/issue-24424.rs:4:57
+   |
+LL | impl <'l0, 'l1, T0> Trait1<'l0, T0> for bool where T0 : Trait0<'l0>, T0 : Trait0<'l1> {}
+   |                                                         ^^^^^^^^^^^       ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-25368.rs b/src/test/ui/issues/issue-25368.rs
index b7f0f613e80..4be83457f7a 100644
--- a/src/test/ui/issues/issue-25368.rs
+++ b/src/test/ui/issues/issue-25368.rs
@@ -5,10 +5,10 @@ use std::marker::PhantomData;
 struct Foo<T> {foo: PhantomData<T>}
 
 fn main() {
-    let (tx, rx) = //~ ERROR type annotations needed
+    let (tx, rx) =
         channel();
-    // FIXME(#89862): Suggest adding a generic argument to `channel` instead
     spawn(move || {
         tx.send(Foo{ foo: PhantomData });
+        //~^ ERROR type annotations needed
     });
 }
diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr
index ffcb7384952..e6ed3aac710 100644
--- a/src/test/ui/issues/issue-25368.stderr
+++ b/src/test/ui/issues/issue-25368.stderr
@@ -1,13 +1,13 @@
-error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
-  --> $DIR/issue-25368.rs:8:9
+error[E0282]: type annotations needed
+  --> $DIR/issue-25368.rs:11:27
    |
-LL |     let (tx, rx) =
-   |         ^^^^^^^^
+LL |         tx.send(Foo{ foo: PhantomData });
+   |                           ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
    |
-help: consider giving this pattern a type, where the type for type parameter `T` is specified
+help: consider specifying the generic argument
    |
-LL |     let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
-   |                 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+LL |         tx.send(Foo{ foo: PhantomData::<T> });
+   |                                      +++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr
index fcc007a4a88..b5a2b2f55a6 100644
--- a/src/test/ui/issues/issue-2823.stderr
+++ b/src/test/ui/issues/issue-2823.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `C` in the current scope
   --> $DIR/issue-2823.rs:13:16
    |
 LL | struct C {
-   |        - method `clone` not found for this struct
+   | -------- method `clone` not found for this struct
 ...
 LL |     let _d = c.clone();
    |                ^^^^^ method not found in `C`
diff --git a/src/test/ui/issues/issue-28971.stderr b/src/test/ui/issues/issue-28971.stderr
index e0a65e33c44..2eb8a1c2653 100644
--- a/src/test/ui/issues/issue-28971.stderr
+++ b/src/test/ui/issues/issue-28971.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant or associated item named `Baz` found for enum `Foo` in
   --> $DIR/issue-28971.rs:7:18
    |
 LL | enum Foo {
-   |      --- variant or associated item `Baz` not found for this enum
+   | -------- variant or associated item `Baz` not found for this enum
 ...
 LL |             Foo::Baz(..) => (),
    |                  ^^^
diff --git a/src/test/ui/issues/issue-3044.rs b/src/test/ui/issues/issue-3044.rs
index 7363cae8370..7c626a01b12 100644
--- a/src/test/ui/issues/issue-3044.rs
+++ b/src/test/ui/issues/issue-3044.rs
@@ -1,7 +1,6 @@
 fn main() {
     let needlesArr: Vec<char> = vec!['a', 'f'];
     needlesArr.iter().fold(|x, y| {
+        //~^ ERROR this function takes 2 arguments but 1 argument was supplied
     });
-    //~^^ ERROR mismatched types
-    //~| ERROR this function takes 2 arguments but 1 argument was supplied
 }
diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr
index 6dbe6b59391..a4c455ca192 100644
--- a/src/test/ui/issues/issue-3044.stderr
+++ b/src/test/ui/issues/issue-3044.stderr
@@ -1,19 +1,9 @@
-error[E0308]: mismatched types
-  --> $DIR/issue-3044.rs:3:35
-   |
-LL |       needlesArr.iter().fold(|x, y| {
-   |  ___________________________________^
-LL | |     });
-   | |_____^ expected closure, found `()`
-   |
-   = note: expected closure `[closure@$DIR/issue-3044.rs:3:28: 4:6]`
-            found unit type `()`
-
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/issue-3044.rs:3:23
    |
 LL |       needlesArr.iter().fold(|x, y| {
    |  _______________________^^^^-
+LL | |
 LL | |     });
    | |______- an argument is missing
    |
@@ -25,10 +15,10 @@ LL |     fn fold<B, F>(mut self, init: B, mut f: F) -> B
 help: provide the argument
    |
 LL ~     needlesArr.iter().fold(|x, y| {
+LL +
 LL ~     }, /* value */);
    |
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0061, E0308.
-For more information about an error, try `rustc --explain E0061`.
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr
index 982b6118ce6..68337a715e1 100644
--- a/src/test/ui/issues/issue-31173.stderr
+++ b/src/test/ui/issues/issue-31173.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item == &_`
+error[E0271]: type mismatch resolving `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item == &_`
   --> $DIR/issue-31173.rs:10:10
    |
 LL |         .cloned()
@@ -12,11 +12,11 @@ note: required by a bound in `cloned`
 LL |         Self: Sized + Iterator<Item = &'a T>,
    |                                ^^^^^^^^^^^^ required by this bound in `cloned`
 
-error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>`, but its trait bounds were not satisfied
+error[E0599]: the method `collect` exists for struct `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>`, but its trait bounds were not satisfied
   --> $DIR/issue-31173.rs:12:10
    |
 LL |         .collect();
-   |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` due to unsatisfied trait bounds
+   |          ^^^^^^^ method cannot be called on `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>` due to unsatisfied trait bounds
    |
   ::: $SRC_DIR/core/src/iter/adapters/cloned.rs:LL:COL
    |
@@ -29,10 +29,10 @@ LL | pub struct TakeWhile<I, P> {
    | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_`
    |
    = note: the following trait bounds were not satisfied:
-           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_`
-           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
-           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
-           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator`
+           `<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]> as Iterator>::Item = &_`
+           which is required by `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
+           `Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
+           which is required by `&mut Cloned<TakeWhile<&mut std::vec::IntoIter<u8>, [closure@$DIR/issue-31173.rs:6:39: 6:43]>>: Iterator`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-34209.stderr b/src/test/ui/issues/issue-34209.stderr
index f9a25b69ff6..8de0edef076 100644
--- a/src/test/ui/issues/issue-34209.stderr
+++ b/src/test/ui/issues/issue-34209.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant named `B` found for enum `S`
   --> $DIR/issue-34209.rs:7:12
    |
 LL | enum S {
-   | ------ variant `B` not found here
+   | ------ variant `B` not found for this enum
 ...
 LL |         S::B {} => {},
    |            ^ help: there is a variant with a similar name: `A`
diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr
index cd84b6ef484..e83590a8f59 100644
--- a/src/test/ui/issues/issue-37884.stderr
+++ b/src/test/ui/issues/issue-37884.stderr
@@ -1,13 +1,8 @@
 error[E0308]: method not compatible with trait
   --> $DIR/issue-37884.rs:6:5
    |
-LL | /     fn next(&'a mut self) -> Option<Self::Item>
-LL | |
-LL | |
-LL | |     {
-LL | |         Some(&mut self.0)
-LL | |     }
-   | |_____^ lifetime mismatch
+LL |     fn next(&'a mut self) -> Option<Self::Item>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> Option<_>`
               found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> Option<_>`
diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr
index a52dc0c9af0..fd694df3045 100644
--- a/src/test/ui/issues/issue-41880.stderr
+++ b/src/test/ui/issues/issue-41880.stderr
@@ -2,10 +2,10 @@ error[E0599]: no method named `iter` found for struct `Iterate` in the current s
   --> $DIR/issue-41880.rs:27:24
    |
 LL | pub struct Iterate<T, F> {
-   |            ------- method `iter` not found for this struct
+   | ------------------------ method `iter` not found for this struct
 ...
 LL |     println!("{:?}", a.iter().take(10).collect::<Vec<usize>>());
-   |                        ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>`
+   |                        ^^^^ method not found in `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:27]>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-4335.stderr b/src/test/ui/issues/issue-4335.stderr
index fa3b58e1279..ecc1fa52398 100644
--- a/src/test/ui/issues/issue-4335.stderr
+++ b/src/test/ui/issues/issue-4335.stderr
@@ -4,9 +4,8 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu
 LL | fn f<'r, T>(v: &'r T) -> Box<dyn FnMut() -> T + 'r> {
    |             - captured outer variable
 LL |     id(Box::new(|| *v))
-   |                 ---^^
-   |                 |  |
-   |                 |  move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+   |                 -- ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait
+   |                 |
    |                 captured by this `FnMut` closure
 
 error: aborting due to previous error
diff --git a/src/test/ui/issues/issue-48838.stderr b/src/test/ui/issues/issue-48838.stderr
index 712a7bc33f8..3502af7028b 100644
--- a/src/test/ui/issues/issue-48838.stderr
+++ b/src/test/ui/issues/issue-48838.stderr
@@ -5,7 +5,7 @@ LL |     Square = |x| x,
    |              ^^^^^ expected `isize`, found closure
    |
    = note: expected type `isize`
-           found closure `[closure@$DIR/issue-48838.rs:2:14: 2:19]`
+           found closure `[closure@$DIR/issue-48838.rs:2:14: 2:17]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-50600.stderr b/src/test/ui/issues/issue-50600.stderr
index 08d9a839920..7fea7e5c098 100644
--- a/src/test/ui/issues/issue-50600.stderr
+++ b/src/test/ui/issues/issue-50600.stderr
@@ -5,7 +5,7 @@ LL |     fn([u8; |x: u8| {}]),
    |             ^^^^^^^^^^ expected `usize`, found closure
    |
    = note: expected type `usize`
-           found closure `[closure@$DIR/issue-50600.rs:2:13: 2:23]`
+           found closure `[closure@$DIR/issue-50600.rs:2:13: 2:20]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-50688.stderr b/src/test/ui/issues/issue-50688.stderr
index 1f348c4cf1f..6973ad271b4 100644
--- a/src/test/ui/issues/issue-50688.stderr
+++ b/src/test/ui/issues/issue-50688.stderr
@@ -5,7 +5,7 @@ LL |     [1; || {}];
    |         ^^^^^ expected `usize`, found closure
    |
    = note: expected type `usize`
-           found closure `[closure@$DIR/issue-50688.rs:2:9: 2:14]`
+           found closure `[closure@$DIR/issue-50688.rs:2:9: 2:11]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr
index f2cbc3e6feb..44ec626dea5 100644
--- a/src/test/ui/issues/issue-51154.stderr
+++ b/src/test/ui/issues/issue-51154.stderr
@@ -9,7 +9,7 @@ LL |     let _: Box<F> = Box::new(|| ());
    |                     arguments to this function are incorrect
    |
    = note: expected type parameter `F`
-                     found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]`
+                     found closure `[closure@$DIR/issue-51154.rs:2:30: 2:32]`
    = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F`
 note: associated function defined here
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/src/test/ui/issues/issue-64430.stderr b/src/test/ui/issues/issue-64430.stderr
index a25b6b8802a..b6b1f3a66c7 100644
--- a/src/test/ui/issues/issue-64430.stderr
+++ b/src/test/ui/issues/issue-64430.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `bar` found for struct `Foo` in the current scope
   --> $DIR/issue-64430.rs:7:9
    |
 LL | pub struct Foo;
-   |            --- method `bar` not found for this struct
+   | -------------- method `bar` not found for this struct
 ...
 LL |     Foo.bar()
    |         ^^^ method not found in `Foo`
diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs
index 98192dae20d..ec1997ccd5d 100644
--- a/src/test/ui/issues/issue-67552.rs
+++ b/src/test/ui/issues/issue-67552.rs
@@ -1,4 +1,5 @@
 // build-fail
+// compile-flags: -Copt-level=0
 // normalize-stderr-test: ".nll/" -> "/"
 
 fn main() {
diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr
index cf05a72e921..2968be7c71f 100644
--- a/src/test/ui/issues/issue-67552.stderr
+++ b/src/test/ui/issues/issue-67552.stderr
@@ -1,11 +1,11 @@
 error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>`
-  --> $DIR/issue-67552.rs:28:9
+  --> $DIR/issue-67552.rs:29:9
    |
 LL |         rec(identity(&mut it))
    |         ^^^^^^^^^^^^^^^^^^^^^^
    |
 note: `rec` defined here
-  --> $DIR/issue-67552.rs:21:1
+  --> $DIR/issue-67552.rs:22:1
    |
 LL | / fn rec<T>(mut it: T)
 LL | | where
diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr
index a55ac23e3ed..b4c877a2d74 100644
--- a/src/test/ui/issues/issue-77919.stderr
+++ b/src/test/ui/issues/issue-77919.stderr
@@ -24,7 +24,7 @@ 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
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
 error: constant expression depends on a generic parameter
   --> $DIR/issue-77919.rs:2:9
diff --git a/src/test/ui/issues/issue-7950.stderr b/src/test/ui/issues/issue-7950.stderr
index 2a683c2d55a..b8b0eb310cf 100644
--- a/src/test/ui/issues/issue-7950.stderr
+++ b/src/test/ui/issues/issue-7950.stderr
@@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `bar` found for struct `Foo`
   --> $DIR/issue-7950.rs:6:10
    |
 LL | struct Foo;
-   |        --- function or associated item `bar` not found for this struct
+   | ---------- function or associated item `bar` not found for this struct
 ...
 LL |     Foo::bar();
    |          ^^^ function or associated item not found in `Foo`
diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr
index 727573a0be4..eab003a1107 100644
--- a/src/test/ui/kindck/kindck-nonsendable-1.stderr
+++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr
@@ -2,16 +2,16 @@ error[E0277]: `Rc<usize>` cannot be sent between threads safely
   --> $DIR/kindck-nonsendable-1.rs:9:5
    |
 LL |     bar(move|| foo(x));
-   |     ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`
+   |     ^^^ ------ within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15]`
    |     |
    |     `Rc<usize>` cannot be sent between threads safely
    |
-   = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc<usize>`
+   = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15]`, the trait `Send` is not implemented for `Rc<usize>`
 note: required because it's used within this closure
   --> $DIR/kindck-nonsendable-1.rs:9:9
    |
 LL |     bar(move|| foo(x));
-   |         ^^^^^^^^^^^^^
+   |         ^^^^^^
 note: required by a bound in `bar`
   --> $DIR/kindck-nonsendable-1.rs:5:21
    |
diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.rs b/src/test/ui/layout/issue-96185-overaligned-enum.rs
new file mode 100644
index 00000000000..ae1e6b012c3
--- /dev/null
+++ b/src/test/ui/layout/issue-96185-overaligned-enum.rs
@@ -0,0 +1,19 @@
+// normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN"
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+// This cannot use `Scalar` abi since there is padding.
+#[rustc_layout(debug)]
+#[repr(align(8))]
+pub enum Aligned1 { //~ ERROR: layout_of
+    Zero = 0,
+    One = 1,
+}
+
+// This should use `Scalar` abi.
+#[rustc_layout(debug)]
+#[repr(align(1))]
+pub enum Aligned2 { //~ ERROR: layout_of
+    Zero = 0,
+    One = 1,
+}
diff --git a/src/test/ui/layout/issue-96185-overaligned-enum.stderr b/src/test/ui/layout/issue-96185-overaligned-enum.stderr
new file mode 100644
index 00000000000..8dc364fa7c9
--- /dev/null
+++ b/src/test/ui/layout/issue-96185-overaligned-enum.stderr
@@ -0,0 +1,172 @@
+error: layout_of(Aligned1) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size(8 bytes),
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align(8 bytes),
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size(8 bytes),
+                   },
+               ],
+           },
+           abi: Aggregate {
+               sized: true,
+           },
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align(8 bytes),
+               pref: $PREF_ALIGN,
+           },
+           size: Size(8 bytes),
+       }
+  --> $DIR/issue-96185-overaligned-enum.rs:8:1
+   |
+LL | pub enum Aligned1 {
+   | ^^^^^^^^^^^^^^^^^
+
+error: layout_of(Aligned2) = Layout {
+           fields: Arbitrary {
+               offsets: [
+                   Size(0 bytes),
+               ],
+               memory_index: [
+                   0,
+               ],
+           },
+           variants: Multiple {
+               tag: Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+               tag_encoding: Direct,
+               tag_field: 0,
+               variants: [
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 0,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size(1 bytes),
+                   },
+                   Layout {
+                       fields: Arbitrary {
+                           offsets: [],
+                           memory_index: [],
+                       },
+                       variants: Single {
+                           index: 1,
+                       },
+                       abi: Aggregate {
+                           sized: true,
+                       },
+                       largest_niche: None,
+                       align: AbiAndPrefAlign {
+                           abi: Align(1 bytes),
+                           pref: $PREF_ALIGN,
+                       },
+                       size: Size(1 bytes),
+                   },
+               ],
+           },
+           abi: Scalar(
+               Initialized {
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           largest_niche: Some(
+               Niche {
+                   offset: Size(0 bytes),
+                   value: Int(
+                       I8,
+                       false,
+                   ),
+                   valid_range: 0..=1,
+               },
+           ),
+           align: AbiAndPrefAlign {
+               abi: Align(1 bytes),
+               pref: $PREF_ALIGN,
+           },
+           size: Size(1 bytes),
+       }
+  --> $DIR/issue-96185-overaligned-enum.rs:16:1
+   |
+LL | pub enum Aligned2 {
+   | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lifetimes/issue-34979.stderr b/src/test/ui/lifetimes/issue-34979.stderr
index 5832c4d173c..a78b3eaf625 100644
--- a/src/test/ui/lifetimes/issue-34979.stderr
+++ b/src/test/ui/lifetimes/issue-34979.stderr
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a (): Foo`
 LL |     &'a (): Foo,
    |             ^^^
    |
-   = note: cannot satisfy `&'a (): Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a (): Foo` found
+  --> $DIR/issue-34979.rs:6:13
+   |
+LL |     &'a (): Foo,
+   |             ^^^
+LL |     &'static (): Foo;
+   |                  ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/issue-79187-2.stderr b/src/test/ui/lifetimes/issue-79187-2.stderr
index 6d8f2f56683..9322e617176 100644
--- a/src/test/ui/lifetimes/issue-79187-2.stderr
+++ b/src/test/ui/lifetimes/issue-79187-2.stderr
@@ -37,7 +37,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187-2.rs:8:14
    |
 LL |     take_foo(|a| a);
-   |              ^^^^^
+   |              ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-79187-2.rs:5:21
    |
diff --git a/src/test/ui/lifetimes/issue-79187.stderr b/src/test/ui/lifetimes/issue-79187.stderr
index 1d89d4dac5e..3e75e7fed2c 100644
--- a/src/test/ui/lifetimes/issue-79187.stderr
+++ b/src/test/ui/lifetimes/issue-79187.stderr
@@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-79187.rs:4:13
    |
 LL |     let f = |_| ();
-   |             ^^^^^^
+   |             ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/issue-79187.rs:1:18
    |
diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr
index 56f8fc10e86..d68472d4b66 100644
--- a/src/test/ui/lint/lint-missing-doc.stderr
+++ b/src/test/ui/lint/lint-missing-doc.stderr
@@ -2,7 +2,7 @@ error: missing documentation for a type alias
   --> $DIR/lint-missing-doc.rs:11:1
    |
 LL | pub type PubTypedef = String;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/lint-missing-doc.rs:3:9
@@ -56,13 +56,13 @@ error: missing documentation for an associated type
   --> $DIR/lint-missing-doc.rs:64:5
    |
 LL |     type AssociatedType;
-   |     ^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
   --> $DIR/lint-missing-doc.rs:65:5
    |
 LL |     type AssociatedTypeDef = Self;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
   --> $DIR/lint-missing-doc.rs:81:5
@@ -92,13 +92,13 @@ error: missing documentation for a constant
   --> $DIR/lint-missing-doc.rs:151:1
    |
 LL | pub const FOO4: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
   --> $DIR/lint-missing-doc.rs:161:1
    |
 LL | pub static BAR4: u32 = 0;
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
   --> $DIR/lint-missing-doc.rs:167:5
@@ -122,19 +122,19 @@ error: missing documentation for a function
   --> $DIR/lint-missing-doc.rs:189:5
    |
 LL |     pub fn extern_fn_undocumented(f: f32) -> f32;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
   --> $DIR/lint-missing-doc.rs:194:5
    |
 LL |     pub static EXTERN_STATIC_UNDOCUMENTED: u8;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a foreign type
   --> $DIR/lint-missing-doc.rs:199:5
    |
 LL |     pub type ExternTyUndocumented;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 22 previous errors
 
diff --git a/src/test/ui/lint/trivial_casts.stderr b/src/test/ui/lint/trivial_casts.stderr
index 141703460ba..8a216360f4e 100644
--- a/src/test/ui/lint/trivial_casts.stderr
+++ b/src/test/ui/lint/trivial_casts.stderr
@@ -128,7 +128,7 @@ LL |     let _ = &baz as &dyn Fn(i32);
    |
    = help: cast can be replaced by coercion; this might require a temporary variable
 
-error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn Fn(i32)`
+error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:22]` as `&dyn Fn(i32)`
   --> $DIR/trivial_casts.rs:73:13
    |
 LL |     let _ = &x as &dyn Fn(i32);
diff --git a/src/test/ui/loops/loop-proper-liveness.rs b/src/test/ui/loops/loop-proper-liveness.rs
index b242ec4296d..6546e397785 100644
--- a/src/test/ui/loops/loop-proper-liveness.rs
+++ b/src/test/ui/loops/loop-proper-liveness.rs
@@ -6,7 +6,7 @@ fn test1() {
     'a: loop {
         x = loop { break 'a };
     }
-    println!("{:?}", x); //~ ERROR borrow of possibly-uninitialized variable
+    println!("{:?}", x); //~ ERROR E0381
 }
 
 // test2 and test3 should not fail.
diff --git a/src/test/ui/loops/loop-proper-liveness.stderr b/src/test/ui/loops/loop-proper-liveness.stderr
index 20d5c66a3f2..75041031736 100644
--- a/src/test/ui/loops/loop-proper-liveness.stderr
+++ b/src/test/ui/loops/loop-proper-liveness.stderr
@@ -1,8 +1,11 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/loop-proper-liveness.rs:9:22
    |
+LL |     let x: i32;
+   |         - binding declared here but left uninitialized
+...
 LL |     println!("{:?}", x);
-   |                      ^ use of possibly-uninitialized `x`
+   |                      ^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
index 66e7ada3ac5..e0f8a5447b0 100644
--- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
+++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr
@@ -13,7 +13,7 @@ error[E0283]: type annotations needed
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
    |
 LL |     x.foo();
-   |       ^^^ cannot infer type for struct `Vec<_>`
+   |       ^^^
    |
 note: multiple `impl`s satisfying `Vec<_>: Foo` found
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1
@@ -23,6 +23,10 @@ LL | impl Foo for Vec<usize> {
 ...
 LL | impl Foo for Vec<isize> {
    | ^^^^^^^^^^^^^^^^^^^^^^^
+help: try using a fully qualified path to specify the expected types
+   |
+LL |     <Vec<T> as Foo>::foo(&x);
+   |     ++++++++++++++++++++++ ~
 
 error[E0308]: mismatched types
   --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index 4be588fe7f9..690fe8fa7af 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -51,8 +51,8 @@ error[E0599]: `Foo` is not an iterator
    |
 LL | pub struct Foo;
    | --------------
-   | |          |
-   | |          method `take` not found for this struct
+   | |
+   | method `take` not found for this struct
    | doesn't satisfy `Foo: Iterator`
 ...
 LL |      .take()
diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr
index 045f9ab7004..040a65d1680 100644
--- a/src/test/ui/methods/method-missing-call.stderr
+++ b/src/test/ui/methods/method-missing-call.stderr
@@ -9,7 +9,7 @@ help: use parentheses to call the method
 LL |                         .get_x();
    |                               ++
 
-error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>`
+error[E0615]: attempted to take value of method `filter_map` on type `Filter<Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:23]>, [closure@$DIR/method-missing-call.rs:28:23: 28:28]>`
   --> $DIR/method-missing-call.rs:29:16
    |
 LL |               .filter_map;
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
index 492d480e13e..56e1b5a0f44 100644
--- a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
+++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `distance` found for struct `Point<i32>` in the cu
   --> $DIR/method-not-found-generic-arg-elision.rs:82:23
    |
 LL | struct Point<T> {
-   |        ----- method `distance` not found for this struct
+   | --------------- method `distance` not found for this struct
 ...
 LL |     let d = point_i32.distance();
    |                       ^^^^^^^^ method not found in `Point<i32>`
@@ -14,7 +14,7 @@ error[E0599]: no method named `other` found for struct `Point` in the current sc
   --> $DIR/method-not-found-generic-arg-elision.rs:84:23
    |
 LL | struct Point<T> {
-   |        ----- method `other` not found for this struct
+   | --------------- method `other` not found for this struct
 ...
 LL |     let d = point_i32.other();
    |                       ^^^^^ method not found in `Point<i32>`
@@ -23,13 +23,13 @@ error[E0599]: no method named `extend` found for struct `Map` in the current sco
   --> $DIR/method-not-found-generic-arg-elision.rs:87:29
    |
 LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
-   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
+   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:21]>`
 
 error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
   --> $DIR/method-not-found-generic-arg-elision.rs:90:13
    |
 LL | struct Wrapper<T>(T);
-   |        ------- method `method` not found for this struct
+   | ----------------- method `method` not found for this struct
 ...
 LL |     wrapper.method();
    |             ^^^^^^ method not found in `Wrapper<bool>`
@@ -45,7 +45,7 @@ error[E0599]: no method named `other` found for struct `Wrapper` in the current
   --> $DIR/method-not-found-generic-arg-elision.rs:92:13
    |
 LL | struct Wrapper<T>(T);
-   |        ------- method `other` not found for this struct
+   | ----------------- method `other` not found for this struct
 ...
 LL |     wrapper.other();
    |             ^^^^^ method not found in `Wrapper<bool>`
@@ -54,7 +54,7 @@ error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_us
   --> $DIR/method-not-found-generic-arg-elision.rs:96:13
    |
 LL | struct Wrapper2<'a, T, const C: usize> {
-   |        -------- method `method` not found for this struct
+   | -------------------------------------- method `method` not found for this struct
 ...
 LL |     wrapper.method();
    |             ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
@@ -68,7 +68,7 @@ error[E0599]: no method named `other` found for struct `Wrapper2` in the current
   --> $DIR/method-not-found-generic-arg-elision.rs:98:13
    |
 LL | struct Wrapper2<'a, T, const C: usize> {
-   |        -------- method `other` not found for this struct
+   | -------------------------------------- method `other` not found for this struct
 ...
 LL |     wrapper.other();
    |             ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
@@ -83,7 +83,7 @@ error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait
   --> $DIR/method-not-found-generic-arg-elision.rs:104:7
    |
 LL | struct Struct<T>{
-   |        ------ method `method` not found for this struct
+   | ---------------- method `method` not found for this struct
 ...
 LL |     s.method();
    |       ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
index c44dd51a5ec..fc7341a563b 100644
--- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
+++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
@@ -6,7 +6,7 @@ static A: () = {
     //~^ ERROR destructors cannot be evaluated at compile-time
     a[0] = String::new();
     //~^ ERROR destructors cannot be evaluated at compile-time
-    //~| ERROR use of possibly-uninitialized variable
+    //~| ERROR binding `a` isn't initialized
 };
 
 struct B<T>([T; 1]);
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
index 80d5fc7ec67..d8154f8d2cb 100644
--- a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
+++ b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
@@ -16,11 +16,14 @@ LL |     let a: [String; 1];
 LL | };
    | - value is dropped here
 
-error[E0381]: use of possibly-uninitialized variable: `a`
+error[E0381]: used binding `a` isn't initialized
   --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
    |
+LL |     let a: [String; 1];
+   |         - binding declared here but left uninitialized
+LL |
 LL |     a[0] = String::new();
-   |     ^^^^ use of possibly-uninitialized `a`
+   |     ^^^^ `a` used here but it isn't initialized
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs
index 8e9c14a03c3..ebc3e2f8c0e 100644
--- a/src/test/ui/mir/ssa-analysis-regression-50041.rs
+++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs
@@ -5,7 +5,7 @@
 #![feature(lang_items)]
 #![no_std]
 
-struct NonNull<T: ?Sized>(*mut T);
+struct NonNull<T: ?Sized>(*const T);
 
 struct Unique<T: ?Sized>(NonNull<T>);
 
@@ -23,7 +23,7 @@ unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
 }
 
 #[inline(never)]
-fn dealloc<T: ?Sized>(_: *mut T) {}
+fn dealloc<T: ?Sized>(_: *const T) {}
 
 pub struct Foo<T>(T);
 
diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
index 1f46229cb5a..d9578f6c8dc 100644
--- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr
@@ -2,7 +2,7 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:3:14
    |
 LL |     a.iter().map(|_: (u32, u32)| 45);
-   |              ^^^ ------------------ found signature of `fn((u32, u32)) -> _`
+   |              ^^^ --------------- found signature of `fn((u32, u32)) -> _`
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
    |
@@ -16,7 +16,7 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:4:14
    |
 LL |     a.iter().map(|_: &(u16, u16)| 45);
-   |              ^^^ ------------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
+   |              ^^^ ---------------- found signature of `for<'r> fn(&'r (u16, u16)) -> _`
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
    |
@@ -30,7 +30,7 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/closure-arg-type-mismatch.rs:5:14
    |
 LL |     a.iter().map(|_: (u16, u16)| 45);
-   |              ^^^ ------------------ found signature of `fn((u16, u16)) -> _`
+   |              ^^^ --------------- found signature of `fn((u16, u16)) -> _`
    |              |
    |              expected signature of `fn(&(u32, u32)) -> _`
    |
diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr
index c1a29dfc933..ef76ec63fda 100644
--- a/src/test/ui/mismatched_types/closure-mismatch.stderr
+++ b/src/test/ui/mismatched_types/closure-mismatch.stderr
@@ -19,7 +19,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/closure-mismatch.rs:8:9
    |
 LL |     baz(|_| ());
-   |         ^^^^^^
+   |         ^^^
 note: the lifetime requirement is introduced here
   --> $DIR/closure-mismatch.rs:5:11
    |
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index a8bcdf5efe9..9d1ea70f8a4 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -2,7 +2,7 @@ error[E0631]: type mismatch in closure arguments
   --> $DIR/issue-36053-2.rs:7:32
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                ^^^^^^ --------- found signature of `for<'r> fn(&'r str) -> _`
    |                                |
    |                                expected signature of `for<'r> fn(&'r &str) -> _`
    |
@@ -12,11 +12,11 @@ note: required by a bound in `filter`
 LL |         P: FnMut(&Self::Item) -> bool,
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `filter`
 
-error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>`, but its trait bounds were not satisfied
+error[E0599]: the method `count` exists for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>`, but its trait bounds were not satisfied
   --> $DIR/issue-36053-2.rs:7:55
    |
 LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                       --------------  ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` due to unsatisfied trait bounds
+   |                                       ---------       ^^^^^ method cannot be called on `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>` due to unsatisfied trait bounds
    |                                       |
    |                                       doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool`
    |                                       doesn't satisfy `_: FnMut<(&&str,)>`
@@ -27,12 +27,12 @@ LL | pub struct Filter<I, P> {
    | ----------------------- doesn't satisfy `_: Iterator`
    |
    = note: the following trait bounds were not satisfied:
-           `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as FnOnce<(&&str,)>>::Output = bool`
-           which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
-           `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: FnMut<(&&str,)>`
-           which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
-           `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
-           which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
+           `<[closure@$DIR/issue-36053-2.rs:7:39: 7:48] as FnOnce<(&&str,)>>::Output = bool`
+           which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
+           `[closure@$DIR/issue-36053-2.rs:7:39: 7:48]: FnMut<(&&str,)>`
+           which is required by `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
+           `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
+           which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:48]>: Iterator`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/issue-47706.stderr b/src/test/ui/mismatched_types/issue-47706.stderr
index 0b4f84a330a..8b856368401 100644
--- a/src/test/ui/mismatched_types/issue-47706.stderr
+++ b/src/test/ui/mismatched_types/issue-47706.stderr
@@ -19,7 +19,7 @@ error[E0593]: function is expected to take 0 arguments, but it takes 1 argument
   --> $DIR/issue-47706.rs:27:9
    |
 LL |     Bar(i32),
-   |     -------- takes 1 argument
+   |     --- takes 1 argument
 ...
 LL |     foo(Qux::Bar);
    |     --- ^^^^^^^^ expected function that takes 0 arguments
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
index e6bc4e22ec2..d76b69ecdc8 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
@@ -57,17 +57,17 @@ fn moved_loop_2() {
 
 fn uninit_1() {
     loop {
-        let value: NonCopy;
-        let _used = value; //~ ERROR use of possibly-uninitialized variable: `value`
-        //~^ NOTE use of possibly-uninitialized `value`
+        let value: NonCopy; //~ NOTE declared here
+        let _used = value; //~ ERROR binding `value` isn't initialized
+        //~^ NOTE `value` used here but it isn't initialized
     }
 }
 
 fn uninit_2() {
-    let mut value: NonCopy;
+    let mut value: NonCopy; //~ NOTE declared here
     loop {
-        let _used = value; //~ ERROR use of possibly-uninitialized variable: `value`
-        //~^ NOTE use of possibly-uninitialized `value`
+        let _used = value; //~ ERROR binding `value` isn't initialized
+        //~^ NOTE `value` used here but it isn't initialized
     }
 }
 
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
index 076d3dff140..c7373b5be9d 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -40,17 +40,22 @@ LL |     let mut value = NonCopy{};
 LL |         let _used2 = value;
    |                      ^^^^^ value moved here, in previous iteration of loop
 
-error[E0381]: use of possibly-uninitialized variable: `value`
+error[E0381]: used binding `value` isn't initialized
   --> $DIR/issue-72649-uninit-in-loop.rs:61:21
    |
+LL |         let value: NonCopy;
+   |             ----- binding declared here but left uninitialized
 LL |         let _used = value;
-   |                     ^^^^^ use of possibly-uninitialized `value`
+   |                     ^^^^^ `value` used here but it isn't initialized
 
-error[E0381]: use of possibly-uninitialized variable: `value`
+error[E0381]: used binding `value` isn't initialized
   --> $DIR/issue-72649-uninit-in-loop.rs:69:21
    |
+LL |     let mut value: NonCopy;
+   |         --------- binding declared here but left uninitialized
+LL |     loop {
 LL |         let _used = value;
-   |                     ^^^^^ use of possibly-uninitialized `value`
+   |                     ^^^^^ `value` used here but it isn't initialized
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/moves/move-into-dead-array-1.rs b/src/test/ui/moves/move-into-dead-array-1.rs
index 2d0ff585263..0b8d76def87 100644
--- a/src/test/ui/moves/move-into-dead-array-1.rs
+++ b/src/test/ui/moves/move-into-dead-array-1.rs
@@ -11,5 +11,5 @@ fn main() {
 
 fn foo(i: usize) {
     let mut a: [D; 4];
-    a[i] = d();        //~ ERROR use of possibly-uninitialized variable: `a`
+    a[i] = d(); //~ ERROR E0381
 }
diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr
index 5f20ccfeddf..344a6bbf0c9 100644
--- a/src/test/ui/moves/move-into-dead-array-1.stderr
+++ b/src/test/ui/moves/move-into-dead-array-1.stderr
@@ -1,8 +1,10 @@
-error[E0381]: use of possibly-uninitialized variable: `a`
+error[E0381]: used binding `a` isn't initialized
   --> $DIR/move-into-dead-array-1.rs:14:5
    |
+LL |     let mut a: [D; 4];
+   |         ----- binding declared here but left uninitialized
 LL |     a[i] = d();
-   |     ^^^^ use of possibly-uninitialized `a`
+   |     ^^^^ `a` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-of-addr-of-mut.rs b/src/test/ui/moves/move-of-addr-of-mut.rs
index f2f64e43cd2..19fd7028692 100644
--- a/src/test/ui/moves/move-of-addr-of-mut.rs
+++ b/src/test/ui/moves/move-of-addr-of-mut.rs
@@ -5,7 +5,7 @@ struct S;
 
 fn main() {
     let mut x: S;
-    std::ptr::addr_of_mut!(x); //~ borrow of
+    std::ptr::addr_of_mut!(x); //~ ERROR E0381
 
     let y = x; // Should error here if `addr_of_mut` is ever allowed on uninitialized variables
     drop(y);
diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr
index ce8fb028316..e75f2b1c089 100644
--- a/src/test/ui/moves/move-of-addr-of-mut.stderr
+++ b/src/test/ui/moves/move-of-addr-of-mut.stderr
@@ -1,8 +1,10 @@
-error[E0381]: borrow of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/move-of-addr-of-mut.rs:8:5
    |
+LL |     let mut x: S;
+   |         ----- binding declared here but left uninitialized
 LL |     std::ptr::addr_of_mut!(x);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `x`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized
    |
    = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
index ce930eee2e9..125e446c332 100644
--- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
+++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
@@ -4,9 +4,8 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure
 LL |     let i = Box::new(3);
    |         - captured outer variable
 LL |     let _f = to_fn(|| test(i));
-   |                    --------^-
-   |                    |       |
-   |                    |       move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+   |                    --      ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait
+   |                    |
    |                    captured by this `Fn` closure
 
 error: aborting due to previous error
diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr
index fbd86bdb661..b04ea14d1a5 100644
--- a/src/test/ui/namespace/namespace-mix.stderr
+++ b/src/test/ui/namespace/namespace-mix.stderr
@@ -94,7 +94,7 @@ LL |     check(xm7::V);
 LL |         V {},
    |         - `xm7::V` defined here
 LL |         TV(),
-   |         ---- similarly named tuple variant `TV` defined here
+   |         -- similarly named tuple variant `TV` defined here
    |
 help: use struct literal syntax instead
    |
diff --git a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
index 6b9635d4a60..2acf44432c6 100644
--- a/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
+++ b/src/test/ui/never_type/fallback-closure-wrap.fallback.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6] as FnOnce<()>>::Output == ()`
+error[E0271]: type mismatch resolving `<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47] as FnOnce<()>>::Output == ()`
   --> $DIR/fallback-closure-wrap.rs:18:31
    |
 LL |       let error = Closure::wrap(Box::new(move || {
@@ -10,7 +10,7 @@ LL | |     }) as Box<dyn FnMut()>);
    |
    = note: expected unit type `()`
                    found type `!`
-   = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 21:6]` to the object type `dyn FnMut()`
+   = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to the object type `dyn FnMut()`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-captures.stderr b/src/test/ui/nll/closure-captures.stderr
index a59e553315a..5233f0b2462 100644
--- a/src/test/ui/nll/closure-captures.stderr
+++ b/src/test/ui/nll/closure-captures.stderr
@@ -37,36 +37,32 @@ LL |         x = 1;
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:27:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |          x = 1;}
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |          x = 1;}
+   |          - mutable borrow occurs due to use of `x` in closure
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:31:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |     x = 1;});
-   | |_____-_____- in this closure
-   |       |
-   |       mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |     x = 1;});
+   |     - mutable borrow occurs due to use of `x` in closure
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:39:10
@@ -80,19 +76,17 @@ LL |          x = 1;}
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:38:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |          x = 1;}
-   | |__________-_____- in this closure
-   |            |
-   |            mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |          x = 1;}
+   |          - mutable borrow occurs due to use of `x` in closure
 
 error[E0594]: cannot assign to `x`, as it is not declared as mutable
   --> $DIR/closure-captures.rs:43:5
@@ -106,53 +100,47 @@ LL |     x = 1;});
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:42:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |     x = 1;});
-   | |_____-_____- in this closure
-   |       |
-   |       mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |     x = 1;});
+   |     - mutable borrow occurs due to use of `x` in closure
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:48:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(|| {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |         *x = 1;});
-   | |_________--_____- in this closure
-   |           |
-   |           mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(|| {
+   |     ------ -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |         *x = 1;});
+   |         -- mutable borrow occurs due to use of `x` in closure
 
 error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
   --> $DIR/closure-captures.rs:51:9
    |
-LL |   fn fn_ref<F: Fn()>(f: F) -> F { f }
-   |                         - change this to accept `FnMut` instead of `Fn`
+LL | fn fn_ref<F: Fn()>(f: F) -> F { f }
+   |                       - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       fn_ref(move || {
-   |  _____------_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         ||
-   | |         ^^ cannot borrow as mutable
-LL | |         *x = 1;});
-   | |_________--_____- in this closure
-   |           |
-   |           mutable borrow occurs due to use of `x` in closure
+LL |     fn_ref(move || {
+   |     ------ ------- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         ||
+   |         ^^ cannot borrow as mutable
+LL |         *x = 1;});
+   |         -- mutable borrow occurs due to use of `x` in closure
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
index ff16bf0e078..f86a19fff84 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr
@@ -2,7 +2,7 @@ note: no external requirements
   --> $DIR/escape-argument-callee.rs:26:38
    |
 LL |         let mut closure = expect_sig(|p, y| *p = y);
-   |                                      ^^^^^^^^^^^^^
+   |                                      ^^^^^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr
index 49ec0dd931a..8cd8b43cabe 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr
@@ -2,7 +2,7 @@ note: no external requirements
   --> $DIR/escape-argument.rs:26:38
    |
 LL |         let mut closure = expect_sig(|p, y| *p = y);
-   |                                      ^^^^^^^^^^^^^
+   |                                      ^^^^^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
index f0ae4c7fb04..abf80e03928 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/escape-upvar-nested.rs:21:32
    |
 LL |             let mut closure1 = || p = &y;
-   |                                ^^^^^^^^^
+   |                                ^^
    |
    = note: defining type: test::{closure#0}::{closure#0} with closure substs [
                i16,
@@ -15,12 +15,8 @@ LL |             let mut closure1 = || p = &y;
 note: external requirements
   --> $DIR/escape-upvar-nested.rs:20:27
    |
-LL |           let mut closure = || {
-   |  ___________________________^
-LL | |             let mut closure1 = || p = &y;
-LL | |             closure1();
-LL | |         };
-   | |_________^
+LL |         let mut closure = || {
+   |                           ^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
index e99fc4b43a2..bc754642173 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/escape-upvar-ref.rs:23:27
    |
 LL |         let mut closure = || p = &y;
-   |                           ^^^^^^^^^
+   |                           ^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
index 11420efaa06..b9b0f3ad257 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr
@@ -1,12 +1,8 @@
 note: no external requirements
   --> $DIR/propagate-approximated-fail-no-postdom.rs:43:9
    |
-LL | /         |_outlives1, _outlives2, _outlives3, x, y| {
-LL | |             // Only works if 'x: 'y:
-LL | |             let p = x.get();
-LL | |             demand_y(x, y, p)
-LL | |         },
-   | |_________^
+LL |         |_outlives1, _outlives2, _outlives3, x, y| {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
index 98c3c28fb43..a2371ee314a 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr
@@ -1,13 +1,8 @@
 note: external requirements
   --> $DIR/propagate-approximated-ref.rs:43:47
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |  _______________________________________________^
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(x, y, x.get())
-LL | |
-LL | |     });
-   | |_____^
+LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index 3ab55b370c2..e53ae167f12 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -1,12 +1,8 @@
 note: no external requirements
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:21:15
    |
-LL |       foo(cell, |cell_a, cell_x| {
-   |  _______________^
-LL | |         cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
-LL | |
-LL | |     })
-   | |_____^
+LL |     foo(cell, |cell_a, cell_x| {
+   |               ^^^^^^^^^^^^^^^^
    |
    = note: defining type: case1::{closure#0} with closure substs [
                i32,
@@ -41,11 +37,8 @@ LL | | }
 note: external requirements
   --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15
    |
-LL |       foo(cell, |cell_a, cell_x| {
-   |  _______________^
-LL | |         cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
-LL | |     })
-   | |_____^
+LL |     foo(cell, |cell_a, cell_x| {
+   |               ^^^^^^^^^^^^^^^^
    |
    = note: defining type: case2::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index ec2c220b6b8..c3c7eb1bd9e 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -1,14 +1,8 @@
 note: external requirements
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:47
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |  _______________________________________________^
-LL | |
-LL | |
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(x, y, x.get())
-LL | |     });
-   | |_____^
+LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+   |                                               ^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 234212c8876..846e5aedb3e 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -1,14 +1,8 @@
 note: external requirements
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:47
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |  _______________________________________________^
-LL | |
-LL | |
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(x, y, x.get())
-LL | |     });
-   | |_____^
+LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
index 2ec9d4d8db1..a570932eda9 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr
@@ -1,13 +1,8 @@
 note: external requirements
   --> $DIR/propagate-approximated-val.rs:36:45
    |
-LL |       establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
-   |  _____________________________________________^
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(outlives1, outlives2, x.get())
-LL | |
-LL | |     });
-   | |_____^
+LL |     establish_relationships(cell_a, cell_b, |outlives1, outlives2, x, y| {
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
index 21e4232c788..407bc6764d6 100644
--- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr
@@ -1,12 +1,8 @@
 note: external requirements
   --> $DIR/propagate-despite-same-free-region.rs:42:9
    |
-LL | /         |_outlives1, _outlives2, x, y| {
-LL | |             // Only works if 'x: 'y:
-LL | |             let p = x.get();
-LL | |             demand_y(x, y, p)
-LL | |         },
-   | |_________^
+LL |         |_outlives1, _outlives2, x, y| {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
index 8b9b0435420..fcb55d37f31 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr
@@ -1,13 +1,8 @@
 note: no external requirements
   --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:35:47
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
-   |  _______________________________________________^
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(x, y, x.get())
-LL | |
-LL | |     });
-   | |_____^
+LL |     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
+   |                                               ^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
index 060ce690f03..75beae39e23 100644
--- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr
@@ -1,13 +1,8 @@
 note: no external requirements
   --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:39:47
    |
-LL |       establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
-   |  _______________________________________________^
-LL | |         // Only works if 'x: 'y:
-LL | |         demand_y(x, y, x.get())
-LL | |
-LL | |     });
-   | |_____^
+LL |     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: defining type: supply::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
index 08605efa2ea..58aced2bfcd 100644
--- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr
@@ -1,15 +1,8 @@
 note: external requirements
   --> $DIR/propagate-from-trait-match.rs:32:36
    |
-LL |       establish_relationships(value, |value| {
-   |  ____________________________________^
-LL | |
-LL | |
-LL | |         // This function call requires that
-...  |
-LL | |         require(value);
-LL | |     });
-   | |_____^
+LL |     establish_relationships(value, |value| {
+   |                                    ^^^^^^^
    |
    = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
index 5fc1d5c4361..1c9d0c83549 100644
--- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
+++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr
@@ -2,7 +2,7 @@ note: no external requirements
   --> $DIR/return-wrong-bound-region.rs:11:16
    |
 LL |     expect_sig(|a, b| b); // ought to return `a`
-   |                ^^^^^^^^
+   |                ^^^^^^
    |
    = note: defining type: test::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
index ebea6d3d9d1..46a156d2af9 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
+++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.rs
@@ -25,14 +25,12 @@ impl Drop for D {
 
 fn cannot_partially_init_adt_with_drop() {
     let d: D;
-    d.x = 10;
-    //~^ ERROR assign of possibly-uninitialized variable: `d` [E0381]
+    d.x = 10; //~ ERROR E0381
 }
 
 fn cannot_partially_init_mutable_adt_with_drop() {
     let mut d: D;
-    d.x = 10;
-    //~^ ERROR assign of possibly-uninitialized variable: `d` [E0381]
+    d.x = 10; //~ ERROR E0381
 }
 
 fn cannot_partially_reinit_adt_with_drop() {
@@ -44,14 +42,12 @@ fn cannot_partially_reinit_adt_with_drop() {
 
 fn cannot_partially_init_inner_adt_via_outer_with_drop() {
     let d: D;
-    d.s.y = 20;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `d` [E0381]
+    d.s.y = 20; //~ ERROR E0381
 }
 
 fn cannot_partially_init_inner_adt_via_mutable_outer_with_drop() {
     let mut d: D;
-    d.s.y = 20;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `d` [E0381]
+    d.s.y = 20; //~ ERROR E0381
 }
 
 fn cannot_partially_reinit_inner_adt_via_outer_with_drop() {
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
index 1b66e034d37..63f230be7d4 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-erroneous-use.stderr
@@ -1,17 +1,25 @@
-error[E0381]: assign of possibly-uninitialized variable: `d`
+error[E0381]: assigned binding `d` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:28:5
    |
+LL |     let d: D;
+   |         - binding declared here but left uninitialized
 LL |     d.x = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `d`
+   |     ^^^^^^^^ `d` assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign of possibly-uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:34:5
+error[E0381]: assigned binding `d` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:33:5
    |
+LL |     let mut d: D;
+   |         ----- binding declared here but left uninitialized
 LL |     d.x = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `d`
+   |     ^^^^^^^^ `d` assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign of moved value: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:41:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:39:5
    |
 LL |     let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
    |         ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
@@ -20,20 +28,28 @@ LL |     drop(d);
 LL |     d.x = 10;
    |     ^^^^^^^^ value assigned here after move
 
-error[E0381]: assign to part of possibly-uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:47:5
+error[E0381]: partially assigned binding `d` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:45:5
    |
+LL |     let d: D;
+   |         - binding declared here but left uninitialized
 LL |     d.s.y = 20;
-   |     ^^^^^^^^^^ use of possibly-uninitialized `d.s`
+   |     ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:53:5
+error[E0381]: partially assigned binding `d` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:50:5
    |
+LL |     let mut d: D;
+   |         ----- binding declared here but left uninitialized
 LL |     d.s.y = 20;
-   |     ^^^^^^^^^^ use of possibly-uninitialized `d.s`
+   |     ^^^^^^^^^^ `d.s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `d`
-  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:60:5
+  --> $DIR/issue-21232-partial-init-and-erroneous-use.rs:56:5
    |
 LL |     let mut d = D { x: 0, s: S{ y: 0, z: 0} };
    |         ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.rs b/src/test/ui/nll/issue-21232-partial-init-and-use.rs
index 1836f766cc7..4cd1e406f94 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-use.rs
+++ b/src/test/ui/nll/issue-21232-partial-init-and-use.rs
@@ -94,15 +94,13 @@ macro_rules! use_part {
 
 fn test_0000_local_fully_init_and_use_struct() {
     let s: S<B>;
-    s.x = 10; s.y = Box::new(20);
-    //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
+    s.x = 10; s.y = Box::new(20); //~ ERROR E0381
     use_fully!(struct s);
 }
 
 fn test_0001_local_fully_init_and_use_tuple() {
     let t: T;
-    t.0 = 10; t.1 = Box::new(20);
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.0 = 10; t.1 = Box::new(20); //~ ERROR E0381
     use_fully!(tuple t);
 }
 
@@ -122,15 +120,13 @@ fn test_0011_local_fully_reinit_and_use_tuple() {
 
 fn test_0100_local_partial_init_and_use_struct() {
     let s: S<B>;
-    s.x = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
+    s.x = 10; //~ ERROR E0381
     use_part!(struct s);
 }
 
 fn test_0101_local_partial_init_and_use_tuple() {
     let t: T;
-    t.0 = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.0 = 10; //~ ERROR E0381
     use_part!(tuple t);
 }
 
@@ -150,15 +146,13 @@ fn test_0111_local_partial_reinit_and_use_tuple() {
 
 fn test_0200_local_void_init_and_use_struct() {
     let s: S<Void>;
-    s.x = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `s` [E0381]
+    s.x = 10; //~ ERROR E0381
     use_part!(struct s);
 }
 
 fn test_0201_local_void_init_and_use_tuple() {
     let t: Tvoid;
-    t.0 = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `t` [E0381]
+    t.0 = 10; //~ ERROR E0381
     use_part!(tuple t);
 }
 
@@ -173,15 +167,13 @@ fn test_0201_local_void_init_and_use_tuple() {
 
 fn test_1000_field_fully_init_and_use_struct() {
     let q: Q<S<B>>;
-    q.r.f.x = 10; q.r.f.y = Box::new(20);
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.x = 10; q.r.f.y = Box::new(20); //~ ERROR E0381
     use_fully!(struct q.r.f);
 }
 
 fn test_1001_field_fully_init_and_use_tuple() {
     let q: Q<T>;
-    q.r.f.0 = 10; q.r.f.1 = Box::new(20);
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.0 = 10; q.r.f.1 = Box::new(20); //~ ERROR E0381
     use_fully!(tuple q.r.f);
 }
 
@@ -201,15 +193,13 @@ fn test_1011_field_fully_reinit_and_use_tuple() {
 
 fn test_1100_field_partial_init_and_use_struct() {
     let q: Q<S<B>>;
-    q.r.f.x = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.x = 10; //~ ERROR E0381
     use_part!(struct q.r.f);
 }
 
 fn test_1101_field_partial_init_and_use_tuple() {
     let q: Q<T>;
-    q.r.f.0 = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.0 = 10; //~ ERROR E0381
     use_part!(tuple q.r.f);
 }
 
@@ -229,15 +219,13 @@ fn test_1111_field_partial_reinit_and_use_tuple() {
 
 fn test_1200_field_void_init_and_use_struct() {
     let mut q: Q<S<Void>>;
-    q.r.f.x = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.x = 10; //~ ERROR E0381
     use_part!(struct q.r.f);
 }
 
 fn test_1201_field_void_init_and_use_tuple() {
     let mut q: Q<Tvoid>;
-    q.r.f.0 = 10;
-    //~^ ERROR assign to part of possibly-uninitialized variable: `q` [E0381]
+    q.r.f.0 = 10; //~ ERROR E0381
     use_part!(tuple q.r.f);
 }
 
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
index 77fa484c21d..947c9e29b45 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -1,17 +1,25 @@
-error[E0381]: assign to part of possibly-uninitialized variable: `s`
+error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-use.rs:97:5
    |
+LL |     let s: S<B>;
+   |         - binding declared here but left uninitialized
 LL |     s.x = 10; s.y = Box::new(20);
-   |     ^^^^^^^^ use of possibly-uninitialized `s`
+   |     ^^^^^^^^ `s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/issue-21232-partial-init-and-use.rs:104:5
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:103:5
    |
+LL |     let t: T;
+   |         - binding declared here but left uninitialized
 LL |     t.0 = 10; t.1 = Box::new(20);
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `s`
-  --> $DIR/issue-21232-partial-init-and-use.rs:111:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:109:5
    |
 LL |     let mut s: S<B> = S::new(); drop(s);
    |         -----                        - value moved here
@@ -21,7 +29,7 @@ LL |     s.x = 10; s.y = Box::new(20);
    |     ^^^^^^^^ value partially assigned here after move
 
 error[E0382]: assign to part of moved value: `t`
-  --> $DIR/issue-21232-partial-init-and-use.rs:118:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:116:5
    |
 LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         -----                             - value moved here
@@ -30,20 +38,28 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
 LL |     t.0 = 10; t.1 = Box::new(20);
    |     ^^^^^^^^ value partially assigned here after move
 
-error[E0381]: assign to part of possibly-uninitialized variable: `s`
-  --> $DIR/issue-21232-partial-init-and-use.rs:125:5
+error[E0381]: partially assigned binding `s` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:123:5
    |
+LL |     let s: S<B>;
+   |         - binding declared here but left uninitialized
 LL |     s.x = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `s`
+   |     ^^^^^^^^ `s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/issue-21232-partial-init-and-use.rs:132:5
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:129:5
    |
+LL |     let t: T;
+   |         - binding declared here but left uninitialized
 LL |     t.0 = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `s`
-  --> $DIR/issue-21232-partial-init-and-use.rs:139:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:135:5
    |
 LL |     let mut s: S<B> = S::new(); drop(s);
    |         -----                        - value moved here
@@ -53,7 +69,7 @@ LL |     s.x = 10;
    |     ^^^^^^^^ value partially assigned here after move
 
 error[E0382]: assign to part of moved value: `t`
-  --> $DIR/issue-21232-partial-init-and-use.rs:146:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:142:5
    |
 LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         -----                             - value moved here
@@ -62,32 +78,48 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
 LL |     t.0 = 10;
    |     ^^^^^^^^ value partially assigned here after move
 
-error[E0381]: assign to part of possibly-uninitialized variable: `s`
-  --> $DIR/issue-21232-partial-init-and-use.rs:153:5
+error[E0381]: partially assigned binding `s` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:149:5
    |
+LL |     let s: S<Void>;
+   |         - binding declared here but left uninitialized
 LL |     s.x = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `s`
+   |     ^^^^^^^^ `s` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `t`
-  --> $DIR/issue-21232-partial-init-and-use.rs:160:5
+error[E0381]: partially assigned binding `t` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:155:5
    |
+LL |     let t: Tvoid;
+   |         - binding declared here but left uninitialized
 LL |     t.0 = 10;
-   |     ^^^^^^^^ use of possibly-uninitialized `t`
+   |     ^^^^^^^^ `t` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:176:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:170:5
    |
+LL |     let q: Q<S<B>>;
+   |         - binding declared here but left uninitialized
 LL |     q.r.f.x = 10; q.r.f.y = Box::new(20);
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:183:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:176:5
    |
+LL |     let q: Q<T>;
+   |         - binding declared here but left uninitialized
 LL |     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `q.r`
-  --> $DIR/issue-21232-partial-init-and-use.rs:190:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:182:5
    |
 LL |     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
    |                                                 --- value moved here
@@ -97,7 +129,7 @@ LL |     q.r.f.x = 10; q.r.f.y = Box::new(20);
    = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
 
 error[E0382]: assign to part of moved value: `q.r`
-  --> $DIR/issue-21232-partial-init-and-use.rs:197:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:189:5
    |
 LL |     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
    |                                                      --- value moved here
@@ -106,20 +138,28 @@ LL |     q.r.f.0 = 10; q.r.f.1 = Box::new(20);
    |
    = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:204:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:196:5
    |
+LL |     let q: Q<S<B>>;
+   |         - binding declared here but left uninitialized
 LL |     q.r.f.x = 10;
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:211:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:202:5
    |
+LL |     let q: Q<T>;
+   |         - binding declared here but left uninitialized
 LL |     q.r.f.0 = 10;
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `q.r`
-  --> $DIR/issue-21232-partial-init-and-use.rs:218:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:208:5
    |
 LL |     let mut q: Q<S<B>> = Q::new(S::new()); drop(q.r);
    |                                                 --- value moved here
@@ -129,7 +169,7 @@ LL |     q.r.f.x = 10;
    = note: move occurs because `q.r` has type `R<S<Box<u32>>>`, which does not implement the `Copy` trait
 
 error[E0382]: assign to part of moved value: `q.r`
-  --> $DIR/issue-21232-partial-init-and-use.rs:225:5
+  --> $DIR/issue-21232-partial-init-and-use.rs:215:5
    |
 LL |     let mut q: Q<T> = Q::new((0, Box::new(0))); drop(q.r);
    |                                                      --- value moved here
@@ -138,20 +178,28 @@ LL |     q.r.f.0 = 10;
    |
    = note: move occurs because `q.r` has type `R<(u32, Box<u32>)>`, which does not implement the `Copy` trait
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:232:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:222:5
    |
+LL |     let mut q: Q<S<Void>>;
+   |         ----- binding declared here but left uninitialized
 LL |     q.r.f.x = 10;
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
-error[E0381]: assign to part of possibly-uninitialized variable: `q`
-  --> $DIR/issue-21232-partial-init-and-use.rs:239:5
+error[E0381]: partially assigned binding `q` isn't fully initialized
+  --> $DIR/issue-21232-partial-init-and-use.rs:228:5
    |
+LL |     let mut q: Q<Tvoid>;
+   |         ----- binding declared here but left uninitialized
 LL |     q.r.f.0 = 10;
-   |     ^^^^^^^^^^^^ use of possibly-uninitialized `q.r.f`
+   |     ^^^^^^^^^^^^ `q.r.f` partially assigned here but it isn't fully initialized
+   |
+   = help: partial initialization isn't supported, fully initialize the binding with a default value and mutate it, or use `std::mem::MaybeUninit`
 
 error[E0382]: assign to part of moved value: `c`
-  --> $DIR/issue-21232-partial-init-and-use.rs:257:13
+  --> $DIR/issue-21232-partial-init-and-use.rs:245:13
    |
 LL |     let mut c = (1, "".to_owned());
    |         ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait
@@ -162,7 +210,7 @@ LL |             c.0 = 2;
    |             ^^^^^^^ value partially assigned here after move
 
 error[E0382]: assign to part of moved value: `c`
-  --> $DIR/issue-21232-partial-init-and-use.rs:267:13
+  --> $DIR/issue-21232-partial-init-and-use.rs:255:13
    |
 LL |     let mut c = (1, (1, "".to_owned()));
    |         ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
@@ -173,7 +221,7 @@ LL |             (c.1).0 = 2;
    |             ^^^^^^^^^^^ value partially assigned here after move
 
 error[E0382]: assign to part of moved value: `c.1`
-  --> $DIR/issue-21232-partial-init-and-use.rs:275:13
+  --> $DIR/issue-21232-partial-init-and-use.rs:263:13
    |
 LL |         c2 => {
    |         -- value moved here
diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
index c9324f0422c..fb61b30f09d 100644
--- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
+++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr
@@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn`
 LL |        let x = (vec![22], vec![44]);
    |            - captured outer variable
 LL |        expect_fn(|| drop(x.0));
-   |                  --------^^^-
-   |                  |       |
-   |                  |       move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |                  --      ^^^ move occurs because `x.0` has type `Vec<i32>`, which does not implement the `Copy` trait
+   |                  |
    |                  captured by this `Fn` closure
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.stderr
index a5a0fc415bb..036a7a0abfd 100644
--- a/src/test/ui/nll/issue-54556-stephaneyfx.stderr
+++ b/src/test/ui/nll/issue-54556-stephaneyfx.stderr
@@ -10,7 +10,7 @@ LL | }
    | -
    | |
    | `stmt` dropped here while still borrowed
-   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>`
+   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:19]>`
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
diff --git a/src/test/ui/nll/issue-98693.rs b/src/test/ui/nll/issue-98693.rs
new file mode 100644
index 00000000000..18e6ec63046
--- /dev/null
+++ b/src/test/ui/nll/issue-98693.rs
@@ -0,0 +1,21 @@
+// Regression test for #98693.
+//
+// The closure encounters an obligation that `T` must outlive `!U1`,
+// a placeholder from universe U1. We were ignoring this placeholder
+// when promoting the constraint to the enclosing function, and
+// thus incorrectly judging the closure to be safe.
+
+fn assert_static<T>()
+where
+    for<'a> T: 'a,
+{
+}
+
+fn test<T>() {
+    || {
+        //~^ ERROR the parameter type `T` may not live long enough
+        assert_static::<T>();
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-98693.stderr b/src/test/ui/nll/issue-98693.stderr
new file mode 100644
index 00000000000..31689620c64
--- /dev/null
+++ b/src/test/ui/nll/issue-98693.stderr
@@ -0,0 +1,17 @@
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/issue-98693.rs:15:5
+   |
+LL | /     || {
+LL | |
+LL | |         assert_static::<T>();
+LL | |     };
+   | |_____^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test<T: 'static>() {
+   |          +++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/nll/match-cfg-fake-edges.rs b/src/test/ui/nll/match-cfg-fake-edges.rs
index 2e6d675fb64..252f7f8ba07 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.rs
+++ b/src/test/ui/nll/match-cfg-fake-edges.rs
@@ -18,7 +18,7 @@ fn guard_may_be_skipped(y: i32) {
     match y {
         _ if { x = 2; true } => 1,
         _ if {
-            x; //~ ERROR use of possibly-uninitialized variable: `x`
+            x; //~ ERROR E0381
             false
         } => 2,
         _ => 3,
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 4b3817929fd..250aa482e5c 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -1,8 +1,14 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
+error[E0381]: used binding `x` isn't initialized
   --> $DIR/match-cfg-fake-edges.rs:21:13
    |
+LL |     let x;
+   |         - binding declared here but left uninitialized
+...
+LL |         _ if { x = 2; true } => 1,
+   |                ----- binding initialized here in some conditions
+LL |         _ if {
 LL |             x;
-   |             ^ use of possibly-uninitialized `x`
+   |             ^ `x` used here but it isn't initialized
 
 error[E0382]: use of moved value: `x`
   --> $DIR/match-cfg-fake-edges.rs:35:13
diff --git a/src/test/ui/nll/match-on-borrowed.stderr b/src/test/ui/nll/match-on-borrowed.stderr
index 2121b59b02d..664f36f695c 100644
--- a/src/test/ui/nll/match-on-borrowed.stderr
+++ b/src/test/ui/nll/match-on-borrowed.stderr
@@ -33,11 +33,13 @@ LL |     match t {
 LL |     x;
    |     - borrow later used here
 
-error[E0381]: use of possibly-uninitialized variable: `n`
+error[E0381]: used binding `n` isn't initialized
   --> $DIR/match-on-borrowed.rs:93:11
    |
+LL |     let n: Never;
+   |         - binding declared here but left uninitialized
 LL |     match n {}
-   |           ^ use of possibly-uninitialized `n`
+   |           ^ `n` used here but it isn't initialized
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
index 8fe25181da1..feab2476970 100644
--- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/projection-no-regions-closure.rs:25:23
    |
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^
    |
    = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -39,7 +39,7 @@ note: external requirements
   --> $DIR/projection-no-regions-closure.rs:34:23
    |
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^
    |
    = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -66,7 +66,7 @@ note: external requirements
   --> $DIR/projection-no-regions-closure.rs:42:23
    |
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^
    |
    = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -103,7 +103,7 @@ note: external requirements
   --> $DIR/projection-no-regions-closure.rs:52:23
    |
 LL |     with_signature(x, |mut y| Box::new(y.next()))
-   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^
    |
    = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
index caf2e3c4747..98063bd0a76 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/projection-one-region-closure.rs:45:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -56,7 +56,7 @@ note: external requirements
   --> $DIR/projection-one-region-closure.rs:56:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -109,7 +109,7 @@ note: external requirements
   --> $DIR/projection-one-region-closure.rs:70:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -137,7 +137,7 @@ note: external requirements
   --> $DIR/projection-one-region-closure.rs:80:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 4eebe682d4f..45e61bcbda8 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:37:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -44,7 +44,7 @@ note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:47:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -85,7 +85,7 @@ note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:60:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -113,7 +113,7 @@ note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:69:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -141,7 +141,7 @@ note: external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:81:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
index 46a02598e19..f2549205b81 100644
--- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr
@@ -2,7 +2,7 @@ note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:36:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -28,7 +28,7 @@ note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:45:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -54,7 +54,7 @@ note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:64:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -80,7 +80,7 @@ note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:73:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -106,7 +106,7 @@ note: no external requirements
   --> $DIR/projection-one-region-trait-bound-static-closure.rs:85:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index 1ee788b40ab..8e1b6fa2e46 100644
--- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -40,7 +40,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
                i32,
@@ -77,7 +77,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
                i32,
@@ -105,7 +105,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:70:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
                i32,
@@ -133,7 +133,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:79:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [
                i32,
@@ -161,7 +161,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -203,7 +203,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:97:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
@@ -231,7 +231,7 @@ note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:109:29
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
-   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^
    |
    = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
index a4588730b3f..12c76d198e7 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:24:24
    |
 LL |     twice(cell, value, |a, b| invoke(a, b));
-   |                        ^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^
    |
    = note: defining type: generic::<T>::{closure#0} with closure substs [
                i16,
@@ -27,7 +27,7 @@ note: external requirements
   --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
    |
 LL |     twice(cell, value, |a, b| invoke(a, b));
-   |                        ^^^^^^^^^^^^^^^^^^^
+   |                        ^^^^^^
    |
    = note: defining type: generic_fail::<T>::{closure#0} with closure substs [
                i16,
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
index 084dd93cb86..35741859dff 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
@@ -2,7 +2,7 @@ note: external requirements
   --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
    |
 LL |     with_signature(x, |y| y)
-   |                       ^^^^^
+   |                       ^^^
    |
    = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
index 11a737ba291..0261bc39e71 100644
--- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
+++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr
@@ -1,15 +1,8 @@
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
    |
-LL |       with_signature(a, b, |x, y| {
-   |  __________________________^
-LL | |
-LL | |         //
-LL | |         // See `correct_region`, which explains the point of this
-...  |
-LL | |         require(&x, &y)
-LL | |     })
-   | |_____^
+LL |     with_signature(a, b, |x, y| {
+   |                          ^^^^^^
    |
    = note: defining type: no_region::<T>::{closure#0} with closure substs [
                i32,
@@ -55,15 +48,8 @@ LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) {
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
    |
-LL |       with_signature(a, b, |x, y| {
-   |  __________________________^
-LL | |         // Key point of this test:
-LL | |         //
-LL | |         // The *closure* is being type-checked with all of its free
-...  |
-LL | |         require(&x, &y)
-LL | |     })
-   | |_____^
+LL |     with_signature(a, b, |x, y| {
+   |                          ^^^^^^
    |
    = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -90,13 +76,8 @@ LL | | }
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
    |
-LL |       with_signature(a, b, |x, y| {
-   |  __________________________^
-LL | |
-LL | |         // See `correct_region`
-LL | |         require(&x, &y)
-LL | |     })
-   | |_____^
+LL |     with_signature(a, b, |x, y| {
+   |                          ^^^^^^
    |
    = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
@@ -140,12 +121,8 @@ LL |     T: 'b + 'a,
 note: external requirements
   --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
    |
-LL |       with_signature(a, b, |x, y| {
-   |  __________________________^
-LL | |         // See `correct_region`
-LL | |         require(&x, &y)
-LL | |     })
-   | |_____^
+LL |     with_signature(a, b, |x, y| {
+   |                          ^^^^^^
    |
    = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
diff --git a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
index 3326fa521fc..ee332278c30 100644
--- a/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
+++ b/src/test/ui/nll/user-annotations/adt-nullary-enums.stderr
@@ -30,15 +30,14 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
 ...
 LL |             SomeEnum::SomeVariant(Cell::new(&c)),
    |                                   ----------^^-
    |                                   |         |
    |                                   |         borrowed value does not live long enough
    |                                   argument requires that `c` is borrowed for `'a`
-...
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
index 9664fb9f548..95bbd62c4fb 100644
--- a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
@@ -28,28 +28,28 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
 ...
 LL |         f(&c);
    |         --^^-
    |         | |
    |         | borrowed value does not live long enough
    |         argument requires that `c` is borrowed for `'a`
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error[E0597]: `c` does not live long enough
   --> $DIR/adt-tuple-struct-calls.rs:53:11
    |
 LL |     let f = SomeStruct::<&'a u32>;
    |         - lifetime `'1` appears in the type of `f`
-...
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
+LL |         let c = 66;
 LL |         f(&c);
    |         --^^-
    |         | |
    |         | borrowed value does not live long enough
    |         argument requires that `c` is borrowed for `'1`
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/fns.stderr b/src/test/ui/nll/user-annotations/fns.stderr
index e0640da39e2..bd4d121d569 100644
--- a/src/test/ui/nll/user-annotations/fns.stderr
+++ b/src/test/ui/nll/user-annotations/fns.stderr
@@ -28,14 +28,14 @@ error[E0597]: `c` does not live long enough
    |
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
-...
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
+LL |         let c = 66;
 LL |         some_fn::<&'a u32>(&c);
    |         -------------------^^-
    |         |                  |
    |         |                  borrowed value does not live long enough
    |         argument requires that `c` is borrowed for `'a`
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/method-call.stderr b/src/test/ui/nll/user-annotations/method-call.stderr
index 10447e45a6d..fcaeb465d14 100644
--- a/src/test/ui/nll/user-annotations/method-call.stderr
+++ b/src/test/ui/nll/user-annotations/method-call.stderr
@@ -29,13 +29,14 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
 ...
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
+LL |         let c = 66;
 LL |         a.method::<&'a u32>(b,  &c);
    |         ------------------------^^-
    |         |                       |
    |         |                       borrowed value does not live long enough
    |         argument requires that `c` is borrowed for `'a`
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
index e7851833e93..328dde9805a 100644
--- a/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
+++ b/src/test/ui/nll/user-annotations/method-ufcs-3.stderr
@@ -29,13 +29,14 @@ error[E0597]: `c` does not live long enough
 LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
    |                                              -- lifetime `'a` defined here
 ...
+LL |     let _closure = || {
+   |                     - `c` dropped here while still borrowed
+LL |         let c = 66;
 LL |         <_ as Bazoom<_>>::method::<&'a u32>(&a, b, &c);
    |         -------------------------------------------^^-
    |         |                                          |
    |         |                                          borrowed value does not live long enough
    |         argument requires that `c` is borrowed for `'a`
-LL |     };
-   |     - `c` dropped here while still borrowed
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr
index e4c57c04e72..249c2fe2fa7 100644
--- a/src/test/ui/no-send-res-ports.stderr
+++ b/src/test/ui/no-send-res-ports.stderr
@@ -1,17 +1,12 @@
 error[E0277]: `Rc<()>` cannot be sent between threads safely
   --> $DIR/no-send-res-ports.rs:25:5
    |
-LL |       thread::spawn(move|| {
-   |  _____^^^^^^^^^^^^^_-
-   | |     |
-   | |     `Rc<()>` cannot be sent between threads safely
-LL | |
-LL | |         let y = x;
-LL | |         println!("{:?}", y);
-LL | |     });
-   | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`
+LL |     thread::spawn(move|| {
+   |     ^^^^^^^^^^^^^ ------ within this `[closure@$DIR/no-send-res-ports.rs:25:19: 25:25]`
+   |     |
+   |     `Rc<()>` cannot be sent between threads safely
    |
-   = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>`
+   = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 25:25]`, the trait `Send` is not implemented for `Rc<()>`
 note: required because it appears within the type `Port<()>`
   --> $DIR/no-send-res-ports.rs:5:8
    |
@@ -25,13 +20,8 @@ LL |     struct Foo {
 note: required because it's used within this closure
   --> $DIR/no-send-res-ports.rs:25:19
    |
-LL |       thread::spawn(move|| {
-   |  ___________________^
-LL | |
-LL | |         let y = x;
-LL | |         println!("{:?}", y);
-LL | |     });
-   | |_____^
+LL |     thread::spawn(move|| {
+   |                   ^^^^^^
 note: required by a bound in `spawn`
   --> $SRC_DIR/std/src/thread/mod.rs:LL:COL
    |
diff --git a/src/test/ui/non-fmt-panic.stderr b/src/test/ui/non-fmt-panic.stderr
index 4da97ed5d60..6e4434e6f33 100644
--- a/src/test/ui/non-fmt-panic.stderr
+++ b/src/test/ui/non-fmt-panic.stderr
@@ -73,9 +73,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, S);
    |                    ^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     assert!(false, "{}", S);
    |                    +++++
@@ -86,9 +86,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, 123);
    |                    ^^^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     assert!(false, "{}", 123);
    |                    +++++
@@ -99,9 +99,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, Some(123));
    |                    ^^^^^^^^^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{:?}" format string to use the Debug implementation of `Option<i32>`
+help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
    |
 LL |     assert!(false, "{:?}", Some(123));
    |                    +++++++
@@ -124,9 +124,9 @@ warning: panic message is not a string literal
 LL |     panic!(C);
    |            ^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", C);
    |            +++++
@@ -137,9 +137,9 @@ warning: panic message is not a string literal
 LL |     panic!(S);
    |            ^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", S);
    |            +++++
@@ -150,9 +150,9 @@ warning: panic message is not a string literal
 LL |     unreachable!(S);
    |                  ^
    |
-   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     unreachable!("{}", S);
    |                  +++++
@@ -163,9 +163,9 @@ warning: panic message is not a string literal
 LL |     unreachable!(S);
    |                  ^
    |
-   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     unreachable!("{}", S);
    |                  +++++
@@ -176,9 +176,9 @@ warning: panic message is not a string literal
 LL |     std::panic!(123);
    |                 ^^^
    |
-   = note: this usage of std::panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     std::panic!("{}", 123);
    |                 +++++
@@ -193,9 +193,9 @@ warning: panic message is not a string literal
 LL |     core::panic!(&*"abc");
    |                  ^^^^^^^
    |
-   = note: this usage of core::panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     core::panic!("{}", &*"abc");
    |                  +++++
@@ -206,9 +206,9 @@ warning: panic message is not a string literal
 LL |     panic!(Some(123));
    |            ^^^^^^^^^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{:?}" format string to use the Debug implementation of `Option<i32>`
+help: add a "{:?}" format string to use the `Debug` implementation of `Option<i32>`
    |
 LL |     panic!("{:?}", Some(123));
    |            +++++++
@@ -259,9 +259,9 @@ warning: panic message is not a string literal
 LL |     panic!(a!());
    |            ^^^^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", a!());
    |            +++++
@@ -276,9 +276,9 @@ warning: panic message is not a string literal
 LL |     unreachable!(a!());
    |                  ^^^^
    |
-   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     unreachable!("{}", a!());
    |                  +++++
@@ -289,9 +289,9 @@ warning: panic message is not a string literal
 LL |     panic!(format!("{}", 1));
    |            ^^^^^^^^^^^^^^^^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-   = note: the panic!() macro supports formatting, so there's no need for the format!() macro here
+   = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here
 help: remove the `format!(..)` macro call
    |
 LL -     panic!(format!("{}", 1));
@@ -304,9 +304,9 @@ warning: panic message is not a string literal
 LL |     unreachable!(format!("{}", 1));
    |                  ^^^^^^^^^^^^^^^^
    |
-   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-   = note: the unreachable!() macro supports formatting, so there's no need for the format!() macro here
+   = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here
 help: remove the `format!(..)` macro call
    |
 LL -     unreachable!(format!("{}", 1));
@@ -319,9 +319,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, format!("{}", 1));
    |                    ^^^^^^^^^^^^^^^^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-   = note: the assert!() macro supports formatting, so there's no need for the format!() macro here
+   = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here
 help: remove the `format!(..)` macro call
    |
 LL -     assert!(false, format!("{}", 1));
@@ -334,9 +334,9 @@ warning: panic message is not a string literal
 LL |     debug_assert!(false, format!("{}", 1));
    |                          ^^^^^^^^^^^^^^^^
    |
-   = note: this usage of debug_assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-   = note: the debug_assert!() macro supports formatting, so there's no need for the format!() macro here
+   = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here
 help: remove the `format!(..)` macro call
    |
 LL -     debug_assert!(false, format!("{}", 1));
@@ -349,9 +349,9 @@ warning: panic message is not a string literal
 LL |     panic![123];
    |            ^^^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!["{}", 123];
    |            +++++
@@ -366,9 +366,9 @@ warning: panic message is not a string literal
 LL |     panic!{123};
    |            ^^^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!{"{}", 123};
    |            +++++
@@ -385,7 +385,7 @@ LL |     panic!(v);
    |     |
    |     help: use std::panic::panic_any instead: `std::panic::panic_any`
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
 
 warning: panic message is not a string literal
@@ -394,7 +394,7 @@ warning: panic message is not a string literal
 LL |     assert!(false, v);
    |                    ^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
 
 warning: panic message is not a string literal
@@ -403,9 +403,9 @@ warning: panic message is not a string literal
 LL |     panic!(v);
    |            ^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{:?}" format string to use the Debug implementation of `T`
+help: add a "{:?}" format string to use the `Debug` implementation of `T`
    |
 LL |     panic!("{:?}", v);
    |            +++++++
@@ -420,9 +420,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, v);
    |                    ^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{:?}" format string to use the Debug implementation of `T`
+help: add a "{:?}" format string to use the `Debug` implementation of `T`
    |
 LL |     assert!(false, "{:?}", v);
    |                    +++++++
@@ -433,9 +433,9 @@ warning: panic message is not a string literal
 LL |     panic!(v);
    |            ^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", v);
    |            +++++
@@ -450,9 +450,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, v);
    |                    ^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     assert!(false, "{}", v);
    |                    +++++
@@ -463,9 +463,9 @@ warning: panic message is not a string literal
 LL |     panic!(v);
    |            ^
    |
-   = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     panic!("{}", v);
    |            +++++
@@ -480,9 +480,9 @@ warning: panic message is not a string literal
 LL |     assert!(false, v);
    |                    ^
    |
-   = note: this usage of assert!() is deprecated; it will be a hard error in Rust 2021
+   = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
-help: add a "{}" format string to Display the message
+help: add a "{}" format string to `Display` the message
    |
 LL |     assert!(false, "{}", v);
    |                    +++++
diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr
index 88e9cd6a9c0..0c696163a26 100644
--- a/src/test/ui/noncopyable-class.stderr
+++ b/src/test/ui/noncopyable-class.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Foo` in the current scop
   --> $DIR/noncopyable-class.rs:34:16
    |
 LL | struct Foo {
-   |        --- method `clone` not found for this struct
+   | ---------- method `clone` not found for this struct
 ...
 LL |     let _y = x.clone();
    |                ^^^^^ method not found in `Foo`
diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr
index bebf561b120..37d94cf0ebd 100644
--- a/src/test/ui/not-clone-closure.stderr
+++ b/src/test/ui/not-clone-closure.stderr
@@ -1,23 +1,17 @@
-error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`
+error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`
   --> $DIR/not-clone-closure.rs:11:23
    |
-LL |       let hello = move || {
-   |  _________________-
-LL | |         println!("Hello {}", a.0);
-LL | |     };
-   | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`
-LL |
-LL |       let hello = hello.clone();
-   |                         ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S`
+LL |     let hello = move || {
+   |                 ------- within this `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`
+...
+LL |     let hello = hello.clone();
+   |                       ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 7:24]`, the trait `Clone` is not implemented for `S`
    |
 note: required because it's used within this closure
   --> $DIR/not-clone-closure.rs:7:17
    |
-LL |       let hello = move || {
-   |  _________________^
-LL | |         println!("Hello {}", a.0);
-LL | |     };
-   | |_____^
+LL |     let hello = move || {
+   |                 ^^^^^^^
 help: consider annotating `S` with `#[derive(Clone)]`
    |
 LL | #[derive(Clone)]
diff --git a/src/test/ui/panic-runtime/auxiliary/needs-abort.rs b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs
new file mode 100644
index 00000000000..8fad49b5e9d
--- /dev/null
+++ b/src/test/ui/panic-runtime/auxiliary/needs-abort.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
diff --git a/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs
new file mode 100644
index 00000000000..d555b531986
--- /dev/null
+++ b/src/test/ui/panic-runtime/auxiliary/needs-unwind.rs
@@ -0,0 +1,13 @@
+// compile-flags:-C panic=unwind
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![no_std]
+#![feature(c_unwind)]
+
+extern "C-unwind" fn foo() {}
+
+fn bar() {
+    let ptr: extern "C-unwind" fn() = foo;
+    ptr();
+}
diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.rs b/src/test/ui/panic-runtime/need-abort-got-unwind.rs
new file mode 100644
index 00000000000..c72fb96e357
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-abort-got-unwind.rs
@@ -0,0 +1,9 @@
+// build-fail
+// needs-unwind
+// error-pattern:is incompatible with this crate's strategy of `unwind`
+// aux-build:needs-abort.rs
+// ignore-wasm32-bare compiled with panic=abort by default
+
+extern crate needs_abort;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/need-abort-got-unwind.stderr b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr
new file mode 100644
index 00000000000..d29c7875fd0
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-abort-got-unwind.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.rs b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
new file mode 100644
index 00000000000..6752ecf90d2
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.rs
@@ -0,0 +1,9 @@
+// build-fail
+// error-pattern:is incompatible with this crate's strategy of `abort`
+// aux-build:needs-unwind.rs
+// compile-flags:-C panic=abort
+// no-prefer-dynamic
+
+extern crate needs_unwind;
+
+fn main() {}
diff --git a/src/test/ui/panic-runtime/need-unwind-got-abort.stderr b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
new file mode 100644
index 00000000000..4c71df3ebc1
--- /dev/null
+++ b/src/test/ui/panic-runtime/need-unwind-got-abort.stderr
@@ -0,0 +1,4 @@
+error: the crate `needs_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
index 4af754c81f9..7f4a8ed290e 100644
--- a/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
+++ b/src/test/ui/panic-runtime/transitive-link-a-bunch.stderr
@@ -2,9 +2,7 @@ error: cannot link together two panic runtimes: panic_runtime_unwind and panic_r
 
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.rs b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
index c48caaf0790..23bfea6af15 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.rs
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.rs
@@ -1,6 +1,6 @@
 // build-fail
 // needs-unwind
-// error-pattern:is incompatible with this crate's strategy of `unwind`
+// error-pattern:is not compiled with this crate's panic strategy `unwind`
 // aux-build:panic-runtime-abort.rs
 // aux-build:panic-runtime-lang-items.rs
 // ignore-wasm32-bare compiled with panic=abort by default
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
index d4fd2cca81f..d306ce6c5ea 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort.stderr
@@ -1,6 +1,4 @@
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
index 364a27a24eb..014437b7f1b 100644
--- a/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
+++ b/src/test/ui/panic-runtime/want-unwind-got-abort2.stderr
@@ -1,8 +1,6 @@
 error: the linked panic runtime `panic_runtime_abort` is not compiled with this crate's panic strategy `unwind`
 
-error: the crate `wants_panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
+error: the crate `wants_panic_runtime_abort` requires panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
 
-error: the crate `panic_runtime_abort` is compiled with the panic strategy `abort` which is incompatible with this crate's strategy of `unwind`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/panics/location-detail-unwrap-no-file.rs b/src/test/ui/panics/location-detail-unwrap-no-file.rs
index 16cf8a17ff1..5955d9a25ae 100644
--- a/src/test/ui/panics/location-detail-unwrap-no-file.rs
+++ b/src/test/ui/panics/location-detail-unwrap-no-file.rs
@@ -1,6 +1,6 @@
 // run-fail
 // check-run-results
-// compile-flags: -Zlocation-detail=line,column
+// compile-flags: -Copt-level=0 -Zlocation-detail=line,column
 // exec-env:RUST_BACKTRACE=0
 
 fn main() {
diff --git a/src/test/ui/parser/emoji-identifiers.stderr b/src/test/ui/parser/emoji-identifiers.stderr
index 40a85f7f74c..2550dc3d321 100644
--- a/src/test/ui/parser/emoji-identifiers.stderr
+++ b/src/test/ui/parser/emoji-identifiers.stderr
@@ -77,7 +77,7 @@ error[E0599]: no function or associated item named `full_of✨` found for struct
   --> $DIR/emoji-identifiers.rs:9:8
    |
 LL | struct 👀;
-   |        -- function or associated item `full_of✨` not found for this struct
+   | --------- function or associated item `full_of✨` not found for this struct
 ...
 LL |     👀::full_of✨()
    |         ^^^^^^^^^
diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr
index d4f64a7de5b..858b4e8db05 100644
--- a/src/test/ui/parser/expr-as-stmt.stderr
+++ b/src/test/ui/parser/expr-as-stmt.stderr
@@ -200,7 +200,7 @@ LL |     { true } || { true }
    |              ^^^^^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:25]`
+           found closure `[closure@$DIR/expr-as-stmt.rs:51:14: 51:16]`
 help: use parentheses to call this closure
    |
 LL |     { true } (|| { true })()
diff --git a/src/test/ui/parser/macro/macro-doc-comments-1.stderr b/src/test/ui/parser/macro/macro-doc-comments-1.stderr
index 96bdb9808ee..0ebf3d52b63 100644
--- a/src/test/ui/parser/macro/macro-doc-comments-1.stderr
+++ b/src/test/ui/parser/macro/macro-doc-comments-1.stderr
@@ -5,7 +5,10 @@ LL | macro_rules! outer {
    | ------------------ when calling this macro
 ...
 LL |     //! Inner
-   |     ^^^^^^^^^ no rules expected this token in macro call
+   |     ^^^^^^^^^
+   |     |
+   |     no rules expected this token in macro call
+   |     inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/macro/macro-doc-comments-2.stderr b/src/test/ui/parser/macro/macro-doc-comments-2.stderr
index 023d1a3e039..346d865868d 100644
--- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr
+++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr
@@ -5,7 +5,10 @@ LL | macro_rules! inner {
    | ------------------ when calling this macro
 ...
 LL |     /// Outer
-   |     ^^^^^^^^^ no rules expected this token in macro call
+   |     ^^^^^^^^^
+   |     |
+   |     no rules expected this token in macro call
+   |     outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
index e71f15ebfd2..0852c7cb470 100644
--- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
+++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr
@@ -24,7 +24,7 @@ LL | |     }.hi() {
    | |__________^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 14:11]`
+           found closure `[closure@$DIR/struct-literal-restrictions-in-lamda.rs:12:11: 12:13]`
 help: use parentheses to call this closure
    |
 LL ~     while (|| Foo {
diff --git a/src/test/ui/pattern/non-structural-match-types.stderr b/src/test/ui/pattern/non-structural-match-types.stderr
index e9b56cdc05d..45e16264973 100644
--- a/src/test/ui/pattern/non-structural-match-types.stderr
+++ b/src/test/ui/pattern/non-structural-match-types.stderr
@@ -1,4 +1,4 @@
-error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used in patterns
+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 { || {} } => {},
diff --git a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
index 019cd414d2e..d9295746158 100644
--- a/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
+++ b/src/test/ui/pattern/pat-tuple-field-count-cross.stderr
@@ -5,7 +5,10 @@ LL | use declarations_for_tuple_field_count_errors::*;
    |     -------------------------------------------- the tuple struct `Z1` is imported here
 ...
 LL |         Z1 => {}
-   |         ^^ cannot be named the same as a tuple struct
+   |         ^^
+   |         |
+   |         cannot be named the same as a tuple struct
+   |         help: try specify the pattern arguments: `Z1(..)`
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
   --> $DIR/pat-tuple-field-count-cross.rs:9:9
@@ -60,7 +63,7 @@ LL |         E1::Z0() => {}
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15
    |
 LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
-   |               --  ---- similarly named tuple variant `Z1` defined here
+   |               --  -- similarly named tuple variant `Z1` defined here
    |               |
    |               `E1::Z0` defined here
    |
@@ -82,7 +85,7 @@ LL |         E1::Z0(x) => {}
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:15
    |
 LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
-   |               --  ---- similarly named tuple variant `Z1` defined here
+   |               --  -- similarly named tuple variant `Z1` defined here
    |               |
    |               `E1::Z0` defined here
    |
@@ -104,7 +107,7 @@ LL |         E1::Z1 => {}
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19
    |
 LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
-   |               --  ---- `E1::Z1` defined here
+   |               --  -- `E1::Z1` defined here
    |               |
    |               similarly named unit variant `Z0` defined here
    |
@@ -295,7 +298,7 @@ LL |         E1::Z1(x) => {}
   ::: $DIR/auxiliary/declarations-for-tuple-field-count-errors.rs:11:19
    |
 LL | pub enum E1 { Z0, Z1(), S(u8, u8, u8) }
-   |                   ---- tuple variant has 0 fields
+   |                   -- tuple variant has 0 fields
 
 error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 3 fields
   --> $DIR/pat-tuple-field-count-cross.rs:39:9
diff --git a/src/test/ui/pattern/pat-tuple-overfield.stderr b/src/test/ui/pattern/pat-tuple-overfield.stderr
index 9e13a2dc9fb..54d89e03101 100644
--- a/src/test/ui/pattern/pat-tuple-overfield.stderr
+++ b/src/test/ui/pattern/pat-tuple-overfield.stderr
@@ -5,7 +5,10 @@ LL | struct Z1();
    | ------------ the tuple struct `Z1` is defined here
 ...
 LL |         Z1 => {}
-   |         ^^ cannot be named the same as a tuple struct
+   |         ^^
+   |         |
+   |         cannot be named the same as a tuple struct
+   |         help: try specify the pattern arguments: `Z1(..)`
 
 error[E0532]: expected tuple struct or tuple variant, found unit struct `Z0`
   --> $DIR/pat-tuple-overfield.rs:52:9
@@ -289,7 +292,7 @@ error[E0023]: this pattern has 1 field, but the corresponding tuple variant has
   --> $DIR/pat-tuple-overfield.rs:71:16
    |
 LL |     Z1(),
-   |     ---- tuple variant has 0 fields
+   |     -- tuple variant has 0 fields
 ...
 LL |         E1::Z1(_) => {}
    |                ^ expected 0 fields, found 1
@@ -298,7 +301,7 @@ error[E0023]: this pattern has 2 fields, but the corresponding tuple variant has
   --> $DIR/pat-tuple-overfield.rs:72:16
    |
 LL |     Z1(),
-   |     ---- tuple variant has 0 fields
+   |     -- tuple variant has 0 fields
 ...
 LL |         E1::Z1(_, _) => {}
    |                ^  ^ expected 0 fields, found 2
diff --git a/src/test/ui/pattern/pattern-binding-disambiguation.stderr b/src/test/ui/pattern/pattern-binding-disambiguation.stderr
index faa0d7c3074..1529e538b55 100644
--- a/src/test/ui/pattern/pattern-binding-disambiguation.stderr
+++ b/src/test/ui/pattern/pattern-binding-disambiguation.stderr
@@ -5,7 +5,10 @@ LL | struct TupleStruct();
    | --------------------- the tuple struct `TupleStruct` is defined here
 ...
 LL |         TupleStruct => {}
-   |         ^^^^^^^^^^^ cannot be named the same as a tuple struct
+   |         ^^^^^^^^^^^
+   |         |
+   |         cannot be named the same as a tuple struct
+   |         help: try specify the pattern arguments: `TupleStruct(..)`
 
 error[E0530]: match bindings cannot shadow tuple variants
   --> $DIR/pattern-binding-disambiguation.rs:33:9
@@ -14,7 +17,10 @@ LL | use E::*;
    |     ---- the tuple variant `TupleVariant` is imported here
 ...
 LL |         TupleVariant => {}
-   |         ^^^^^^^^^^^^ cannot be named the same as a tuple variant
+   |         ^^^^^^^^^^^^
+   |         |
+   |         cannot be named the same as a tuple variant
+   |         help: try specify the pattern arguments: `TupleVariant(..)`
 
 error[E0530]: match bindings cannot shadow struct variants
   --> $DIR/pattern-binding-disambiguation.rs:36:9
diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr
index f174215f257..fdf817caea7 100644
--- a/src/test/ui/polymorphization/const_parameters/closures.stderr
+++ b/src/test/ui/polymorphization/const_parameters/closures.stderr
@@ -14,7 +14,7 @@ LL | pub fn unused<const T: usize>() -> usize {
    |               -------------- generic parameter `T` is unused
 LL |
 LL |     let add_one = |x: usize| x + 1;
-   |                   ^^^^^^^^^^^^^^^^
+   |                   ^^^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:17:8
@@ -29,7 +29,7 @@ LL | pub fn used_parent<const T: usize>() -> usize {
    |                    -------------- generic parameter `T` is unused
 LL |     let x: usize = T;
 LL |     let add_one = |x: usize| x + 1;
-   |                   ^^^^^^^^^^^^^^^^
+   |                   ^^^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:48:13
@@ -38,7 +38,7 @@ LL | pub fn unused_upvar<const T: usize>() -> usize {
    |                     -------------- generic parameter `T` is unused
 LL |     let x: usize = T;
 LL |     let y = || x;
-   |             ^^^^
+   |             ^^
 
 error: aborting due to 4 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/polymorphization/generators.rs b/src/test/ui/polymorphization/generators.rs
index 68ea4a026d7..779bac0ace2 100644
--- a/src/test/ui/polymorphization/generators.rs
+++ b/src/test/ui/polymorphization/generators.rs
@@ -1,5 +1,5 @@
 // build-fail
-// compile-flags:-Zpolymorphize=on
+// compile-flags:-Zpolymorphize=on -Zinline-mir=off
 #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)]
 //~^ WARN the feature `generic_const_exprs` is incomplete
 
diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr
index 5edbb119f78..a24eee5fed1 100644
--- a/src/test/ui/polymorphization/generators.stderr
+++ b/src/test/ui/polymorphization/generators.stderr
@@ -10,16 +10,12 @@ LL | #![feature(generic_const_exprs, generators, generator_trait, rustc_attrs)]
 error: item has unused generic parameters
   --> $DIR/generators.rs:35:5
    |
-LL |   pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-   |                      - generic parameter `T` is unused
-LL | /     || {
-LL | |
-LL | |         yield 1;
-LL | |         2
-LL | |     }
-   | |_____^
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                    - generic parameter `T` is unused
+LL |     || {
+   |     ^^
 
-note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 39:6], u32, u32>`
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:35:5: 35:7], u32, u32>`
   --> $DIR/generators.rs:86:5
    |
 LL |     finish(unused_type::<u32>());
@@ -28,16 +24,12 @@ LL |     finish(unused_type::<u32>());
 error: item has unused generic parameters
   --> $DIR/generators.rs:60:5
    |
-LL |   pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
-   |                       ------------ generic parameter `T` is unused
-LL | /     || {
-LL | |
-LL | |         yield 1;
-LL | |         2
-LL | |     }
-   | |_____^
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+   |                     ------------ generic parameter `T` is unused
+LL |     || {
+   |     ^^
 
-note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 64:6], u32, u32>`
+note: the above error was encountered while instantiating `fn finish::<[generator@$DIR/generators.rs:60:5: 60:7], u32, u32>`
   --> $DIR/generators.rs:89:5
    |
 LL |     finish(unused_const::<1u32>());
diff --git a/src/test/ui/polymorphization/lifetimes.stderr b/src/test/ui/polymorphization/lifetimes.stderr
index 2020256717c..4773dd4fa2e 100644
--- a/src/test/ui/polymorphization/lifetimes.stderr
+++ b/src/test/ui/polymorphization/lifetimes.stderr
@@ -11,7 +11,7 @@ LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
    |                 - generic parameter `T` is unused
 LL |     let _: T = Default::default();
 LL |     let add_one = |x: u32| x + 1;
-   |                   ^^^^^^^^^^^^^^
+   |                   ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/polymorphization/predicates.rs b/src/test/ui/polymorphization/predicates.rs
index dea1e21e77f..6a5fc2e33de 100644
--- a/src/test/ui/polymorphization/predicates.rs
+++ b/src/test/ui/polymorphization/predicates.rs
@@ -1,5 +1,6 @@
 // build-fail
-// compile-flags:-Zpolymorphize=on
+// compile-flags: -Copt-level=0 -Zpolymorphize=on
+
 #![feature(rustc_attrs)]
 
 // This test checks that `T` is considered used in `foo`, because it is used in a predicate for
diff --git a/src/test/ui/polymorphization/predicates.stderr b/src/test/ui/polymorphization/predicates.stderr
index dc6ebceae21..e5af1d7515f 100644
--- a/src/test/ui/polymorphization/predicates.stderr
+++ b/src/test/ui/polymorphization/predicates.stderr
@@ -1,17 +1,17 @@
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:14:4
+  --> $DIR/predicates.rs:15:4
    |
 LL | fn foo<I, T>(_: I)
    |    ^^^    - generic parameter `T` is unused
 
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:23:4
+  --> $DIR/predicates.rs:24:4
    |
 LL | fn baz<I, T>(_: I)
    |    ^^^    - generic parameter `T` is unused
 
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:44:19
+  --> $DIR/predicates.rs:45:19
    |
 LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
    |          -         - generic parameter `E` is unused
@@ -19,10 +19,10 @@ LL | impl<'a, I, T: 'a, E> Iterator for Foo<'a, I, E>
    |          generic parameter `I` is unused
 ...
 LL |         self.find(|_| true)
-   |                   ^^^^^^^^
+   |                   ^^^
 
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:58:4
+  --> $DIR/predicates.rs:59:4
    |
 LL | fn quux<A, B, C: Default>() -> usize
    |    ^^^^ -  - generic parameter `B` is unused
@@ -30,19 +30,19 @@ LL | fn quux<A, B, C: Default>() -> usize
    |         generic parameter `A` is unused
 
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:75:4
+  --> $DIR/predicates.rs:76:4
    |
 LL | fn foobar<F, G>() -> usize
    |    ^^^^^^ - generic parameter `F` is unused
 
 error: item has unused generic parameters
-  --> $DIR/predicates.rs:9:4
+  --> $DIR/predicates.rs:10:4
    |
 LL | fn bar<I>() {
    |    ^^^ - generic parameter `I` is unused
 
 note: the above error was encountered while instantiating `fn foo::<std::slice::Iter<u32>, T>`
-  --> $DIR/predicates.rs:85:5
+  --> $DIR/predicates.rs:86:5
    |
 LL |     foo(x.iter());
    |     ^^^^^^^^^^^^^
diff --git a/src/test/ui/polymorphization/type_parameters/closures.stderr b/src/test/ui/polymorphization/type_parameters/closures.stderr
index 417feebbc55..94a4a08bd2f 100644
--- a/src/test/ui/polymorphization/type_parameters/closures.stderr
+++ b/src/test/ui/polymorphization/type_parameters/closures.stderr
@@ -5,7 +5,7 @@ LL | pub fn unused<T>() -> u32 {
    |               - generic parameter `T` is unused
 ...
 LL |     let add_one = |x: u32| x + 1;
-   |                   ^^^^^^^^^^^^^^
+   |                   ^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:16:8
@@ -20,7 +20,7 @@ LL | pub fn used_parent<T: Default>() -> u32 {
    |                    - generic parameter `T` is unused
 LL |     let _: T = Default::default();
 LL |     let add_one = |x: u32| x + 1;
-   |                   ^^^^^^^^^^^^^^
+   |                   ^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:94:23
@@ -32,7 +32,7 @@ LL |     pub fn unused_all<G: Default>() -> u32 {
    |                       - generic parameter `G` is unused
 LL |
 LL |         let add_one = |x: u32| x + 1;
-   |                       ^^^^^^^^^^^^^^
+   |                       ^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:92:12
@@ -46,16 +46,11 @@ LL |     pub fn unused_all<G: Default>() -> u32 {
 error: item has unused generic parameters
   --> $DIR/closures.rs:128:23
    |
-LL |       pub fn used_impl<G: Default>() -> u32 {
-   |                        - generic parameter `G` is unused
+LL |     pub fn used_impl<G: Default>() -> u32 {
+   |                      - generic parameter `G` is unused
 LL |
-LL |           let add_one = |x: u32| {
-   |  _______________________^
-LL | |
-LL | |             let _: F = Default::default();
-LL | |             x + 1
-LL | |         };
-   | |_________^
+LL |         let add_one = |x: u32| {
+   |                       ^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:126:12
@@ -66,16 +61,11 @@ LL |     pub fn used_impl<G: Default>() -> u32 {
 error: item has unused generic parameters
   --> $DIR/closures.rs:115:23
    |
-LL |   impl<F: Default> Foo<F> {
-   |        - generic parameter `F` is unused
+LL | impl<F: Default> Foo<F> {
+   |      - generic parameter `F` is unused
 ...
-LL |           let add_one = |x: u32| {
-   |  _______________________^
-LL | |
-LL | |             let _: G = Default::default();
-LL | |             x + 1
-LL | |         };
-   | |_________^
+LL |         let add_one = |x: u32| {
+   |                       ^^^^^^^^
 
 error: item has unused generic parameters
   --> $DIR/closures.rs:113:12
diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr
index b51cc5c719f..27f88d28174 100644
--- a/src/test/ui/polymorphization/unsized_cast.stderr
+++ b/src/test/ui/polymorphization/unsized_cast.stderr
@@ -5,16 +5,16 @@ LL | fn foo<T: Default>() {
    |        - generic parameter `T` is unused
 LL |     let _: T = Default::default();
 LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
-   |                  ^^^^^
+   |                  ^^
 
 error: item has unused generic parameters
-  --> $DIR/unsized_cast.rs:11:5
+  --> $DIR/unsized_cast.rs:11:6
    |
 LL | fn foo<T: Default>() {
    |        - generic parameter `T` is unused
 LL |     let _: T = Default::default();
 LL |     (|| Box::new(|| {}) as Box<dyn Fn()>)();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |      ^^
 
 error: item has unused generic parameters
   --> $DIR/unsized_cast.rs:22:15
@@ -23,21 +23,16 @@ LL | fn foo2<T: Default>() {
    |         - generic parameter `T` is unused
 ...
 LL |         call(&|| {}, ());
-   |               ^^^^^
+   |               ^^
 
 error: item has unused generic parameters
-  --> $DIR/unsized_cast.rs:19:5
+  --> $DIR/unsized_cast.rs:19:6
    |
-LL |   fn foo2<T: Default>() {
-   |           - generic parameter `T` is unused
-LL |       let _: T = Default::default();
-LL | /     (|| {
-LL | |
-LL | |         let call: extern "rust-call" fn(_, _) = Fn::call;
-LL | |         call(&|| {}, ());
-LL | |
-LL | |     })();
-   | |______^
+LL | fn foo2<T: Default>() {
+   |         - generic parameter `T` is unused
+LL |     let _: T = Default::default();
+LL |     (|| {
+   |      ^^
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/proc-macro/auxiliary/expand-expr.rs b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
index 2bc34f3c6bf..5463e79d74e 100644
--- a/src/test/ui/proc-macro/auxiliary/expand-expr.rs
+++ b/src/test/ui/proc-macro/auxiliary/expand-expr.rs
@@ -10,6 +10,72 @@ extern crate proc_macro;
 use proc_macro::*;
 use std::str::FromStr;
 
+// Flatten the TokenStream, removing any toplevel `Delimiter::None`s for
+// comparison.
+fn flatten(ts: TokenStream) -> Vec<TokenTree> {
+    ts.into_iter()
+        .flat_map(|tt| match &tt {
+            TokenTree::Group(group) if group.delimiter() == Delimiter::None => {
+                flatten(group.stream())
+            }
+            _ => vec![tt],
+        })
+        .collect()
+}
+
+// Assert that two TokenStream values are roughly equal to one-another.
+fn assert_ts_eq(lhs: &TokenStream, rhs: &TokenStream) {
+    let ltts = flatten(lhs.clone());
+    let rtts = flatten(rhs.clone());
+
+    if ltts.len() != rtts.len() {
+        panic!(
+            "expected the same number of tts ({} == {})\nlhs:\n{:#?}\nrhs:\n{:#?}",
+            ltts.len(),
+            rtts.len(),
+            lhs,
+            rhs
+        )
+    }
+
+    for (ltt, rtt) in ltts.iter().zip(&rtts) {
+        match (ltt, rtt) {
+            (TokenTree::Group(l), TokenTree::Group(r)) => {
+                assert_eq!(
+                    l.delimiter(),
+                    r.delimiter(),
+                    "expected delimiters to match for {:?} and {:?}",
+                    l,
+                    r
+                );
+                assert_ts_eq(&l.stream(), &r.stream());
+            }
+            (TokenTree::Punct(l), TokenTree::Punct(r)) => assert_eq!(
+                (l.as_char(), l.spacing()),
+                (r.as_char(), r.spacing()),
+                "expected punct to match for {:?} and {:?}",
+                l,
+                r
+            ),
+            (TokenTree::Ident(l), TokenTree::Ident(r)) => assert_eq!(
+                l.to_string(),
+                r.to_string(),
+                "expected ident to match for {:?} and {:?}",
+                l,
+                r
+            ),
+            (TokenTree::Literal(l), TokenTree::Literal(r)) => assert_eq!(
+                l.to_string(),
+                r.to_string(),
+                "expected literal to match for {:?} and {:?}",
+                l,
+                r
+            ),
+            (l, r) => panic!("expected type to match for {:?} and {:?}", l, r),
+        }
+    }
+}
+
 #[proc_macro]
 pub fn expand_expr_is(input: TokenStream) -> TokenStream {
     let mut iter = input.into_iter();
@@ -31,6 +97,9 @@ pub fn expand_expr_is(input: TokenStream) -> TokenStream {
         expanded.to_string()
     );
 
+    // Also compare the raw tts to make sure they line up.
+    assert_ts_eq(&expected, &expanded);
+
     TokenStream::new()
 }
 
@@ -48,7 +117,7 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
     // invocation expand to the same literal.
     let input_t = ts.expand_expr().expect("expand_expr failed on macro input").to_string();
     let parse_t = TokenStream::from_str("file!{}")
-    .unwrap()
+        .unwrap()
         .expand_expr()
         .expect("expand_expr failed on internal macro")
         .to_string();
diff --git a/src/test/ui/proc-macro/parent-source-spans.stderr b/src/test/ui/proc-macro/parent-source-spans.stderr
index 4548269b507..3c46b95cbc6 100644
--- a/src/test/ui/proc-macro/parent-source-spans.stderr
+++ b/src/test/ui/proc-macro/parent-source-spans.stderr
@@ -148,7 +148,7 @@ LL |     one!("hello", "world");
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
+   |     -- similarly named tuple variant `Ok` defined here
    |
    = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -164,7 +164,7 @@ LL |     two!("yay", "rust");
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
+   |     -- similarly named tuple variant `Ok` defined here
    |
    = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -180,7 +180,7 @@ LL |     three!("hip", "hop");
   ::: $SRC_DIR/core/src/result.rs:LL:COL
    |
 LL |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
-   |     --------------------------------------------------- similarly named tuple variant `Ok` defined here
+   |     -- similarly named tuple variant `Ok` defined here
    |
    = note: this error originates in the macro `parent_source_spans` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
index c857eb459b8..c9e93174e20 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs
@@ -1,18 +1,14 @@
-// Dropck shouldn't hit a recursion limit from checking `S<u32>` since it has
-// no free regions or type parameters.
-// Codegen however, has to error for the infinitely many `drop_in_place`
-// functions it has been asked to create.
-
-// build-fail
-// normalize-stderr-test: ".nll/" -> "/"
-// compile-flags: -Zmir-opt-level=0
+// `S` is infinitely recursing so it's not possible to generate a finite
+// drop impl (ignoring polymorphization).
+//
+// Dropck should therefore detect that this is the case and eagerly error.
 
 struct S<T> {
     t: T,
     s: Box<S<fn(u: T)>>,
 }
 
-fn f(x: S<u32>) {}
+fn f(x: S<u32>) {} //~ ERROR overflow while adding drop-check rules for S<u32>
 
 fn main() {
     // Force instantiation.
diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
index d749ee00c22..1da29be43db 100644
--- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
+++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr
@@ -1,15 +1,10 @@
-error: reached the recursion limit while instantiating `std::ptr::drop_in_place::<S<fn(f...)))))))))))))))))))))))))))))>))`
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+error[E0320]: overflow while adding drop-check rules for S<u32>
+  --> $DIR/issue-38591-non-regular-dropck-recursion.rs:11:6
    |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | fn f(x: S<u32>) {}
+   |      ^
    |
-note: `std::ptr::drop_in_place` defined here
-  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-   |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt'
+   = note: overflowed on S<fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(fn(u32)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))>
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs
index aa3f66b2e28..e647f0ff4fb 100644
--- a/src/test/ui/recursion/issue-83150.rs
+++ b/src/test/ui/recursion/issue-83150.rs
@@ -1,5 +1,6 @@
 // build-fail
-//~^ ERROR overflow evaluating the requirement
+// compile-flags: -Copt-level=0
+//~^^ ERROR overflow evaluating the requirement
 
 fn main() {
     let mut iter = 0u8..1;
diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr
index 4c8469be626..89a83298471 100644
--- a/src/test/ui/recursion/issue-83150.stderr
+++ b/src/test/ui/recursion/issue-83150.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-83150.rs:9:1
+  --> $DIR/issue-83150.rs:10:1
    |
 LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
@@ -9,10 +9,10 @@ LL |     func(&mut iter.map(|x| x + 1))
    = note: `#[warn(unconditional_recursion)]` on by default
    = help: a `loop` may express intention better if this is on purpose
 
-error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator`
+error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
-   = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>`
+   = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>, [closure@$DIR/issue-83150.rs:11:24: 11:27]>`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/recursion/issue-86784.rs b/src/test/ui/recursion/issue-86784.rs
new file mode 100644
index 00000000000..34f4aaedb32
--- /dev/null
+++ b/src/test/ui/recursion/issue-86784.rs
@@ -0,0 +1,2597 @@
+// build-pass
+
+fn main() {
+    let _temp_1 = 0;
+    let _temp_2 = 0;
+    let _temp_3 = 0;
+    let _temp_4 = 0;
+    let _temp_5 = 0;
+    let _temp_6 = 0;
+    let _temp_7 = 0;
+    let _temp_8 = 0;
+    let _temp_9 = 0;
+    let _temp_10 = 0;
+    let _temp_11 = 0;
+    let _temp_12 = 0;
+    let _temp_13 = 0;
+    let _temp_14 = 0;
+    let _temp_15 = 0;
+    let _temp_16 = 0;
+    let _temp_17 = 0;
+    let _temp_18 = 0;
+    let _temp_19 = 0;
+    let _temp_20 = 0;
+    let _temp_21 = 0;
+    let _temp_22 = 0;
+    let _temp_23 = 0;
+    let _temp_24 = 0;
+    let _temp_25 = 0;
+    let _temp_26 = 0;
+    let _temp_27 = 0;
+    let _temp_28 = 0;
+    let _temp_29 = 0;
+    let _temp_30 = 0;
+    let _temp_31 = 0;
+    let _temp_32 = 0;
+    let _temp_33 = 0;
+    let _temp_34 = 0;
+    let _temp_35 = 0;
+    let _temp_36 = 0;
+    let _temp_37 = 0;
+    let _temp_38 = 0;
+    let _temp_39 = 0;
+    let _temp_40 = 0;
+    let _temp_41 = 0;
+    let _temp_42 = 0;
+    let _temp_43 = 0;
+    let _temp_44 = 0;
+    let _temp_45 = 0;
+    let _temp_46 = 0;
+    let _temp_47 = 0;
+    let _temp_48 = 0;
+    let _temp_49 = 0;
+    let _temp_50 = 0;
+    let _temp_51 = 0;
+    let _temp_52 = 0;
+    let _temp_53 = 0;
+    let _temp_54 = 0;
+    let _temp_55 = 0;
+    let _temp_56 = 0;
+    let _temp_57 = 0;
+    let _temp_58 = 0;
+    let _temp_59 = 0;
+    let _temp_60 = 0;
+    let _temp_61 = 0;
+    let _temp_62 = 0;
+    let _temp_63 = 0;
+    let _temp_64 = 0;
+    let _temp_65 = 0;
+    let _temp_66 = 0;
+    let _temp_67 = 0;
+    let _temp_68 = 0;
+    let _temp_69 = 0;
+    let _temp_70 = 0;
+    let _temp_71 = 0;
+    let _temp_72 = 0;
+    let _temp_73 = 0;
+    let _temp_74 = 0;
+    let _temp_75 = 0;
+    let _temp_76 = 0;
+    let _temp_77 = 0;
+    let _temp_78 = 0;
+    let _temp_79 = 0;
+    let _temp_80 = 0;
+    let _temp_81 = 0;
+    let _temp_82 = 0;
+    let _temp_83 = 0;
+    let _temp_84 = 0;
+    let _temp_85 = 0;
+    let _temp_86 = 0;
+    let _temp_87 = 0;
+    let _temp_88 = 0;
+    let _temp_89 = 0;
+    let _temp_90 = 0;
+    let _temp_91 = 0;
+    let _temp_92 = 0;
+    let _temp_93 = 0;
+    let _temp_94 = 0;
+    let _temp_95 = 0;
+    let _temp_96 = 0;
+    let _temp_97 = 0;
+    let _temp_98 = 0;
+    let _temp_99 = 0;
+    let _temp_100 = 0;
+    let _temp_101 = 0;
+    let _temp_102 = 0;
+    let _temp_103 = 0;
+    let _temp_104 = 0;
+    let _temp_105 = 0;
+    let _temp_106 = 0;
+    let _temp_107 = 0;
+    let _temp_108 = 0;
+    let _temp_109 = 0;
+    let _temp_110 = 0;
+    let _temp_111 = 0;
+    let _temp_112 = 0;
+    let _temp_113 = 0;
+    let _temp_114 = 0;
+    let _temp_115 = 0;
+    let _temp_116 = 0;
+    let _temp_117 = 0;
+    let _temp_118 = 0;
+    let _temp_119 = 0;
+    let _temp_120 = 0;
+    let _temp_121 = 0;
+    let _temp_122 = 0;
+    let _temp_123 = 0;
+    let _temp_124 = 0;
+    let _temp_125 = 0;
+    let _temp_126 = 0;
+    let _temp_127 = 0;
+    let _temp_128 = 0;
+    let _temp_129 = 0;
+    let _temp_130 = 0;
+    let _temp_131 = 0;
+    let _temp_132 = 0;
+    let _temp_133 = 0;
+    let _temp_134 = 0;
+    let _temp_135 = 0;
+    let _temp_136 = 0;
+    let _temp_137 = 0;
+    let _temp_138 = 0;
+    let _temp_139 = 0;
+    let _temp_140 = 0;
+    let _temp_141 = 0;
+    let _temp_142 = 0;
+    let _temp_143 = 0;
+    let _temp_144 = 0;
+    let _temp_145 = 0;
+    let _temp_146 = 0;
+    let _temp_147 = 0;
+    let _temp_148 = 0;
+    let _temp_149 = 0;
+    let _temp_150 = 0;
+    let _temp_151 = 0;
+    let _temp_152 = 0;
+    let _temp_153 = 0;
+    let _temp_154 = 0;
+    let _temp_155 = 0;
+    let _temp_156 = 0;
+    let _temp_157 = 0;
+    let _temp_158 = 0;
+    let _temp_159 = 0;
+    let _temp_160 = 0;
+    let _temp_161 = 0;
+    let _temp_162 = 0;
+    let _temp_163 = 0;
+    let _temp_164 = 0;
+    let _temp_165 = 0;
+    let _temp_166 = 0;
+    let _temp_167 = 0;
+    let _temp_168 = 0;
+    let _temp_169 = 0;
+    let _temp_170 = 0;
+    let _temp_171 = 0;
+    let _temp_172 = 0;
+    let _temp_173 = 0;
+    let _temp_174 = 0;
+    let _temp_175 = 0;
+    let _temp_176 = 0;
+    let _temp_177 = 0;
+    let _temp_178 = 0;
+    let _temp_179 = 0;
+    let _temp_180 = 0;
+    let _temp_181 = 0;
+    let _temp_182 = 0;
+    let _temp_183 = 0;
+    let _temp_184 = 0;
+    let _temp_185 = 0;
+    let _temp_186 = 0;
+    let _temp_187 = 0;
+    let _temp_188 = 0;
+    let _temp_189 = 0;
+    let _temp_190 = 0;
+    let _temp_191 = 0;
+    let _temp_192 = 0;
+    let _temp_193 = 0;
+    let _temp_194 = 0;
+    let _temp_195 = 0;
+    let _temp_196 = 0;
+    let _temp_197 = 0;
+    let _temp_198 = 0;
+    let _temp_199 = 0;
+    let _temp_200 = 0;
+    let _temp_201 = 0;
+    let _temp_202 = 0;
+    let _temp_203 = 0;
+    let _temp_204 = 0;
+    let _temp_205 = 0;
+    let _temp_206 = 0;
+    let _temp_207 = 0;
+    let _temp_208 = 0;
+    let _temp_209 = 0;
+    let _temp_210 = 0;
+    let _temp_211 = 0;
+    let _temp_212 = 0;
+    let _temp_213 = 0;
+    let _temp_214 = 0;
+    let _temp_215 = 0;
+    let _temp_216 = 0;
+    let _temp_217 = 0;
+    let _temp_218 = 0;
+    let _temp_219 = 0;
+    let _temp_220 = 0;
+    let _temp_221 = 0;
+    let _temp_222 = 0;
+    let _temp_223 = 0;
+    let _temp_224 = 0;
+    let _temp_225 = 0;
+    let _temp_226 = 0;
+    let _temp_227 = 0;
+    let _temp_228 = 0;
+    let _temp_229 = 0;
+    let _temp_230 = 0;
+    let _temp_231 = 0;
+    let _temp_232 = 0;
+    let _temp_233 = 0;
+    let _temp_234 = 0;
+    let _temp_235 = 0;
+    let _temp_236 = 0;
+    let _temp_237 = 0;
+    let _temp_238 = 0;
+    let _temp_239 = 0;
+    let _temp_240 = 0;
+    let _temp_241 = 0;
+    let _temp_242 = 0;
+    let _temp_243 = 0;
+    let _temp_244 = 0;
+    let _temp_245 = 0;
+    let _temp_246 = 0;
+    let _temp_247 = 0;
+    let _temp_248 = 0;
+    let _temp_249 = 0;
+    let _temp_250 = 0;
+    let _temp_251 = 0;
+    let _temp_252 = 0;
+    let _temp_253 = 0;
+    let _temp_254 = 0;
+    let _temp_255 = 0;
+    let _temp_256 = 0;
+    let _temp_257 = 0;
+    let _temp_258 = 0;
+    let _temp_259 = 0;
+    let _temp_260 = 0;
+    let _temp_261 = 0;
+    let _temp_262 = 0;
+    let _temp_263 = 0;
+    let _temp_264 = 0;
+    let _temp_265 = 0;
+    let _temp_266 = 0;
+    let _temp_267 = 0;
+    let _temp_268 = 0;
+    let _temp_269 = 0;
+    let _temp_270 = 0;
+    let _temp_271 = 0;
+    let _temp_272 = 0;
+    let _temp_273 = 0;
+    let _temp_274 = 0;
+    let _temp_275 = 0;
+    let _temp_276 = 0;
+    let _temp_277 = 0;
+    let _temp_278 = 0;
+    let _temp_279 = 0;
+    let _temp_280 = 0;
+    let _temp_281 = 0;
+    let _temp_282 = 0;
+    let _temp_283 = 0;
+    let _temp_284 = 0;
+    let _temp_285 = 0;
+    let _temp_286 = 0;
+    let _temp_287 = 0;
+    let _temp_288 = 0;
+    let _temp_289 = 0;
+    let _temp_290 = 0;
+    let _temp_291 = 0;
+    let _temp_292 = 0;
+    let _temp_293 = 0;
+    let _temp_294 = 0;
+    let _temp_295 = 0;
+    let _temp_296 = 0;
+    let _temp_297 = 0;
+    let _temp_298 = 0;
+    let _temp_299 = 0;
+    let _temp_300 = 0;
+    let _temp_301 = 0;
+    let _temp_302 = 0;
+    let _temp_303 = 0;
+    let _temp_304 = 0;
+    let _temp_305 = 0;
+    let _temp_306 = 0;
+    let _temp_307 = 0;
+    let _temp_308 = 0;
+    let _temp_309 = 0;
+    let _temp_310 = 0;
+    let _temp_311 = 0;
+    let _temp_312 = 0;
+    let _temp_313 = 0;
+    let _temp_314 = 0;
+    let _temp_315 = 0;
+    let _temp_316 = 0;
+    let _temp_317 = 0;
+    let _temp_318 = 0;
+    let _temp_319 = 0;
+    let _temp_320 = 0;
+    let _temp_321 = 0;
+    let _temp_322 = 0;
+    let _temp_323 = 0;
+    let _temp_324 = 0;
+    let _temp_325 = 0;
+    let _temp_326 = 0;
+    let _temp_327 = 0;
+    let _temp_328 = 0;
+    let _temp_329 = 0;
+    let _temp_330 = 0;
+    let _temp_331 = 0;
+    let _temp_332 = 0;
+    let _temp_333 = 0;
+    let _temp_334 = 0;
+    let _temp_335 = 0;
+    let _temp_336 = 0;
+    let _temp_337 = 0;
+    let _temp_338 = 0;
+    let _temp_339 = 0;
+    let _temp_340 = 0;
+    let _temp_341 = 0;
+    let _temp_342 = 0;
+    let _temp_343 = 0;
+    let _temp_344 = 0;
+    let _temp_345 = 0;
+    let _temp_346 = 0;
+    let _temp_347 = 0;
+    let _temp_348 = 0;
+    let _temp_349 = 0;
+    let _temp_350 = 0;
+    let _temp_351 = 0;
+    let _temp_352 = 0;
+    let _temp_353 = 0;
+    let _temp_354 = 0;
+    let _temp_355 = 0;
+    let _temp_356 = 0;
+    let _temp_357 = 0;
+    let _temp_358 = 0;
+    let _temp_359 = 0;
+    let _temp_360 = 0;
+    let _temp_361 = 0;
+    let _temp_362 = 0;
+    let _temp_363 = 0;
+    let _temp_364 = 0;
+    let _temp_365 = 0;
+    let _temp_366 = 0;
+    let _temp_367 = 0;
+    let _temp_368 = 0;
+    let _temp_369 = 0;
+    let _temp_370 = 0;
+    let _temp_371 = 0;
+    let _temp_372 = 0;
+    let _temp_373 = 0;
+    let _temp_374 = 0;
+    let _temp_375 = 0;
+    let _temp_376 = 0;
+    let _temp_377 = 0;
+    let _temp_378 = 0;
+    let _temp_379 = 0;
+    let _temp_380 = 0;
+    let _temp_381 = 0;
+    let _temp_382 = 0;
+    let _temp_383 = 0;
+    let _temp_384 = 0;
+    let _temp_385 = 0;
+    let _temp_386 = 0;
+    let _temp_387 = 0;
+    let _temp_388 = 0;
+    let _temp_389 = 0;
+    let _temp_390 = 0;
+    let _temp_391 = 0;
+    let _temp_392 = 0;
+    let _temp_393 = 0;
+    let _temp_394 = 0;
+    let _temp_395 = 0;
+    let _temp_396 = 0;
+    let _temp_397 = 0;
+    let _temp_398 = 0;
+    let _temp_399 = 0;
+    let _temp_400 = 0;
+    let _temp_401 = 0;
+    let _temp_402 = 0;
+    let _temp_403 = 0;
+    let _temp_404 = 0;
+    let _temp_405 = 0;
+    let _temp_406 = 0;
+    let _temp_407 = 0;
+    let _temp_408 = 0;
+    let _temp_409 = 0;
+    let _temp_410 = 0;
+    let _temp_411 = 0;
+    let _temp_412 = 0;
+    let _temp_413 = 0;
+    let _temp_414 = 0;
+    let _temp_415 = 0;
+    let _temp_416 = 0;
+    let _temp_417 = 0;
+    let _temp_418 = 0;
+    let _temp_419 = 0;
+    let _temp_420 = 0;
+    let _temp_421 = 0;
+    let _temp_422 = 0;
+    let _temp_423 = 0;
+    let _temp_424 = 0;
+    let _temp_425 = 0;
+    let _temp_426 = 0;
+    let _temp_427 = 0;
+    let _temp_428 = 0;
+    let _temp_429 = 0;
+    let _temp_430 = 0;
+    let _temp_431 = 0;
+    let _temp_432 = 0;
+    let _temp_433 = 0;
+    let _temp_434 = 0;
+    let _temp_435 = 0;
+    let _temp_436 = 0;
+    let _temp_437 = 0;
+    let _temp_438 = 0;
+    let _temp_439 = 0;
+    let _temp_440 = 0;
+    let _temp_441 = 0;
+    let _temp_442 = 0;
+    let _temp_443 = 0;
+    let _temp_444 = 0;
+    let _temp_445 = 0;
+    let _temp_446 = 0;
+    let _temp_447 = 0;
+    let _temp_448 = 0;
+    let _temp_449 = 0;
+    let _temp_450 = 0;
+    let _temp_451 = 0;
+    let _temp_452 = 0;
+    let _temp_453 = 0;
+    let _temp_454 = 0;
+    let _temp_455 = 0;
+    let _temp_456 = 0;
+    let _temp_457 = 0;
+    let _temp_458 = 0;
+    let _temp_459 = 0;
+    let _temp_460 = 0;
+    let _temp_461 = 0;
+    let _temp_462 = 0;
+    let _temp_463 = 0;
+    let _temp_464 = 0;
+    let _temp_465 = 0;
+    let _temp_466 = 0;
+    let _temp_467 = 0;
+    let _temp_468 = 0;
+    let _temp_469 = 0;
+    let _temp_470 = 0;
+    let _temp_471 = 0;
+    let _temp_472 = 0;
+    let _temp_473 = 0;
+    let _temp_474 = 0;
+    let _temp_475 = 0;
+    let _temp_476 = 0;
+    let _temp_477 = 0;
+    let _temp_478 = 0;
+    let _temp_479 = 0;
+    let _temp_480 = 0;
+    let _temp_481 = 0;
+    let _temp_482 = 0;
+    let _temp_483 = 0;
+    let _temp_484 = 0;
+    let _temp_485 = 0;
+    let _temp_486 = 0;
+    let _temp_487 = 0;
+    let _temp_488 = 0;
+    let _temp_489 = 0;
+    let _temp_490 = 0;
+    let _temp_491 = 0;
+    let _temp_492 = 0;
+    let _temp_493 = 0;
+    let _temp_494 = 0;
+    let _temp_495 = 0;
+    let _temp_496 = 0;
+    let _temp_497 = 0;
+    let _temp_498 = 0;
+    let _temp_499 = 0;
+    let _temp_500 = 0;
+    let _temp_501 = 0;
+    let _temp_502 = 0;
+    let _temp_503 = 0;
+    let _temp_504 = 0;
+    let _temp_505 = 0;
+    let _temp_506 = 0;
+    let _temp_507 = 0;
+    let _temp_508 = 0;
+    let _temp_509 = 0;
+    let _temp_510 = 0;
+    let _temp_511 = 0;
+    let _temp_512 = 0;
+    let _temp_513 = 0;
+    let _temp_514 = 0;
+    let _temp_515 = 0;
+    let _temp_516 = 0;
+    let _temp_517 = 0;
+    let _temp_518 = 0;
+    let _temp_519 = 0;
+    let _temp_520 = 0;
+    let _temp_521 = 0;
+    let _temp_522 = 0;
+    let _temp_523 = 0;
+    let _temp_524 = 0;
+    let _temp_525 = 0;
+    let _temp_526 = 0;
+    let _temp_527 = 0;
+    let _temp_528 = 0;
+    let _temp_529 = 0;
+    let _temp_530 = 0;
+    let _temp_531 = 0;
+    let _temp_532 = 0;
+    let _temp_533 = 0;
+    let _temp_534 = 0;
+    let _temp_535 = 0;
+    let _temp_536 = 0;
+    let _temp_537 = 0;
+    let _temp_538 = 0;
+    let _temp_539 = 0;
+    let _temp_540 = 0;
+    let _temp_541 = 0;
+    let _temp_542 = 0;
+    let _temp_543 = 0;
+    let _temp_544 = 0;
+    let _temp_545 = 0;
+    let _temp_546 = 0;
+    let _temp_547 = 0;
+    let _temp_548 = 0;
+    let _temp_549 = 0;
+    let _temp_550 = 0;
+    let _temp_551 = 0;
+    let _temp_552 = 0;
+    let _temp_553 = 0;
+    let _temp_554 = 0;
+    let _temp_555 = 0;
+    let _temp_556 = 0;
+    let _temp_557 = 0;
+    let _temp_558 = 0;
+    let _temp_559 = 0;
+    let _temp_560 = 0;
+    let _temp_561 = 0;
+    let _temp_562 = 0;
+    let _temp_563 = 0;
+    let _temp_564 = 0;
+    let _temp_565 = 0;
+    let _temp_566 = 0;
+    let _temp_567 = 0;
+    let _temp_568 = 0;
+    let _temp_569 = 0;
+    let _temp_570 = 0;
+    let _temp_571 = 0;
+    let _temp_572 = 0;
+    let _temp_573 = 0;
+    let _temp_574 = 0;
+    let _temp_575 = 0;
+    let _temp_576 = 0;
+    let _temp_577 = 0;
+    let _temp_578 = 0;
+    let _temp_579 = 0;
+    let _temp_580 = 0;
+    let _temp_581 = 0;
+    let _temp_582 = 0;
+    let _temp_583 = 0;
+    let _temp_584 = 0;
+    let _temp_585 = 0;
+    let _temp_586 = 0;
+    let _temp_587 = 0;
+    let _temp_588 = 0;
+    let _temp_589 = 0;
+    let _temp_590 = 0;
+    let _temp_591 = 0;
+    let _temp_592 = 0;
+    let _temp_593 = 0;
+    let _temp_594 = 0;
+    let _temp_595 = 0;
+    let _temp_596 = 0;
+    let _temp_597 = 0;
+    let _temp_598 = 0;
+    let _temp_599 = 0;
+    let _temp_600 = 0;
+    let _temp_601 = 0;
+    let _temp_602 = 0;
+    let _temp_603 = 0;
+    let _temp_604 = 0;
+    let _temp_605 = 0;
+    let _temp_606 = 0;
+    let _temp_607 = 0;
+    let _temp_608 = 0;
+    let _temp_609 = 0;
+    let _temp_610 = 0;
+    let _temp_611 = 0;
+    let _temp_612 = 0;
+    let _temp_613 = 0;
+    let _temp_614 = 0;
+    let _temp_615 = 0;
+    let _temp_616 = 0;
+    let _temp_617 = 0;
+    let _temp_618 = 0;
+    let _temp_619 = 0;
+    let _temp_620 = 0;
+    let _temp_621 = 0;
+    let _temp_622 = 0;
+    let _temp_623 = 0;
+    let _temp_624 = 0;
+    let _temp_625 = 0;
+    let _temp_626 = 0;
+    let _temp_627 = 0;
+    let _temp_628 = 0;
+    let _temp_629 = 0;
+    let _temp_630 = 0;
+    let _temp_631 = 0;
+    let _temp_632 = 0;
+    let _temp_633 = 0;
+    let _temp_634 = 0;
+    let _temp_635 = 0;
+    let _temp_636 = 0;
+    let _temp_637 = 0;
+    let _temp_638 = 0;
+    let _temp_639 = 0;
+    let _temp_640 = 0;
+    let _temp_641 = 0;
+    let _temp_642 = 0;
+    let _temp_643 = 0;
+    let _temp_644 = 0;
+    let _temp_645 = 0;
+    let _temp_646 = 0;
+    let _temp_647 = 0;
+    let _temp_648 = 0;
+    let _temp_649 = 0;
+    let _temp_650 = 0;
+    let _temp_651 = 0;
+    let _temp_652 = 0;
+    let _temp_653 = 0;
+    let _temp_654 = 0;
+    let _temp_655 = 0;
+    let _temp_656 = 0;
+    let _temp_657 = 0;
+    let _temp_658 = 0;
+    let _temp_659 = 0;
+    let _temp_660 = 0;
+    let _temp_661 = 0;
+    let _temp_662 = 0;
+    let _temp_663 = 0;
+    let _temp_664 = 0;
+    let _temp_665 = 0;
+    let _temp_666 = 0;
+    let _temp_667 = 0;
+    let _temp_668 = 0;
+    let _temp_669 = 0;
+    let _temp_670 = 0;
+    let _temp_671 = 0;
+    let _temp_672 = 0;
+    let _temp_673 = 0;
+    let _temp_674 = 0;
+    let _temp_675 = 0;
+    let _temp_676 = 0;
+    let _temp_677 = 0;
+    let _temp_678 = 0;
+    let _temp_679 = 0;
+    let _temp_680 = 0;
+    let _temp_681 = 0;
+    let _temp_682 = 0;
+    let _temp_683 = 0;
+    let _temp_684 = 0;
+    let _temp_685 = 0;
+    let _temp_686 = 0;
+    let _temp_687 = 0;
+    let _temp_688 = 0;
+    let _temp_689 = 0;
+    let _temp_690 = 0;
+    let _temp_691 = 0;
+    let _temp_692 = 0;
+    let _temp_693 = 0;
+    let _temp_694 = 0;
+    let _temp_695 = 0;
+    let _temp_696 = 0;
+    let _temp_697 = 0;
+    let _temp_698 = 0;
+    let _temp_699 = 0;
+    let _temp_700 = 0;
+    let _temp_701 = 0;
+    let _temp_702 = 0;
+    let _temp_703 = 0;
+    let _temp_704 = 0;
+    let _temp_705 = 0;
+    let _temp_706 = 0;
+    let _temp_707 = 0;
+    let _temp_708 = 0;
+    let _temp_709 = 0;
+    let _temp_710 = 0;
+    let _temp_711 = 0;
+    let _temp_712 = 0;
+    let _temp_713 = 0;
+    let _temp_714 = 0;
+    let _temp_715 = 0;
+    let _temp_716 = 0;
+    let _temp_717 = 0;
+    let _temp_718 = 0;
+    let _temp_719 = 0;
+    let _temp_720 = 0;
+    let _temp_721 = 0;
+    let _temp_722 = 0;
+    let _temp_723 = 0;
+    let _temp_724 = 0;
+    let _temp_725 = 0;
+    let _temp_726 = 0;
+    let _temp_727 = 0;
+    let _temp_728 = 0;
+    let _temp_729 = 0;
+    let _temp_730 = 0;
+    let _temp_731 = 0;
+    let _temp_732 = 0;
+    let _temp_733 = 0;
+    let _temp_734 = 0;
+    let _temp_735 = 0;
+    let _temp_736 = 0;
+    let _temp_737 = 0;
+    let _temp_738 = 0;
+    let _temp_739 = 0;
+    let _temp_740 = 0;
+    let _temp_741 = 0;
+    let _temp_742 = 0;
+    let _temp_743 = 0;
+    let _temp_744 = 0;
+    let _temp_745 = 0;
+    let _temp_746 = 0;
+    let _temp_747 = 0;
+    let _temp_748 = 0;
+    let _temp_749 = 0;
+    let _temp_750 = 0;
+    let _temp_751 = 0;
+    let _temp_752 = 0;
+    let _temp_753 = 0;
+    let _temp_754 = 0;
+    let _temp_755 = 0;
+    let _temp_756 = 0;
+    let _temp_757 = 0;
+    let _temp_758 = 0;
+    let _temp_759 = 0;
+    let _temp_760 = 0;
+    let _temp_761 = 0;
+    let _temp_762 = 0;
+    let _temp_763 = 0;
+    let _temp_764 = 0;
+    let _temp_765 = 0;
+    let _temp_766 = 0;
+    let _temp_767 = 0;
+    let _temp_768 = 0;
+    let _temp_769 = 0;
+    let _temp_770 = 0;
+    let _temp_771 = 0;
+    let _temp_772 = 0;
+    let _temp_773 = 0;
+    let _temp_774 = 0;
+    let _temp_775 = 0;
+    let _temp_776 = 0;
+    let _temp_777 = 0;
+    let _temp_778 = 0;
+    let _temp_779 = 0;
+    let _temp_780 = 0;
+    let _temp_781 = 0;
+    let _temp_782 = 0;
+    let _temp_783 = 0;
+    let _temp_784 = 0;
+    let _temp_785 = 0;
+    let _temp_786 = 0;
+    let _temp_787 = 0;
+    let _temp_788 = 0;
+    let _temp_789 = 0;
+    let _temp_790 = 0;
+    let _temp_791 = 0;
+    let _temp_792 = 0;
+    let _temp_793 = 0;
+    let _temp_794 = 0;
+    let _temp_795 = 0;
+    let _temp_796 = 0;
+    let _temp_797 = 0;
+    let _temp_798 = 0;
+    let _temp_799 = 0;
+    let _temp_800 = 0;
+    let _temp_801 = 0;
+    let _temp_802 = 0;
+    let _temp_803 = 0;
+    let _temp_804 = 0;
+    let _temp_805 = 0;
+    let _temp_806 = 0;
+    let _temp_807 = 0;
+    let _temp_808 = 0;
+    let _temp_809 = 0;
+    let _temp_810 = 0;
+    let _temp_811 = 0;
+    let _temp_812 = 0;
+    let _temp_813 = 0;
+    let _temp_814 = 0;
+    let _temp_815 = 0;
+    let _temp_816 = 0;
+    let _temp_817 = 0;
+    let _temp_818 = 0;
+    let _temp_819 = 0;
+    let _temp_820 = 0;
+    let _temp_821 = 0;
+    let _temp_822 = 0;
+    let _temp_823 = 0;
+    let _temp_824 = 0;
+    let _temp_825 = 0;
+    let _temp_826 = 0;
+    let _temp_827 = 0;
+    let _temp_828 = 0;
+    let _temp_829 = 0;
+    let _temp_830 = 0;
+    let _temp_831 = 0;
+    let _temp_832 = 0;
+    let _temp_833 = 0;
+    let _temp_834 = 0;
+    let _temp_835 = 0;
+    let _temp_836 = 0;
+    let _temp_837 = 0;
+    let _temp_838 = 0;
+    let _temp_839 = 0;
+    let _temp_840 = 0;
+    let _temp_841 = 0;
+    let _temp_842 = 0;
+    let _temp_843 = 0;
+    let _temp_844 = 0;
+    let _temp_845 = 0;
+    let _temp_846 = 0;
+    let _temp_847 = 0;
+    let _temp_848 = 0;
+    let _temp_849 = 0;
+    let _temp_850 = 0;
+    let _temp_851 = 0;
+    let _temp_852 = 0;
+    let _temp_853 = 0;
+    let _temp_854 = 0;
+    let _temp_855 = 0;
+    let _temp_856 = 0;
+    let _temp_857 = 0;
+    let _temp_858 = 0;
+    let _temp_859 = 0;
+    let _temp_860 = 0;
+    let _temp_861 = 0;
+    let _temp_862 = 0;
+    let _temp_863 = 0;
+    let _temp_864 = 0;
+    let _temp_865 = 0;
+    let _temp_866 = 0;
+    let _temp_867 = 0;
+    let _temp_868 = 0;
+    let _temp_869 = 0;
+    let _temp_870 = 0;
+    let _temp_871 = 0;
+    let _temp_872 = 0;
+    let _temp_873 = 0;
+    let _temp_874 = 0;
+    let _temp_875 = 0;
+    let _temp_876 = 0;
+    let _temp_877 = 0;
+    let _temp_878 = 0;
+    let _temp_879 = 0;
+    let _temp_880 = 0;
+    let _temp_881 = 0;
+    let _temp_882 = 0;
+    let _temp_883 = 0;
+    let _temp_884 = 0;
+    let _temp_885 = 0;
+    let _temp_886 = 0;
+    let _temp_887 = 0;
+    let _temp_888 = 0;
+    let _temp_889 = 0;
+    let _temp_890 = 0;
+    let _temp_891 = 0;
+    let _temp_892 = 0;
+    let _temp_893 = 0;
+    let _temp_894 = 0;
+    let _temp_895 = 0;
+    let _temp_896 = 0;
+    let _temp_897 = 0;
+    let _temp_898 = 0;
+    let _temp_899 = 0;
+    let _temp_900 = 0;
+    let _temp_901 = 0;
+    let _temp_902 = 0;
+    let _temp_903 = 0;
+    let _temp_904 = 0;
+    let _temp_905 = 0;
+    let _temp_906 = 0;
+    let _temp_907 = 0;
+    let _temp_908 = 0;
+    let _temp_909 = 0;
+    let _temp_910 = 0;
+    let _temp_911 = 0;
+    let _temp_912 = 0;
+    let _temp_913 = 0;
+    let _temp_914 = 0;
+    let _temp_915 = 0;
+    let _temp_916 = 0;
+    let _temp_917 = 0;
+    let _temp_918 = 0;
+    let _temp_919 = 0;
+    let _temp_920 = 0;
+    let _temp_921 = 0;
+    let _temp_922 = 0;
+    let _temp_923 = 0;
+    let _temp_924 = 0;
+    let _temp_925 = 0;
+    let _temp_926 = 0;
+    let _temp_927 = 0;
+    let _temp_928 = 0;
+    let _temp_929 = 0;
+    let _temp_930 = 0;
+    let _temp_931 = 0;
+    let _temp_932 = 0;
+    let _temp_933 = 0;
+    let _temp_934 = 0;
+    let _temp_935 = 0;
+    let _temp_936 = 0;
+    let _temp_937 = 0;
+    let _temp_938 = 0;
+    let _temp_939 = 0;
+    let _temp_940 = 0;
+    let _temp_941 = 0;
+    let _temp_942 = 0;
+    let _temp_943 = 0;
+    let _temp_944 = 0;
+    let _temp_945 = 0;
+    let _temp_946 = 0;
+    let _temp_947 = 0;
+    let _temp_948 = 0;
+    let _temp_949 = 0;
+    let _temp_950 = 0;
+    let _temp_951 = 0;
+    let _temp_952 = 0;
+    let _temp_953 = 0;
+    let _temp_954 = 0;
+    let _temp_955 = 0;
+    let _temp_956 = 0;
+    let _temp_957 = 0;
+    let _temp_958 = 0;
+    let _temp_959 = 0;
+    let _temp_960 = 0;
+    let _temp_961 = 0;
+    let _temp_962 = 0;
+    let _temp_963 = 0;
+    let _temp_964 = 0;
+    let _temp_965 = 0;
+    let _temp_966 = 0;
+    let _temp_967 = 0;
+    let _temp_968 = 0;
+    let _temp_969 = 0;
+    let _temp_970 = 0;
+    let _temp_971 = 0;
+    let _temp_972 = 0;
+    let _temp_973 = 0;
+    let _temp_974 = 0;
+    let _temp_975 = 0;
+    let _temp_976 = 0;
+    let _temp_977 = 0;
+    let _temp_978 = 0;
+    let _temp_979 = 0;
+    let _temp_980 = 0;
+    let _temp_981 = 0;
+    let _temp_982 = 0;
+    let _temp_983 = 0;
+    let _temp_984 = 0;
+    let _temp_985 = 0;
+    let _temp_986 = 0;
+    let _temp_987 = 0;
+    let _temp_988 = 0;
+    let _temp_989 = 0;
+    let _temp_990 = 0;
+    let _temp_991 = 0;
+    let _temp_992 = 0;
+    let _temp_993 = 0;
+    let _temp_994 = 0;
+    let _temp_995 = 0;
+    let _temp_996 = 0;
+    let _temp_997 = 0;
+    let _temp_998 = 0;
+    let _temp_999 = 0;
+    let _temp_1000 = 0;
+    let _temp_1001 = 0;
+    let _temp_1002 = 0;
+    let _temp_1003 = 0;
+    let _temp_1004 = 0;
+    let _temp_1005 = 0;
+    let _temp_1006 = 0;
+    let _temp_1007 = 0;
+    let _temp_1008 = 0;
+    let _temp_1009 = 0;
+    let _temp_1010 = 0;
+    let _temp_1011 = 0;
+    let _temp_1012 = 0;
+    let _temp_1013 = 0;
+    let _temp_1014 = 0;
+    let _temp_1015 = 0;
+    let _temp_1016 = 0;
+    let _temp_1017 = 0;
+    let _temp_1018 = 0;
+    let _temp_1019 = 0;
+    let _temp_1020 = 0;
+    let _temp_1021 = 0;
+    let _temp_1022 = 0;
+    let _temp_1023 = 0;
+    let _temp_1024 = 0;
+    let _temp_1025 = 0;
+    let _temp_1026 = 0;
+    let _temp_1027 = 0;
+    let _temp_1028 = 0;
+    let _temp_1029 = 0;
+    let _temp_1030 = 0;
+    let _temp_1031 = 0;
+    let _temp_1032 = 0;
+    let _temp_1033 = 0;
+    let _temp_1034 = 0;
+    let _temp_1035 = 0;
+    let _temp_1036 = 0;
+    let _temp_1037 = 0;
+    let _temp_1038 = 0;
+    let _temp_1039 = 0;
+    let _temp_1040 = 0;
+    let _temp_1041 = 0;
+    let _temp_1042 = 0;
+    let _temp_1043 = 0;
+    let _temp_1044 = 0;
+    let _temp_1045 = 0;
+    let _temp_1046 = 0;
+    let _temp_1047 = 0;
+    let _temp_1048 = 0;
+    let _temp_1049 = 0;
+    let _temp_1050 = 0;
+    let _temp_1051 = 0;
+    let _temp_1052 = 0;
+    let _temp_1053 = 0;
+    let _temp_1054 = 0;
+    let _temp_1055 = 0;
+    let _temp_1056 = 0;
+    let _temp_1057 = 0;
+    let _temp_1058 = 0;
+    let _temp_1059 = 0;
+    let _temp_1060 = 0;
+    let _temp_1061 = 0;
+    let _temp_1062 = 0;
+    let _temp_1063 = 0;
+    let _temp_1064 = 0;
+    let _temp_1065 = 0;
+    let _temp_1066 = 0;
+    let _temp_1067 = 0;
+    let _temp_1068 = 0;
+    let _temp_1069 = 0;
+    let _temp_1070 = 0;
+    let _temp_1071 = 0;
+    let _temp_1072 = 0;
+    let _temp_1073 = 0;
+    let _temp_1074 = 0;
+    let _temp_1075 = 0;
+    let _temp_1076 = 0;
+    let _temp_1077 = 0;
+    let _temp_1078 = 0;
+    let _temp_1079 = 0;
+    let _temp_1080 = 0;
+    let _temp_1081 = 0;
+    let _temp_1082 = 0;
+    let _temp_1083 = 0;
+    let _temp_1084 = 0;
+    let _temp_1085 = 0;
+    let _temp_1086 = 0;
+    let _temp_1087 = 0;
+    let _temp_1088 = 0;
+    let _temp_1089 = 0;
+    let _temp_1090 = 0;
+    let _temp_1091 = 0;
+    let _temp_1092 = 0;
+    let _temp_1093 = 0;
+    let _temp_1094 = 0;
+    let _temp_1095 = 0;
+    let _temp_1096 = 0;
+    let _temp_1097 = 0;
+    let _temp_1098 = 0;
+    let _temp_1099 = 0;
+    let _temp_1100 = 0;
+    let _temp_1101 = 0;
+    let _temp_1102 = 0;
+    let _temp_1103 = 0;
+    let _temp_1104 = 0;
+    let _temp_1105 = 0;
+    let _temp_1106 = 0;
+    let _temp_1107 = 0;
+    let _temp_1108 = 0;
+    let _temp_1109 = 0;
+    let _temp_1110 = 0;
+    let _temp_1111 = 0;
+    let _temp_1112 = 0;
+    let _temp_1113 = 0;
+    let _temp_1114 = 0;
+    let _temp_1115 = 0;
+    let _temp_1116 = 0;
+    let _temp_1117 = 0;
+    let _temp_1118 = 0;
+    let _temp_1119 = 0;
+    let _temp_1120 = 0;
+    let _temp_1121 = 0;
+    let _temp_1122 = 0;
+    let _temp_1123 = 0;
+    let _temp_1124 = 0;
+    let _temp_1125 = 0;
+    let _temp_1126 = 0;
+    let _temp_1127 = 0;
+    let _temp_1128 = 0;
+    let _temp_1129 = 0;
+    let _temp_1130 = 0;
+    let _temp_1131 = 0;
+    let _temp_1132 = 0;
+    let _temp_1133 = 0;
+    let _temp_1134 = 0;
+    let _temp_1135 = 0;
+    let _temp_1136 = 0;
+    let _temp_1137 = 0;
+    let _temp_1138 = 0;
+    let _temp_1139 = 0;
+    let _temp_1140 = 0;
+    let _temp_1141 = 0;
+    let _temp_1142 = 0;
+    let _temp_1143 = 0;
+    let _temp_1144 = 0;
+    let _temp_1145 = 0;
+    let _temp_1146 = 0;
+    let _temp_1147 = 0;
+    let _temp_1148 = 0;
+    let _temp_1149 = 0;
+    let _temp_1150 = 0;
+    let _temp_1151 = 0;
+    let _temp_1152 = 0;
+    let _temp_1153 = 0;
+    let _temp_1154 = 0;
+    let _temp_1155 = 0;
+    let _temp_1156 = 0;
+    let _temp_1157 = 0;
+    let _temp_1158 = 0;
+    let _temp_1159 = 0;
+    let _temp_1160 = 0;
+    let _temp_1161 = 0;
+    let _temp_1162 = 0;
+    let _temp_1163 = 0;
+    let _temp_1164 = 0;
+    let _temp_1165 = 0;
+    let _temp_1166 = 0;
+    let _temp_1167 = 0;
+    let _temp_1168 = 0;
+    let _temp_1169 = 0;
+    let _temp_1170 = 0;
+    let _temp_1171 = 0;
+    let _temp_1172 = 0;
+    let _temp_1173 = 0;
+    let _temp_1174 = 0;
+    let _temp_1175 = 0;
+    let _temp_1176 = 0;
+    let _temp_1177 = 0;
+    let _temp_1178 = 0;
+    let _temp_1179 = 0;
+    let _temp_1180 = 0;
+    let _temp_1181 = 0;
+    let _temp_1182 = 0;
+    let _temp_1183 = 0;
+    let _temp_1184 = 0;
+    let _temp_1185 = 0;
+    let _temp_1186 = 0;
+    let _temp_1187 = 0;
+    let _temp_1188 = 0;
+    let _temp_1189 = 0;
+    let _temp_1190 = 0;
+    let _temp_1191 = 0;
+    let _temp_1192 = 0;
+    let _temp_1193 = 0;
+    let _temp_1194 = 0;
+    let _temp_1195 = 0;
+    let _temp_1196 = 0;
+    let _temp_1197 = 0;
+    let _temp_1198 = 0;
+    let _temp_1199 = 0;
+    let _temp_1200 = 0;
+    let _temp_1201 = 0;
+    let _temp_1202 = 0;
+    let _temp_1203 = 0;
+    let _temp_1204 = 0;
+    let _temp_1205 = 0;
+    let _temp_1206 = 0;
+    let _temp_1207 = 0;
+    let _temp_1208 = 0;
+    let _temp_1209 = 0;
+    let _temp_1210 = 0;
+    let _temp_1211 = 0;
+    let _temp_1212 = 0;
+    let _temp_1213 = 0;
+    let _temp_1214 = 0;
+    let _temp_1215 = 0;
+    let _temp_1216 = 0;
+    let _temp_1217 = 0;
+    let _temp_1218 = 0;
+    let _temp_1219 = 0;
+    let _temp_1220 = 0;
+    let _temp_1221 = 0;
+    let _temp_1222 = 0;
+    let _temp_1223 = 0;
+    let _temp_1224 = 0;
+    let _temp_1225 = 0;
+    let _temp_1226 = 0;
+    let _temp_1227 = 0;
+    let _temp_1228 = 0;
+    let _temp_1229 = 0;
+    let _temp_1230 = 0;
+    let _temp_1231 = 0;
+    let _temp_1232 = 0;
+    let _temp_1233 = 0;
+    let _temp_1234 = 0;
+    let _temp_1235 = 0;
+    let _temp_1236 = 0;
+    let _temp_1237 = 0;
+    let _temp_1238 = 0;
+    let _temp_1239 = 0;
+    let _temp_1240 = 0;
+    let _temp_1241 = 0;
+    let _temp_1242 = 0;
+    let _temp_1243 = 0;
+    let _temp_1244 = 0;
+    let _temp_1245 = 0;
+    let _temp_1246 = 0;
+    let _temp_1247 = 0;
+    let _temp_1248 = 0;
+    let _temp_1249 = 0;
+    let _temp_1250 = 0;
+    let _temp_1251 = 0;
+    let _temp_1252 = 0;
+    let _temp_1253 = 0;
+    let _temp_1254 = 0;
+    let _temp_1255 = 0;
+    let _temp_1256 = 0;
+    let _temp_1257 = 0;
+    let _temp_1258 = 0;
+    let _temp_1259 = 0;
+    let _temp_1260 = 0;
+    let _temp_1261 = 0;
+    let _temp_1262 = 0;
+    let _temp_1263 = 0;
+    let _temp_1264 = 0;
+    let _temp_1265 = 0;
+    let _temp_1266 = 0;
+    let _temp_1267 = 0;
+    let _temp_1268 = 0;
+    let _temp_1269 = 0;
+    let _temp_1270 = 0;
+    let _temp_1271 = 0;
+    let _temp_1272 = 0;
+    let _temp_1273 = 0;
+    let _temp_1274 = 0;
+    let _temp_1275 = 0;
+    let _temp_1276 = 0;
+    let _temp_1277 = 0;
+    let _temp_1278 = 0;
+    let _temp_1279 = 0;
+    let _temp_1280 = 0;
+    let _temp_1281 = 0;
+    let _temp_1282 = 0;
+    let _temp_1283 = 0;
+    let _temp_1284 = 0;
+    let _temp_1285 = 0;
+    let _temp_1286 = 0;
+    let _temp_1287 = 0;
+    let _temp_1288 = 0;
+    let _temp_1289 = 0;
+    let _temp_1290 = 0;
+    let _temp_1291 = 0;
+    let _temp_1292 = 0;
+    let _temp_1293 = 0;
+    let _temp_1294 = 0;
+    let _temp_1295 = 0;
+    let _temp_1296 = 0;
+    let _temp_1297 = 0;
+    let _temp_1298 = 0;
+    let _temp_1299 = 0;
+    let _temp_1300 = 0;
+    let _temp_1301 = 0;
+    let _temp_1302 = 0;
+    let _temp_1303 = 0;
+    let _temp_1304 = 0;
+    let _temp_1305 = 0;
+    let _temp_1306 = 0;
+    let _temp_1307 = 0;
+    let _temp_1308 = 0;
+    let _temp_1309 = 0;
+    let _temp_1310 = 0;
+    let _temp_1311 = 0;
+    let _temp_1312 = 0;
+    let _temp_1313 = 0;
+    let _temp_1314 = 0;
+    let _temp_1315 = 0;
+    let _temp_1316 = 0;
+    let _temp_1317 = 0;
+    let _temp_1318 = 0;
+    let _temp_1319 = 0;
+    let _temp_1320 = 0;
+    let _temp_1321 = 0;
+    let _temp_1322 = 0;
+    let _temp_1323 = 0;
+    let _temp_1324 = 0;
+    let _temp_1325 = 0;
+    let _temp_1326 = 0;
+    let _temp_1327 = 0;
+    let _temp_1328 = 0;
+    let _temp_1329 = 0;
+    let _temp_1330 = 0;
+    let _temp_1331 = 0;
+    let _temp_1332 = 0;
+    let _temp_1333 = 0;
+    let _temp_1334 = 0;
+    let _temp_1335 = 0;
+    let _temp_1336 = 0;
+    let _temp_1337 = 0;
+    let _temp_1338 = 0;
+    let _temp_1339 = 0;
+    let _temp_1340 = 0;
+    let _temp_1341 = 0;
+    let _temp_1342 = 0;
+    let _temp_1343 = 0;
+    let _temp_1344 = 0;
+    let _temp_1345 = 0;
+    let _temp_1346 = 0;
+    let _temp_1347 = 0;
+    let _temp_1348 = 0;
+    let _temp_1349 = 0;
+    let _temp_1350 = 0;
+    let _temp_1351 = 0;
+    let _temp_1352 = 0;
+    let _temp_1353 = 0;
+    let _temp_1354 = 0;
+    let _temp_1355 = 0;
+    let _temp_1356 = 0;
+    let _temp_1357 = 0;
+    let _temp_1358 = 0;
+    let _temp_1359 = 0;
+    let _temp_1360 = 0;
+    let _temp_1361 = 0;
+    let _temp_1362 = 0;
+    let _temp_1363 = 0;
+    let _temp_1364 = 0;
+    let _temp_1365 = 0;
+    let _temp_1366 = 0;
+    let _temp_1367 = 0;
+    let _temp_1368 = 0;
+    let _temp_1369 = 0;
+    let _temp_1370 = 0;
+    let _temp_1371 = 0;
+    let _temp_1372 = 0;
+    let _temp_1373 = 0;
+    let _temp_1374 = 0;
+    let _temp_1375 = 0;
+    let _temp_1376 = 0;
+    let _temp_1377 = 0;
+    let _temp_1378 = 0;
+    let _temp_1379 = 0;
+    let _temp_1380 = 0;
+    let _temp_1381 = 0;
+    let _temp_1382 = 0;
+    let _temp_1383 = 0;
+    let _temp_1384 = 0;
+    let _temp_1385 = 0;
+    let _temp_1386 = 0;
+    let _temp_1387 = 0;
+    let _temp_1388 = 0;
+    let _temp_1389 = 0;
+    let _temp_1390 = 0;
+    let _temp_1391 = 0;
+    let _temp_1392 = 0;
+    let _temp_1393 = 0;
+    let _temp_1394 = 0;
+    let _temp_1395 = 0;
+    let _temp_1396 = 0;
+    let _temp_1397 = 0;
+    let _temp_1398 = 0;
+    let _temp_1399 = 0;
+    let _temp_1400 = 0;
+    let _temp_1401 = 0;
+    let _temp_1402 = 0;
+    let _temp_1403 = 0;
+    let _temp_1404 = 0;
+    let _temp_1405 = 0;
+    let _temp_1406 = 0;
+    let _temp_1407 = 0;
+    let _temp_1408 = 0;
+    let _temp_1409 = 0;
+    let _temp_1410 = 0;
+    let _temp_1411 = 0;
+    let _temp_1412 = 0;
+    let _temp_1413 = 0;
+    let _temp_1414 = 0;
+    let _temp_1415 = 0;
+    let _temp_1416 = 0;
+    let _temp_1417 = 0;
+    let _temp_1418 = 0;
+    let _temp_1419 = 0;
+    let _temp_1420 = 0;
+    let _temp_1421 = 0;
+    let _temp_1422 = 0;
+    let _temp_1423 = 0;
+    let _temp_1424 = 0;
+    let _temp_1425 = 0;
+    let _temp_1426 = 0;
+    let _temp_1427 = 0;
+    let _temp_1428 = 0;
+    let _temp_1429 = 0;
+    let _temp_1430 = 0;
+    let _temp_1431 = 0;
+    let _temp_1432 = 0;
+    let _temp_1433 = 0;
+    let _temp_1434 = 0;
+    let _temp_1435 = 0;
+    let _temp_1436 = 0;
+    let _temp_1437 = 0;
+    let _temp_1438 = 0;
+    let _temp_1439 = 0;
+    let _temp_1440 = 0;
+    let _temp_1441 = 0;
+    let _temp_1442 = 0;
+    let _temp_1443 = 0;
+    let _temp_1444 = 0;
+    let _temp_1445 = 0;
+    let _temp_1446 = 0;
+    let _temp_1447 = 0;
+    let _temp_1448 = 0;
+    let _temp_1449 = 0;
+    let _temp_1450 = 0;
+    let _temp_1451 = 0;
+    let _temp_1452 = 0;
+    let _temp_1453 = 0;
+    let _temp_1454 = 0;
+    let _temp_1455 = 0;
+    let _temp_1456 = 0;
+    let _temp_1457 = 0;
+    let _temp_1458 = 0;
+    let _temp_1459 = 0;
+    let _temp_1460 = 0;
+    let _temp_1461 = 0;
+    let _temp_1462 = 0;
+    let _temp_1463 = 0;
+    let _temp_1464 = 0;
+    let _temp_1465 = 0;
+    let _temp_1466 = 0;
+    let _temp_1467 = 0;
+    let _temp_1468 = 0;
+    let _temp_1469 = 0;
+    let _temp_1470 = 0;
+    let _temp_1471 = 0;
+    let _temp_1472 = 0;
+    let _temp_1473 = 0;
+    let _temp_1474 = 0;
+    let _temp_1475 = 0;
+    let _temp_1476 = 0;
+    let _temp_1477 = 0;
+    let _temp_1478 = 0;
+    let _temp_1479 = 0;
+    let _temp_1480 = 0;
+    let _temp_1481 = 0;
+    let _temp_1482 = 0;
+    let _temp_1483 = 0;
+    let _temp_1484 = 0;
+    let _temp_1485 = 0;
+    let _temp_1486 = 0;
+    let _temp_1487 = 0;
+    let _temp_1488 = 0;
+    let _temp_1489 = 0;
+    let _temp_1490 = 0;
+    let _temp_1491 = 0;
+    let _temp_1492 = 0;
+    let _temp_1493 = 0;
+    let _temp_1494 = 0;
+    let _temp_1495 = 0;
+    let _temp_1496 = 0;
+    let _temp_1497 = 0;
+    let _temp_1498 = 0;
+    let _temp_1499 = 0;
+    let _temp_1500 = 0;
+    let _temp_1501 = 0;
+    let _temp_1502 = 0;
+    let _temp_1503 = 0;
+    let _temp_1504 = 0;
+    let _temp_1505 = 0;
+    let _temp_1506 = 0;
+    let _temp_1507 = 0;
+    let _temp_1508 = 0;
+    let _temp_1509 = 0;
+    let _temp_1510 = 0;
+    let _temp_1511 = 0;
+    let _temp_1512 = 0;
+    let _temp_1513 = 0;
+    let _temp_1514 = 0;
+    let _temp_1515 = 0;
+    let _temp_1516 = 0;
+    let _temp_1517 = 0;
+    let _temp_1518 = 0;
+    let _temp_1519 = 0;
+    let _temp_1520 = 0;
+    let _temp_1521 = 0;
+    let _temp_1522 = 0;
+    let _temp_1523 = 0;
+    let _temp_1524 = 0;
+    let _temp_1525 = 0;
+    let _temp_1526 = 0;
+    let _temp_1527 = 0;
+    let _temp_1528 = 0;
+    let _temp_1529 = 0;
+    let _temp_1530 = 0;
+    let _temp_1531 = 0;
+    let _temp_1532 = 0;
+    let _temp_1533 = 0;
+    let _temp_1534 = 0;
+    let _temp_1535 = 0;
+    let _temp_1536 = 0;
+    let _temp_1537 = 0;
+    let _temp_1538 = 0;
+    let _temp_1539 = 0;
+    let _temp_1540 = 0;
+    let _temp_1541 = 0;
+    let _temp_1542 = 0;
+    let _temp_1543 = 0;
+    let _temp_1544 = 0;
+    let _temp_1545 = 0;
+    let _temp_1546 = 0;
+    let _temp_1547 = 0;
+    let _temp_1548 = 0;
+    let _temp_1549 = 0;
+    let _temp_1550 = 0;
+    let _temp_1551 = 0;
+    let _temp_1552 = 0;
+    let _temp_1553 = 0;
+    let _temp_1554 = 0;
+    let _temp_1555 = 0;
+    let _temp_1556 = 0;
+    let _temp_1557 = 0;
+    let _temp_1558 = 0;
+    let _temp_1559 = 0;
+    let _temp_1560 = 0;
+    let _temp_1561 = 0;
+    let _temp_1562 = 0;
+    let _temp_1563 = 0;
+    let _temp_1564 = 0;
+    let _temp_1565 = 0;
+    let _temp_1566 = 0;
+    let _temp_1567 = 0;
+    let _temp_1568 = 0;
+    let _temp_1569 = 0;
+    let _temp_1570 = 0;
+    let _temp_1571 = 0;
+    let _temp_1572 = 0;
+    let _temp_1573 = 0;
+    let _temp_1574 = 0;
+    let _temp_1575 = 0;
+    let _temp_1576 = 0;
+    let _temp_1577 = 0;
+    let _temp_1578 = 0;
+    let _temp_1579 = 0;
+    let _temp_1580 = 0;
+    let _temp_1581 = 0;
+    let _temp_1582 = 0;
+    let _temp_1583 = 0;
+    let _temp_1584 = 0;
+    let _temp_1585 = 0;
+    let _temp_1586 = 0;
+    let _temp_1587 = 0;
+    let _temp_1588 = 0;
+    let _temp_1589 = 0;
+    let _temp_1590 = 0;
+    let _temp_1591 = 0;
+    let _temp_1592 = 0;
+    let _temp_1593 = 0;
+    let _temp_1594 = 0;
+    let _temp_1595 = 0;
+    let _temp_1596 = 0;
+    let _temp_1597 = 0;
+    let _temp_1598 = 0;
+    let _temp_1599 = 0;
+    let _temp_1600 = 0;
+    let _temp_1601 = 0;
+    let _temp_1602 = 0;
+    let _temp_1603 = 0;
+    let _temp_1604 = 0;
+    let _temp_1605 = 0;
+    let _temp_1606 = 0;
+    let _temp_1607 = 0;
+    let _temp_1608 = 0;
+    let _temp_1609 = 0;
+    let _temp_1610 = 0;
+    let _temp_1611 = 0;
+    let _temp_1612 = 0;
+    let _temp_1613 = 0;
+    let _temp_1614 = 0;
+    let _temp_1615 = 0;
+    let _temp_1616 = 0;
+    let _temp_1617 = 0;
+    let _temp_1618 = 0;
+    let _temp_1619 = 0;
+    let _temp_1620 = 0;
+    let _temp_1621 = 0;
+    let _temp_1622 = 0;
+    let _temp_1623 = 0;
+    let _temp_1624 = 0;
+    let _temp_1625 = 0;
+    let _temp_1626 = 0;
+    let _temp_1627 = 0;
+    let _temp_1628 = 0;
+    let _temp_1629 = 0;
+    let _temp_1630 = 0;
+    let _temp_1631 = 0;
+    let _temp_1632 = 0;
+    let _temp_1633 = 0;
+    let _temp_1634 = 0;
+    let _temp_1635 = 0;
+    let _temp_1636 = 0;
+    let _temp_1637 = 0;
+    let _temp_1638 = 0;
+    let _temp_1639 = 0;
+    let _temp_1640 = 0;
+    let _temp_1641 = 0;
+    let _temp_1642 = 0;
+    let _temp_1643 = 0;
+    let _temp_1644 = 0;
+    let _temp_1645 = 0;
+    let _temp_1646 = 0;
+    let _temp_1647 = 0;
+    let _temp_1648 = 0;
+    let _temp_1649 = 0;
+    let _temp_1650 = 0;
+    let _temp_1651 = 0;
+    let _temp_1652 = 0;
+    let _temp_1653 = 0;
+    let _temp_1654 = 0;
+    let _temp_1655 = 0;
+    let _temp_1656 = 0;
+    let _temp_1657 = 0;
+    let _temp_1658 = 0;
+    let _temp_1659 = 0;
+    let _temp_1660 = 0;
+    let _temp_1661 = 0;
+    let _temp_1662 = 0;
+    let _temp_1663 = 0;
+    let _temp_1664 = 0;
+    let _temp_1665 = 0;
+    let _temp_1666 = 0;
+    let _temp_1667 = 0;
+    let _temp_1668 = 0;
+    let _temp_1669 = 0;
+    let _temp_1670 = 0;
+    let _temp_1671 = 0;
+    let _temp_1672 = 0;
+    let _temp_1673 = 0;
+    let _temp_1674 = 0;
+    let _temp_1675 = 0;
+    let _temp_1676 = 0;
+    let _temp_1677 = 0;
+    let _temp_1678 = 0;
+    let _temp_1679 = 0;
+    let _temp_1680 = 0;
+    let _temp_1681 = 0;
+    let _temp_1682 = 0;
+    let _temp_1683 = 0;
+    let _temp_1684 = 0;
+    let _temp_1685 = 0;
+    let _temp_1686 = 0;
+    let _temp_1687 = 0;
+    let _temp_1688 = 0;
+    let _temp_1689 = 0;
+    let _temp_1690 = 0;
+    let _temp_1691 = 0;
+    let _temp_1692 = 0;
+    let _temp_1693 = 0;
+    let _temp_1694 = 0;
+    let _temp_1695 = 0;
+    let _temp_1696 = 0;
+    let _temp_1697 = 0;
+    let _temp_1698 = 0;
+    let _temp_1699 = 0;
+    let _temp_1700 = 0;
+    let _temp_1701 = 0;
+    let _temp_1702 = 0;
+    let _temp_1703 = 0;
+    let _temp_1704 = 0;
+    let _temp_1705 = 0;
+    let _temp_1706 = 0;
+    let _temp_1707 = 0;
+    let _temp_1708 = 0;
+    let _temp_1709 = 0;
+    let _temp_1710 = 0;
+    let _temp_1711 = 0;
+    let _temp_1712 = 0;
+    let _temp_1713 = 0;
+    let _temp_1714 = 0;
+    let _temp_1715 = 0;
+    let _temp_1716 = 0;
+    let _temp_1717 = 0;
+    let _temp_1718 = 0;
+    let _temp_1719 = 0;
+    let _temp_1720 = 0;
+    let _temp_1721 = 0;
+    let _temp_1722 = 0;
+    let _temp_1723 = 0;
+    let _temp_1724 = 0;
+    let _temp_1725 = 0;
+    let _temp_1726 = 0;
+    let _temp_1727 = 0;
+    let _temp_1728 = 0;
+    let _temp_1729 = 0;
+    let _temp_1730 = 0;
+    let _temp_1731 = 0;
+    let _temp_1732 = 0;
+    let _temp_1733 = 0;
+    let _temp_1734 = 0;
+    let _temp_1735 = 0;
+    let _temp_1736 = 0;
+    let _temp_1737 = 0;
+    let _temp_1738 = 0;
+    let _temp_1739 = 0;
+    let _temp_1740 = 0;
+    let _temp_1741 = 0;
+    let _temp_1742 = 0;
+    let _temp_1743 = 0;
+    let _temp_1744 = 0;
+    let _temp_1745 = 0;
+    let _temp_1746 = 0;
+    let _temp_1747 = 0;
+    let _temp_1748 = 0;
+    let _temp_1749 = 0;
+    let _temp_1750 = 0;
+    let _temp_1751 = 0;
+    let _temp_1752 = 0;
+    let _temp_1753 = 0;
+    let _temp_1754 = 0;
+    let _temp_1755 = 0;
+    let _temp_1756 = 0;
+    let _temp_1757 = 0;
+    let _temp_1758 = 0;
+    let _temp_1759 = 0;
+    let _temp_1760 = 0;
+    let _temp_1761 = 0;
+    let _temp_1762 = 0;
+    let _temp_1763 = 0;
+    let _temp_1764 = 0;
+    let _temp_1765 = 0;
+    let _temp_1766 = 0;
+    let _temp_1767 = 0;
+    let _temp_1768 = 0;
+    let _temp_1769 = 0;
+    let _temp_1770 = 0;
+    let _temp_1771 = 0;
+    let _temp_1772 = 0;
+    let _temp_1773 = 0;
+    let _temp_1774 = 0;
+    let _temp_1775 = 0;
+    let _temp_1776 = 0;
+    let _temp_1777 = 0;
+    let _temp_1778 = 0;
+    let _temp_1779 = 0;
+    let _temp_1780 = 0;
+    let _temp_1781 = 0;
+    let _temp_1782 = 0;
+    let _temp_1783 = 0;
+    let _temp_1784 = 0;
+    let _temp_1785 = 0;
+    let _temp_1786 = 0;
+    let _temp_1787 = 0;
+    let _temp_1788 = 0;
+    let _temp_1789 = 0;
+    let _temp_1790 = 0;
+    let _temp_1791 = 0;
+    let _temp_1792 = 0;
+    let _temp_1793 = 0;
+    let _temp_1794 = 0;
+    let _temp_1795 = 0;
+    let _temp_1796 = 0;
+    let _temp_1797 = 0;
+    let _temp_1798 = 0;
+    let _temp_1799 = 0;
+    let _temp_1800 = 0;
+    let _temp_1801 = 0;
+    let _temp_1802 = 0;
+    let _temp_1803 = 0;
+    let _temp_1804 = 0;
+    let _temp_1805 = 0;
+    let _temp_1806 = 0;
+    let _temp_1807 = 0;
+    let _temp_1808 = 0;
+    let _temp_1809 = 0;
+    let _temp_1810 = 0;
+    let _temp_1811 = 0;
+    let _temp_1812 = 0;
+    let _temp_1813 = 0;
+    let _temp_1814 = 0;
+    let _temp_1815 = 0;
+    let _temp_1816 = 0;
+    let _temp_1817 = 0;
+    let _temp_1818 = 0;
+    let _temp_1819 = 0;
+    let _temp_1820 = 0;
+    let _temp_1821 = 0;
+    let _temp_1822 = 0;
+    let _temp_1823 = 0;
+    let _temp_1824 = 0;
+    let _temp_1825 = 0;
+    let _temp_1826 = 0;
+    let _temp_1827 = 0;
+    let _temp_1828 = 0;
+    let _temp_1829 = 0;
+    let _temp_1830 = 0;
+    let _temp_1831 = 0;
+    let _temp_1832 = 0;
+    let _temp_1833 = 0;
+    let _temp_1834 = 0;
+    let _temp_1835 = 0;
+    let _temp_1836 = 0;
+    let _temp_1837 = 0;
+    let _temp_1838 = 0;
+    let _temp_1839 = 0;
+    let _temp_1840 = 0;
+    let _temp_1841 = 0;
+    let _temp_1842 = 0;
+    let _temp_1843 = 0;
+    let _temp_1844 = 0;
+    let _temp_1845 = 0;
+    let _temp_1846 = 0;
+    let _temp_1847 = 0;
+    let _temp_1848 = 0;
+    let _temp_1849 = 0;
+    let _temp_1850 = 0;
+    let _temp_1851 = 0;
+    let _temp_1852 = 0;
+    let _temp_1853 = 0;
+    let _temp_1854 = 0;
+    let _temp_1855 = 0;
+    let _temp_1856 = 0;
+    let _temp_1857 = 0;
+    let _temp_1858 = 0;
+    let _temp_1859 = 0;
+    let _temp_1860 = 0;
+    let _temp_1861 = 0;
+    let _temp_1862 = 0;
+    let _temp_1863 = 0;
+    let _temp_1864 = 0;
+    let _temp_1865 = 0;
+    let _temp_1866 = 0;
+    let _temp_1867 = 0;
+    let _temp_1868 = 0;
+    let _temp_1869 = 0;
+    let _temp_1870 = 0;
+    let _temp_1871 = 0;
+    let _temp_1872 = 0;
+    let _temp_1873 = 0;
+    let _temp_1874 = 0;
+    let _temp_1875 = 0;
+    let _temp_1876 = 0;
+    let _temp_1877 = 0;
+    let _temp_1878 = 0;
+    let _temp_1879 = 0;
+    let _temp_1880 = 0;
+    let _temp_1881 = 0;
+    let _temp_1882 = 0;
+    let _temp_1883 = 0;
+    let _temp_1884 = 0;
+    let _temp_1885 = 0;
+    let _temp_1886 = 0;
+    let _temp_1887 = 0;
+    let _temp_1888 = 0;
+    let _temp_1889 = 0;
+    let _temp_1890 = 0;
+    let _temp_1891 = 0;
+    let _temp_1892 = 0;
+    let _temp_1893 = 0;
+    let _temp_1894 = 0;
+    let _temp_1895 = 0;
+    let _temp_1896 = 0;
+    let _temp_1897 = 0;
+    let _temp_1898 = 0;
+    let _temp_1899 = 0;
+    let _temp_1900 = 0;
+    let _temp_1901 = 0;
+    let _temp_1902 = 0;
+    let _temp_1903 = 0;
+    let _temp_1904 = 0;
+    let _temp_1905 = 0;
+    let _temp_1906 = 0;
+    let _temp_1907 = 0;
+    let _temp_1908 = 0;
+    let _temp_1909 = 0;
+    let _temp_1910 = 0;
+    let _temp_1911 = 0;
+    let _temp_1912 = 0;
+    let _temp_1913 = 0;
+    let _temp_1914 = 0;
+    let _temp_1915 = 0;
+    let _temp_1916 = 0;
+    let _temp_1917 = 0;
+    let _temp_1918 = 0;
+    let _temp_1919 = 0;
+    let _temp_1920 = 0;
+    let _temp_1921 = 0;
+    let _temp_1922 = 0;
+    let _temp_1923 = 0;
+    let _temp_1924 = 0;
+    let _temp_1925 = 0;
+    let _temp_1926 = 0;
+    let _temp_1927 = 0;
+    let _temp_1928 = 0;
+    let _temp_1929 = 0;
+    let _temp_1930 = 0;
+    let _temp_1931 = 0;
+    let _temp_1932 = 0;
+    let _temp_1933 = 0;
+    let _temp_1934 = 0;
+    let _temp_1935 = 0;
+    let _temp_1936 = 0;
+    let _temp_1937 = 0;
+    let _temp_1938 = 0;
+    let _temp_1939 = 0;
+    let _temp_1940 = 0;
+    let _temp_1941 = 0;
+    let _temp_1942 = 0;
+    let _temp_1943 = 0;
+    let _temp_1944 = 0;
+    let _temp_1945 = 0;
+    let _temp_1946 = 0;
+    let _temp_1947 = 0;
+    let _temp_1948 = 0;
+    let _temp_1949 = 0;
+    let _temp_1950 = 0;
+    let _temp_1951 = 0;
+    let _temp_1952 = 0;
+    let _temp_1953 = 0;
+    let _temp_1954 = 0;
+    let _temp_1955 = 0;
+    let _temp_1956 = 0;
+    let _temp_1957 = 0;
+    let _temp_1958 = 0;
+    let _temp_1959 = 0;
+    let _temp_1960 = 0;
+    let _temp_1961 = 0;
+    let _temp_1962 = 0;
+    let _temp_1963 = 0;
+    let _temp_1964 = 0;
+    let _temp_1965 = 0;
+    let _temp_1966 = 0;
+    let _temp_1967 = 0;
+    let _temp_1968 = 0;
+    let _temp_1969 = 0;
+    let _temp_1970 = 0;
+    let _temp_1971 = 0;
+    let _temp_1972 = 0;
+    let _temp_1973 = 0;
+    let _temp_1974 = 0;
+    let _temp_1975 = 0;
+    let _temp_1976 = 0;
+    let _temp_1977 = 0;
+    let _temp_1978 = 0;
+    let _temp_1979 = 0;
+    let _temp_1980 = 0;
+    let _temp_1981 = 0;
+    let _temp_1982 = 0;
+    let _temp_1983 = 0;
+    let _temp_1984 = 0;
+    let _temp_1985 = 0;
+    let _temp_1986 = 0;
+    let _temp_1987 = 0;
+    let _temp_1988 = 0;
+    let _temp_1989 = 0;
+    let _temp_1990 = 0;
+    let _temp_1991 = 0;
+    let _temp_1992 = 0;
+    let _temp_1993 = 0;
+    let _temp_1994 = 0;
+    let _temp_1995 = 0;
+    let _temp_1996 = 0;
+    let _temp_1997 = 0;
+    let _temp_1998 = 0;
+    let _temp_1999 = 0;
+    let _temp_2000 = 0;
+    let _temp_2001 = 0;
+    let _temp_2002 = 0;
+    let _temp_2003 = 0;
+    let _temp_2004 = 0;
+    let _temp_2005 = 0;
+    let _temp_2006 = 0;
+    let _temp_2007 = 0;
+    let _temp_2008 = 0;
+    let _temp_2009 = 0;
+    let _temp_2010 = 0;
+    let _temp_2011 = 0;
+    let _temp_2012 = 0;
+    let _temp_2013 = 0;
+    let _temp_2014 = 0;
+    let _temp_2015 = 0;
+    let _temp_2016 = 0;
+    let _temp_2017 = 0;
+    let _temp_2018 = 0;
+    let _temp_2019 = 0;
+    let _temp_2020 = 0;
+    let _temp_2021 = 0;
+    let _temp_2022 = 0;
+    let _temp_2023 = 0;
+    let _temp_2024 = 0;
+    let _temp_2025 = 0;
+    let _temp_2026 = 0;
+    let _temp_2027 = 0;
+    let _temp_2028 = 0;
+    let _temp_2029 = 0;
+    let _temp_2030 = 0;
+    let _temp_2031 = 0;
+    let _temp_2032 = 0;
+    let _temp_2033 = 0;
+    let _temp_2034 = 0;
+    let _temp_2035 = 0;
+    let _temp_2036 = 0;
+    let _temp_2037 = 0;
+    let _temp_2038 = 0;
+    let _temp_2039 = 0;
+    let _temp_2040 = 0;
+    let _temp_2041 = 0;
+    let _temp_2042 = 0;
+    let _temp_2043 = 0;
+    let _temp_2044 = 0;
+    let _temp_2045 = 0;
+    let _temp_2046 = 0;
+    let _temp_2047 = 0;
+    let _temp_2048 = 0;
+    let _temp_2049 = 0;
+    let _temp_2050 = 0;
+    let _temp_2051 = 0;
+    let _temp_2052 = 0;
+    let _temp_2053 = 0;
+    let _temp_2054 = 0;
+    let _temp_2055 = 0;
+    let _temp_2056 = 0;
+    let _temp_2057 = 0;
+    let _temp_2058 = 0;
+    let _temp_2059 = 0;
+    let _temp_2060 = 0;
+    let _temp_2061 = 0;
+    let _temp_2062 = 0;
+    let _temp_2063 = 0;
+    let _temp_2064 = 0;
+    let _temp_2065 = 0;
+    let _temp_2066 = 0;
+    let _temp_2067 = 0;
+    let _temp_2068 = 0;
+    let _temp_2069 = 0;
+    let _temp_2070 = 0;
+    let _temp_2071 = 0;
+    let _temp_2072 = 0;
+    let _temp_2073 = 0;
+    let _temp_2074 = 0;
+    let _temp_2075 = 0;
+    let _temp_2076 = 0;
+    let _temp_2077 = 0;
+    let _temp_2078 = 0;
+    let _temp_2079 = 0;
+    let _temp_2080 = 0;
+    let _temp_2081 = 0;
+    let _temp_2082 = 0;
+    let _temp_2083 = 0;
+    let _temp_2084 = 0;
+    let _temp_2085 = 0;
+    let _temp_2086 = 0;
+    let _temp_2087 = 0;
+    let _temp_2088 = 0;
+    let _temp_2089 = 0;
+    let _temp_2090 = 0;
+    let _temp_2091 = 0;
+    let _temp_2092 = 0;
+    let _temp_2093 = 0;
+    let _temp_2094 = 0;
+    let _temp_2095 = 0;
+    let _temp_2096 = 0;
+    let _temp_2097 = 0;
+    let _temp_2098 = 0;
+    let _temp_2099 = 0;
+    let _temp_2100 = 0;
+    let _temp_2101 = 0;
+    let _temp_2102 = 0;
+    let _temp_2103 = 0;
+    let _temp_2104 = 0;
+    let _temp_2105 = 0;
+    let _temp_2106 = 0;
+    let _temp_2107 = 0;
+    let _temp_2108 = 0;
+    let _temp_2109 = 0;
+    let _temp_2110 = 0;
+    let _temp_2111 = 0;
+    let _temp_2112 = 0;
+    let _temp_2113 = 0;
+    let _temp_2114 = 0;
+    let _temp_2115 = 0;
+    let _temp_2116 = 0;
+    let _temp_2117 = 0;
+    let _temp_2118 = 0;
+    let _temp_2119 = 0;
+    let _temp_2120 = 0;
+    let _temp_2121 = 0;
+    let _temp_2122 = 0;
+    let _temp_2123 = 0;
+    let _temp_2124 = 0;
+    let _temp_2125 = 0;
+    let _temp_2126 = 0;
+    let _temp_2127 = 0;
+    let _temp_2128 = 0;
+    let _temp_2129 = 0;
+    let _temp_2130 = 0;
+    let _temp_2131 = 0;
+    let _temp_2132 = 0;
+    let _temp_2133 = 0;
+    let _temp_2134 = 0;
+    let _temp_2135 = 0;
+    let _temp_2136 = 0;
+    let _temp_2137 = 0;
+    let _temp_2138 = 0;
+    let _temp_2139 = 0;
+    let _temp_2140 = 0;
+    let _temp_2141 = 0;
+    let _temp_2142 = 0;
+    let _temp_2143 = 0;
+    let _temp_2144 = 0;
+    let _temp_2145 = 0;
+    let _temp_2146 = 0;
+    let _temp_2147 = 0;
+    let _temp_2148 = 0;
+    let _temp_2149 = 0;
+    let _temp_2150 = 0;
+    let _temp_2151 = 0;
+    let _temp_2152 = 0;
+    let _temp_2153 = 0;
+    let _temp_2154 = 0;
+    let _temp_2155 = 0;
+    let _temp_2156 = 0;
+    let _temp_2157 = 0;
+    let _temp_2158 = 0;
+    let _temp_2159 = 0;
+    let _temp_2160 = 0;
+    let _temp_2161 = 0;
+    let _temp_2162 = 0;
+    let _temp_2163 = 0;
+    let _temp_2164 = 0;
+    let _temp_2165 = 0;
+    let _temp_2166 = 0;
+    let _temp_2167 = 0;
+    let _temp_2168 = 0;
+    let _temp_2169 = 0;
+    let _temp_2170 = 0;
+    let _temp_2171 = 0;
+    let _temp_2172 = 0;
+    let _temp_2173 = 0;
+    let _temp_2174 = 0;
+    let _temp_2175 = 0;
+    let _temp_2176 = 0;
+    let _temp_2177 = 0;
+    let _temp_2178 = 0;
+    let _temp_2179 = 0;
+    let _temp_2180 = 0;
+    let _temp_2181 = 0;
+    let _temp_2182 = 0;
+    let _temp_2183 = 0;
+    let _temp_2184 = 0;
+    let _temp_2185 = 0;
+    let _temp_2186 = 0;
+    let _temp_2187 = 0;
+    let _temp_2188 = 0;
+    let _temp_2189 = 0;
+    let _temp_2190 = 0;
+    let _temp_2191 = 0;
+    let _temp_2192 = 0;
+    let _temp_2193 = 0;
+    let _temp_2194 = 0;
+    let _temp_2195 = 0;
+    let _temp_2196 = 0;
+    let _temp_2197 = 0;
+    let _temp_2198 = 0;
+    let _temp_2199 = 0;
+    let _temp_2200 = 0;
+    let _temp_2201 = 0;
+    let _temp_2202 = 0;
+    let _temp_2203 = 0;
+    let _temp_2204 = 0;
+    let _temp_2205 = 0;
+    let _temp_2206 = 0;
+    let _temp_2207 = 0;
+    let _temp_2208 = 0;
+    let _temp_2209 = 0;
+    let _temp_2210 = 0;
+    let _temp_2211 = 0;
+    let _temp_2212 = 0;
+    let _temp_2213 = 0;
+    let _temp_2214 = 0;
+    let _temp_2215 = 0;
+    let _temp_2216 = 0;
+    let _temp_2217 = 0;
+    let _temp_2218 = 0;
+    let _temp_2219 = 0;
+    let _temp_2220 = 0;
+    let _temp_2221 = 0;
+    let _temp_2222 = 0;
+    let _temp_2223 = 0;
+    let _temp_2224 = 0;
+    let _temp_2225 = 0;
+    let _temp_2226 = 0;
+    let _temp_2227 = 0;
+    let _temp_2228 = 0;
+    let _temp_2229 = 0;
+    let _temp_2230 = 0;
+    let _temp_2231 = 0;
+    let _temp_2232 = 0;
+    let _temp_2233 = 0;
+    let _temp_2234 = 0;
+    let _temp_2235 = 0;
+    let _temp_2236 = 0;
+    let _temp_2237 = 0;
+    let _temp_2238 = 0;
+    let _temp_2239 = 0;
+    let _temp_2240 = 0;
+    let _temp_2241 = 0;
+    let _temp_2242 = 0;
+    let _temp_2243 = 0;
+    let _temp_2244 = 0;
+    let _temp_2245 = 0;
+    let _temp_2246 = 0;
+    let _temp_2247 = 0;
+    let _temp_2248 = 0;
+    let _temp_2249 = 0;
+    let _temp_2250 = 0;
+    let _temp_2251 = 0;
+    let _temp_2252 = 0;
+    let _temp_2253 = 0;
+    let _temp_2254 = 0;
+    let _temp_2255 = 0;
+    let _temp_2256 = 0;
+    let _temp_2257 = 0;
+    let _temp_2258 = 0;
+    let _temp_2259 = 0;
+    let _temp_2260 = 0;
+    let _temp_2261 = 0;
+    let _temp_2262 = 0;
+    let _temp_2263 = 0;
+    let _temp_2264 = 0;
+    let _temp_2265 = 0;
+    let _temp_2266 = 0;
+    let _temp_2267 = 0;
+    let _temp_2268 = 0;
+    let _temp_2269 = 0;
+    let _temp_2270 = 0;
+    let _temp_2271 = 0;
+    let _temp_2272 = 0;
+    let _temp_2273 = 0;
+    let _temp_2274 = 0;
+    let _temp_2275 = 0;
+    let _temp_2276 = 0;
+    let _temp_2277 = 0;
+    let _temp_2278 = 0;
+    let _temp_2279 = 0;
+    let _temp_2280 = 0;
+    let _temp_2281 = 0;
+    let _temp_2282 = 0;
+    let _temp_2283 = 0;
+    let _temp_2284 = 0;
+    let _temp_2285 = 0;
+    let _temp_2286 = 0;
+    let _temp_2287 = 0;
+    let _temp_2288 = 0;
+    let _temp_2289 = 0;
+    let _temp_2290 = 0;
+    let _temp_2291 = 0;
+    let _temp_2292 = 0;
+    let _temp_2293 = 0;
+    let _temp_2294 = 0;
+    let _temp_2295 = 0;
+    let _temp_2296 = 0;
+    let _temp_2297 = 0;
+    let _temp_2298 = 0;
+    let _temp_2299 = 0;
+    let _temp_2300 = 0;
+    let _temp_2301 = 0;
+    let _temp_2302 = 0;
+    let _temp_2303 = 0;
+    let _temp_2304 = 0;
+    let _temp_2305 = 0;
+    let _temp_2306 = 0;
+    let _temp_2307 = 0;
+    let _temp_2308 = 0;
+    let _temp_2309 = 0;
+    let _temp_2310 = 0;
+    let _temp_2311 = 0;
+    let _temp_2312 = 0;
+    let _temp_2313 = 0;
+    let _temp_2314 = 0;
+    let _temp_2315 = 0;
+    let _temp_2316 = 0;
+    let _temp_2317 = 0;
+    let _temp_2318 = 0;
+    let _temp_2319 = 0;
+    let _temp_2320 = 0;
+    let _temp_2321 = 0;
+    let _temp_2322 = 0;
+    let _temp_2323 = 0;
+    let _temp_2324 = 0;
+    let _temp_2325 = 0;
+    let _temp_2326 = 0;
+    let _temp_2327 = 0;
+    let _temp_2328 = 0;
+    let _temp_2329 = 0;
+    let _temp_2330 = 0;
+    let _temp_2331 = 0;
+    let _temp_2332 = 0;
+    let _temp_2333 = 0;
+    let _temp_2334 = 0;
+    let _temp_2335 = 0;
+    let _temp_2336 = 0;
+    let _temp_2337 = 0;
+    let _temp_2338 = 0;
+    let _temp_2339 = 0;
+    let _temp_2340 = 0;
+    let _temp_2341 = 0;
+    let _temp_2342 = 0;
+    let _temp_2343 = 0;
+    let _temp_2344 = 0;
+    let _temp_2345 = 0;
+    let _temp_2346 = 0;
+    let _temp_2347 = 0;
+    let _temp_2348 = 0;
+    let _temp_2349 = 0;
+    let _temp_2350 = 0;
+    let _temp_2351 = 0;
+    let _temp_2352 = 0;
+    let _temp_2353 = 0;
+    let _temp_2354 = 0;
+    let _temp_2355 = 0;
+    let _temp_2356 = 0;
+    let _temp_2357 = 0;
+    let _temp_2358 = 0;
+    let _temp_2359 = 0;
+    let _temp_2360 = 0;
+    let _temp_2361 = 0;
+    let _temp_2362 = 0;
+    let _temp_2363 = 0;
+    let _temp_2364 = 0;
+    let _temp_2365 = 0;
+    let _temp_2366 = 0;
+    let _temp_2367 = 0;
+    let _temp_2368 = 0;
+    let _temp_2369 = 0;
+    let _temp_2370 = 0;
+    let _temp_2371 = 0;
+    let _temp_2372 = 0;
+    let _temp_2373 = 0;
+    let _temp_2374 = 0;
+    let _temp_2375 = 0;
+    let _temp_2376 = 0;
+    let _temp_2377 = 0;
+    let _temp_2378 = 0;
+    let _temp_2379 = 0;
+    let _temp_2380 = 0;
+    let _temp_2381 = 0;
+    let _temp_2382 = 0;
+    let _temp_2383 = 0;
+    let _temp_2384 = 0;
+    let _temp_2385 = 0;
+    let _temp_2386 = 0;
+    let _temp_2387 = 0;
+    let _temp_2388 = 0;
+    let _temp_2389 = 0;
+    let _temp_2390 = 0;
+    let _temp_2391 = 0;
+    let _temp_2392 = 0;
+    let _temp_2393 = 0;
+    let _temp_2394 = 0;
+    let _temp_2395 = 0;
+    let _temp_2396 = 0;
+    let _temp_2397 = 0;
+    let _temp_2398 = 0;
+    let _temp_2399 = 0;
+    let _temp_2400 = 0;
+    let _temp_2401 = 0;
+    let _temp_2402 = 0;
+    let _temp_2403 = 0;
+    let _temp_2404 = 0;
+    let _temp_2405 = 0;
+    let _temp_2406 = 0;
+    let _temp_2407 = 0;
+    let _temp_2408 = 0;
+    let _temp_2409 = 0;
+    let _temp_2410 = 0;
+    let _temp_2411 = 0;
+    let _temp_2412 = 0;
+    let _temp_2413 = 0;
+    let _temp_2414 = 0;
+    let _temp_2415 = 0;
+    let _temp_2416 = 0;
+    let _temp_2417 = 0;
+    let _temp_2418 = 0;
+    let _temp_2419 = 0;
+    let _temp_2420 = 0;
+    let _temp_2421 = 0;
+    let _temp_2422 = 0;
+    let _temp_2423 = 0;
+    let _temp_2424 = 0;
+    let _temp_2425 = 0;
+    let _temp_2426 = 0;
+    let _temp_2427 = 0;
+    let _temp_2428 = 0;
+    let _temp_2429 = 0;
+    let _temp_2430 = 0;
+    let _temp_2431 = 0;
+    let _temp_2432 = 0;
+    let _temp_2433 = 0;
+    let _temp_2434 = 0;
+    let _temp_2435 = 0;
+    let _temp_2436 = 0;
+    let _temp_2437 = 0;
+    let _temp_2438 = 0;
+    let _temp_2439 = 0;
+    let _temp_2440 = 0;
+    let _temp_2441 = 0;
+    let _temp_2442 = 0;
+    let _temp_2443 = 0;
+    let _temp_2444 = 0;
+    let _temp_2445 = 0;
+    let _temp_2446 = 0;
+    let _temp_2447 = 0;
+    let _temp_2448 = 0;
+    let _temp_2449 = 0;
+    let _temp_2450 = 0;
+    let _temp_2451 = 0;
+    let _temp_2452 = 0;
+    let _temp_2453 = 0;
+    let _temp_2454 = 0;
+    let _temp_2455 = 0;
+    let _temp_2456 = 0;
+    let _temp_2457 = 0;
+    let _temp_2458 = 0;
+    let _temp_2459 = 0;
+    let _temp_2460 = 0;
+    let _temp_2461 = 0;
+    let _temp_2462 = 0;
+    let _temp_2463 = 0;
+    let _temp_2464 = 0;
+    let _temp_2465 = 0;
+    let _temp_2466 = 0;
+    let _temp_2467 = 0;
+    let _temp_2468 = 0;
+    let _temp_2469 = 0;
+    let _temp_2470 = 0;
+    let _temp_2471 = 0;
+    let _temp_2472 = 0;
+    let _temp_2473 = 0;
+    let _temp_2474 = 0;
+    let _temp_2475 = 0;
+    let _temp_2476 = 0;
+    let _temp_2477 = 0;
+    let _temp_2478 = 0;
+    let _temp_2479 = 0;
+    let _temp_2480 = 0;
+    let _temp_2481 = 0;
+    let _temp_2482 = 0;
+    let _temp_2483 = 0;
+    let _temp_2484 = 0;
+    let _temp_2485 = 0;
+    let _temp_2486 = 0;
+    let _temp_2487 = 0;
+    let _temp_2488 = 0;
+    let _temp_2489 = 0;
+    let _temp_2490 = 0;
+    let _temp_2491 = 0;
+    let _temp_2492 = 0;
+    let _temp_2493 = 0;
+    let _temp_2494 = 0;
+    let _temp_2495 = 0;
+    let _temp_2496 = 0;
+    let _temp_2497 = 0;
+    let _temp_2498 = 0;
+    let _temp_2499 = 0;
+    let _temp_2500 = 0;
+    let _temp_2501 = 0;
+    let _temp_2502 = 0;
+    let _temp_2503 = 0;
+    let _temp_2504 = 0;
+    let _temp_2505 = 0;
+    let _temp_2506 = 0;
+    let _temp_2507 = 0;
+    let _temp_2508 = 0;
+    let _temp_2509 = 0;
+    let _temp_2510 = 0;
+    let _temp_2511 = 0;
+    let _temp_2512 = 0;
+    let _temp_2513 = 0;
+    let _temp_2514 = 0;
+    let _temp_2515 = 0;
+    let _temp_2516 = 0;
+    let _temp_2517 = 0;
+    let _temp_2518 = 0;
+    let _temp_2519 = 0;
+    let _temp_2520 = 0;
+    let _temp_2521 = 0;
+    let _temp_2522 = 0;
+    let _temp_2523 = 0;
+    let _temp_2524 = 0;
+    let _temp_2525 = 0;
+    let _temp_2526 = 0;
+    let _temp_2527 = 0;
+    let _temp_2528 = 0;
+    let _temp_2529 = 0;
+    let _temp_2530 = 0;
+    let _temp_2531 = 0;
+    let _temp_2532 = 0;
+    let _temp_2533 = 0;
+    let _temp_2534 = 0;
+    let _temp_2535 = 0;
+    let _temp_2536 = 0;
+    let _temp_2537 = 0;
+    let _temp_2538 = 0;
+    let _temp_2539 = 0;
+    let _temp_2540 = 0;
+    let _temp_2541 = 0;
+    let _temp_2542 = 0;
+    let _temp_2543 = 0;
+    let _temp_2544 = 0;
+    let _temp_2545 = 0;
+    let _temp_2546 = 0;
+    let _temp_2547 = 0;
+    let _temp_2548 = 0;
+    let _temp_2549 = 0;
+    let _temp_2550 = 0;
+    let _temp_2551 = 0;
+    let _temp_2552 = 0;
+    let _temp_2553 = 0;
+    let _temp_2554 = 0;
+    let _temp_2555 = 0;
+    let _temp_2556 = 0;
+    let _temp_2557 = 0;
+    let _temp_2558 = 0;
+    let _temp_2559 = 0;
+    let _temp_2560 = 0;
+    let _temp_2561 = 0;
+    let _temp_2562 = 0;
+    let _temp_2563 = 0;
+    let _temp_2564 = 0;
+    let _temp_2565 = 0;
+    let _temp_2566 = 0;
+    let _temp_2567 = 0;
+    let _temp_2568 = 0;
+    let _temp_2569 = 0;
+    let _temp_2570 = 0;
+    let _temp_2571 = 0;
+    let _temp_2572 = 0;
+    let _temp_2573 = 0;
+    let _temp_2574 = 0;
+    let _temp_2575 = 0;
+    let _temp_2576 = 0;
+    let _temp_2577 = 0;
+    let _temp_2578 = 0;
+    let _temp_2579 = 0;
+    let _temp_2580 = 0;
+    let _temp_2581 = 0;
+    let _temp_2582 = 0;
+    let _temp_2583 = 0;
+    let _temp_2584 = 0;
+    let _temp_2585 = 0;
+    let _temp_2586 = 0;
+    let _temp_2587 = 0;
+    let _temp_2588 = 0;
+    let _temp_2589 = 0;
+    let _temp_2590 = 0;
+    let _temp_2591 = 0;
+    let _temp_2592 = 0;
+    let _temp_2593 = 0;
+}
diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr
index 6ff3641bc15..d85661f6faa 100644
--- a/src/test/ui/repr/repr-transparent.stderr
+++ b/src/test/ui/repr/repr-transparent.stderr
@@ -58,7 +58,7 @@ error[E0731]: transparent enum needs exactly one variant, but has 2
 LL | enum MultipleVariants {
    | ^^^^^^^^^^^^^^^^^^^^^ needs exactly one variant, but has 2
 LL |     Foo(String),
-   |     -----------
+   |     ---
 LL |     Bar,
    |     --- too many variants in `MultipleVariants`
 
diff --git a/src/test/ui/resolve/issue-55673.rs b/src/test/ui/resolve/issue-55673.rs
new file mode 100644
index 00000000000..0436bd39742
--- /dev/null
+++ b/src/test/ui/resolve/issue-55673.rs
@@ -0,0 +1,12 @@
+trait Foo {
+    type Bar;
+}
+
+fn foo<T: Foo>()
+where
+    T::Baa: std::fmt::Debug,
+    //~^ ERROR associated type `Baa` not found for `T`
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-55673.stderr b/src/test/ui/resolve/issue-55673.stderr
new file mode 100644
index 00000000000..39318f95905
--- /dev/null
+++ b/src/test/ui/resolve/issue-55673.stderr
@@ -0,0 +1,9 @@
+error[E0220]: associated type `Baa` not found for `T`
+  --> $DIR/issue-55673.rs:7:8
+   |
+LL |     T::Baa: std::fmt::Debug,
+   |        ^^^ there is a similarly named associated type `Bar` in the trait `Foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 81d8a34881c..e546d9f64ec 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -318,7 +318,7 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:27:20
    |
 LL |             Fn(u8),
-   |             ------ fn(u8) -> Z {Z::Fn} defined here
+   |             -- fn(u8) -> Z {Z::Fn} defined here
 ...
 LL |         let _: Z = Z::Fn;
    |                -   ^^^^^ expected enum `Z`, found fn item
@@ -353,7 +353,7 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:43:16
    |
 LL |         Fn(u8),
-   |         ------ fn(u8) -> E {E::Fn} defined here
+   |         -- fn(u8) -> E {E::Fn} defined here
 ...
 LL |     let _: E = m::E::Fn;
    |            -   ^^^^^^^^ expected enum `E`, found fn item
@@ -388,7 +388,7 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:51:16
    |
 LL |         Fn(u8),
-   |         ------ fn(u8) -> E {E::Fn} defined here
+   |         -- fn(u8) -> E {E::Fn} defined here
 ...
 LL |     let _: E = E::Fn;
    |            -   ^^^^^ expected enum `E`, found fn item
diff --git a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
index 64cae3748c9..720b7b119ce 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
+++ b/src/test/ui/rfc-2008-non-exhaustive/variant.stderr
@@ -8,7 +8,7 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^^^^^^
+   |                       ^^^^^
 
 error[E0603]: unit variant `Unit` is private
   --> $DIR/variant.rs:14:47
@@ -44,7 +44,7 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^^^^^^
+   |                       ^^^^^
 
 error[E0603]: tuple variant `Tuple` is private
   --> $DIR/variant.rs:26:35
@@ -56,7 +56,7 @@ note: the tuple variant `Tuple` is defined here
   --> $DIR/auxiliary/variants.rs:5:23
    |
 LL |     #[non_exhaustive] Tuple(u32),
-   |                       ^^^^^^^^^^
+   |                       ^^^^^
 
 error[E0639]: cannot create non-exhaustive variant using struct expression
   --> $DIR/variant.rs:8:26
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
index a7e108d72d1..e0dded15217 100644
--- a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
@@ -1,19 +1,19 @@
 fn and_chain() {
     let z;
     if true && { z = 3; true} && z == 3 {}
-    //~^ ERROR use of possibly-uninitialized
+    //~^ ERROR E0381
 }
 
 fn and_chain_2() {
     let z;
     true && { z = 3; true} && z == 3;
-    //~^ ERROR use of possibly-uninitialized
+    //~^ ERROR E0381
 }
 
 fn or_chain() {
     let z;
     if false || { z = 3; false} || z == 3 {}
-    //~^ ERROR use of possibly-uninitialized
+    //~^ ERROR E0381
 }
 
 fn main() {
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
index 3c47040cc8c..30d5a6779fc 100644
--- a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
@@ -1,20 +1,32 @@
-error[E0381]: use of possibly-uninitialized variable: `z`
+error[E0381]: used binding `z` is possibly-uninitialized
   --> $DIR/chains-without-let.rs:3:34
    |
+LL |     let z;
+   |         - binding declared here but left uninitialized
 LL |     if true && { z = 3; true} && z == 3 {}
-   |                                  ^ use of possibly-uninitialized `z`
+   |                  -----           ^ `z` used here but it is possibly-uninitialized
+   |                  |
+   |                  binding initialized here in some conditions
 
-error[E0381]: use of possibly-uninitialized variable: `z`
+error[E0381]: used binding `z` is possibly-uninitialized
   --> $DIR/chains-without-let.rs:9:31
    |
+LL |     let z;
+   |         - binding declared here but left uninitialized
 LL |     true && { z = 3; true} && z == 3;
-   |                               ^ use of possibly-uninitialized `z`
+   |               -----           ^ `z` used here but it is possibly-uninitialized
+   |               |
+   |               binding initialized here in some conditions
 
-error[E0381]: use of possibly-uninitialized variable: `z`
+error[E0381]: used binding `z` is possibly-uninitialized
   --> $DIR/chains-without-let.rs:15:36
    |
+LL |     let z;
+   |         - binding declared here but left uninitialized
 LL |     if false || { z = 3; false} || z == 3 {}
-   |                                    ^ use of possibly-uninitialized `z`
+   |                   -----            ^ `z` used here but it is possibly-uninitialized
+   |                   |
+   |                   binding initialized here in some conditions
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 5cf06cf4b27..93a1f691c8e 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -1249,7 +1249,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:138:41: 138:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:138:41: 138:43]`
 help: use parentheses to call this closure
    |
 LL |     if let Range { start: F, end } = F..(|| true)() {}
@@ -1449,7 +1449,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:203:44: 203:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:203:44: 203:46]`
 help: use parentheses to call this closure
    |
 LL |     while let Range { start: F, end } = F..(|| true)() {}
diff --git a/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr b/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr
index edbea330a04..b52720ae3d9 100644
--- a/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr
+++ b/src/test/ui/rust-2018/uniform-paths/issue-87932.stderr
@@ -2,7 +2,7 @@ error[E0599]: no function or associated item named `deserialize` found for struc
   --> $DIR/issue-87932.rs:13:8
    |
 LL | pub struct A {}
-   |            - function or associated item `deserialize` not found for this struct
+   | ------------ function or associated item `deserialize` not found for this struct
 ...
 LL |     A::deserialize();
    |        ^^^^^^^^^^^ function or associated item not found in `A`
diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
index 06ccc5b1afe..3c7cccfc9a1 100644
--- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
+++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope
   --> $DIR/point-at-arbitrary-self-type-method.rs:8:7
    |
 LL | struct A;
-   |        - method `foo` not found for this struct
+   | -------- method `foo` not found for this struct
 ...
 LL |     fn foo(self: Box<Self>) {}
    |        --- the method is available for `Box<A>` here
diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
index bd77f67fb4e..366c14f7616 100644
--- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
+++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr
@@ -6,7 +6,7 @@ LL | trait B { fn foo(self: Box<Self>); }
    |              |
    |              the method is available for `Box<A>` here
 LL | struct A;
-   |        - method `foo` not found for this struct
+   | -------- method `foo` not found for this struct
 ...
 LL |     A.foo()
    |       ^^^ method not found in `A`
diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
index b4693b7242a..6b43801b5e0 100644
--- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
+++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr
@@ -29,17 +29,14 @@ LL |     f.f.call_mut(())
 error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13
    |
-LL |       let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| {
-   |           ----- captured outer variable
+LL |     let mut f = move |g: Box<dyn FnMut(isize)>, b: isize| {
+   |         ----- captured outer variable
 ...
-LL |       f(Box::new(|a| {
-   |  ________________-
-LL | |
-LL | |         foo(f);
-   | |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait
-LL | |
-LL | |     }), 3);
-   | |_____- captured by this `FnMut` closure
+LL |     f(Box::new(|a| {
+   |                --- captured by this `FnMut` closure
+LL |
+LL |         foo(f);
+   |             ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 52:58]`, which does not implement the `Copy` trait
 
 error[E0505]: cannot move out of `f` because it is borrowed
   --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16
diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr
index 912618555f4..4f30edb3f89 100644
--- a/src/test/ui/span/issue-7575.stderr
+++ b/src/test/ui/span/issue-7575.stderr
@@ -42,7 +42,7 @@ error[E0599]: no method named `fff` found for struct `Myisize` in the current sc
   --> $DIR/issue-7575.rs:62:30
    |
 LL | struct Myisize(isize);
-   |        ------- method `fff` not found for this struct
+   | -------------- method `fff` not found for this struct
 ...
 LL |     u.f8(42) + u.f9(342) + m.fff(42)
    |                            --^^^
diff --git a/src/test/ui/span/move-closure.stderr b/src/test/ui/span/move-closure.stderr
index 3e7041f02b3..dcc60789694 100644
--- a/src/test/ui/span/move-closure.stderr
+++ b/src/test/ui/span/move-closure.stderr
@@ -7,7 +7,7 @@ LL |     let x: () = move || ();
    |            expected due to this
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/move-closure.rs:5:17: 5:27]`
+                found closure `[closure@$DIR/move-closure.rs:5:17: 5:24]`
 help: use parentheses to call this closure
    |
 LL |     let x: () = (move || ())();
diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
index 53a22305e81..d1004a69058 100644
--- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
+++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr
@@ -13,8 +13,8 @@ error[E0599]: the method `foo_one` exists for struct `MyStruct`, but its trait b
    |
 LL | struct MyStruct;
    | ---------------
-   | |      |
-   | |      method `foo_one` not found for this struct
+   | |
+   | method `foo_one` not found for this struct
    | doesn't satisfy `MyStruct: Foo`
 ...
 LL |     println!("{}", MyStruct.foo_one());
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index 450984aacc7..a751ba79347 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,8 +1,8 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[54ea]::Id::This) }, Ty((I,))), [])`
-  --> $DIR/repeated_projection_type.rs:19:1
+error: cannot specialize on associated type `<V as Id>::This == (I,)`
+  --> $DIR/repeated_projection_type.rs:19:15
    |
 LL | impl<I, V: Id<This = (I,)>> X for V {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |               ^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr
index b1ab58551e6..ba9d6bbe300 100644
--- a/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr
+++ b/src/test/ui/specialization/min_specialization/spec-marker-supertraits.stderr
@@ -1,8 +1,8 @@
 error: cannot specialize on trait `HasMethod`
-  --> $DIR/spec-marker-supertraits.rs:22:1
+  --> $DIR/spec-marker-supertraits.rs:22:9
    |
 LL | impl<T: Marker> Spec for T {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr
index 1f2ff99d415..e935786624b 100644
--- a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr
+++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr
@@ -1,8 +1,8 @@
 error: cannot specialize on trait `Default`
-  --> $DIR/specialization_super_trait.rs:13:1
+  --> $DIR/specialization_super_trait.rs:13:9
    |
 LL | impl<T: Default> SpecMarker for T {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_trait.stderr
index ecb07ba908e..bc87ae0f8b8 100644
--- a/src/test/ui/specialization/min_specialization/specialization_trait.stderr
+++ b/src/test/ui/specialization/min_specialization/specialization_trait.stderr
@@ -11,10 +11,10 @@ LL | impl<T> SpecMarker for (T, T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: cannot specialize on trait `Clone`
-  --> $DIR/specialization_trait.rs:21:1
+  --> $DIR/specialization_trait.rs:21:9
    |
 LL | impl<T: Clone> SpecMarker for [T] {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr
index 92daddbd800..7b79c7eb4ad 100644
--- a/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr
+++ b/src/test/ui/specialization/min_specialization/specialize_on_trait.stderr
@@ -1,8 +1,8 @@
 error: cannot specialize on trait `SpecMarker`
-  --> $DIR/specialize_on_trait.rs:15:1
+  --> $DIR/specialize_on_trait.rs:15:9
    |
 LL | impl<T: SpecMarker> X for T {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         ^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr
index 6f2ade0d0ab..10978728fa3 100644
--- a/src/test/ui/stability-attribute/missing-const-stability.stderr
+++ b/src/test/ui/stability-attribute/missing-const-stability.stderr
@@ -4,12 +4,6 @@ error: function has missing const stability attribute
 LL | pub const fn foo() {}
    | ^^^^^^^^^^^^^^^^^^^^^
 
-error: associated function has missing const stability attribute
-  --> $DIR/missing-const-stability.rs:15:5
-   |
-LL |     pub const fn foo() {}
-   |     ^^^^^^^^^^^^^^^^^^^^^
-
 error: implementation has missing const stability attribute
   --> $DIR/missing-const-stability.rs:27:1
    |
@@ -19,5 +13,11 @@ LL | |     fn fun() {}
 LL | | }
    | |_^
 
+error: associated function has missing const stability attribute
+  --> $DIR/missing-const-stability.rs:15:5
+   |
+LL |     pub const fn foo() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 766db2a8356..c7d420e0aae 100644
--- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -21,18 +21,18 @@ help: use parentheses to call the function
 LL |     bar(foo());
    |            ++
 
-error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
+error[E0277]: `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
 LL |     let async_closure = async || ();
    |                         -------- consider calling this closure
 LL |     bar(async_closure);
-   |     --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` is not a future
+   |     --- ^^^^^^^^^^^^^ `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]` is not a future
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
-   = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited
+   = help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33]`
+   = note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33] must be a future or must implement `IntoFuture` to be awaited
 note: required by a bound in `bar`
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
    |
diff --git a/src/test/ui/suggestions/auxiliary/meow.rs b/src/test/ui/suggestions/auxiliary/meow.rs
new file mode 100644
index 00000000000..115df70a690
--- /dev/null
+++ b/src/test/ui/suggestions/auxiliary/meow.rs
@@ -0,0 +1,11 @@
+pub trait Meow {
+    fn meow(&self) {}
+}
+
+pub struct GlobalMeow;
+
+impl Meow for GlobalMeow {}
+
+pub(crate) struct PrivateMeow;
+
+impl Meow for PrivateMeow {}
diff --git a/src/test/ui/suggestions/derive-trait-for-method-call.stderr b/src/test/ui/suggestions/derive-trait-for-method-call.stderr
index 0ec57fabdad..7cc372f2422 100644
--- a/src/test/ui/suggestions/derive-trait-for-method-call.stderr
+++ b/src/test/ui/suggestions/derive-trait-for-method-call.stderr
@@ -11,7 +11,7 @@ LL | enum CloneEnum {
    | -------------- doesn't satisfy `CloneEnum: Default`
 ...
 LL | struct Foo<X, Y> (X, Y);
-   |        --- method `test` not found for this struct
+   | ---------------- method `test` not found for this struct
 ...
 LL |     let y = x.test();
    |               ^^^^ method cannot be called on `Foo<Enum, CloneEnum>` due to unsatisfied trait bounds
@@ -43,7 +43,7 @@ LL | struct CloneStruct {
    | ------------------ doesn't satisfy `CloneStruct: Default`
 ...
 LL | struct Foo<X, Y> (X, Y);
-   |        --- method `test` not found for this struct
+   | ---------------- method `test` not found for this struct
 ...
 LL |     let y = x.test();
    |               ^^^^ method cannot be called on `Foo<Struct, CloneStruct>` due to unsatisfied trait bounds
@@ -65,7 +65,7 @@ error[E0599]: the method `test` exists for struct `Foo<Vec<Enum>, Instant>`, but
   --> $DIR/derive-trait-for-method-call.rs:40:15
    |
 LL | struct Foo<X, Y> (X, Y);
-   |        --- method `test` not found for this struct
+   | ---------------- method `test` not found for this struct
 ...
 LL |     let y = x.test();
    |               ^^^^ method cannot be called on `Foo<Vec<Enum>, Instant>` due to unsatisfied trait bounds
diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
index fb1055c9c30..e06ee4290ab 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr
@@ -1,487 +1,342 @@
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:28:21
    |
-LL |       let x = X(Y);
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-   | |               --    ^ help: consider borrowing here: `&x`
-   | |               |
-   | |               data moved here
-   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-LL | |
-LL | |
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+LL |         let X(_t) = x;
+   |               --    ^ help: consider borrowing here: `&x`
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:32:34
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-LL | |
-LL | |         if let Either::One(_t) = e { }
-   | |                            --    ^ help: consider borrowing here: `&e`
-   | |                            |
-   | |                            data moved here
-   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^ help: consider borrowing here: `&e`
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:36:37
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         while let Either::One(_t) = e { }
-   | |                               --    ^ help: consider borrowing here: `&e`
-   | |                               |
-   | |                               data moved here
-   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^ help: consider borrowing here: `&e`
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:40:15
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match e {
-   | |               ^ help: consider borrowing here: `&e`
-...  |
-LL | |             Either::One(_t)
-   | |                         --
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^ help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:47:15
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match e {
-   | |               ^ help: consider borrowing here: `&e`
-...  |
-LL | |             Either::One(_t) => (),
-   | |                         --
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         match e {
+   |               ^ help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:56:25
    |
-LL |       let x = X(Y);
-   |           - captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         let X(mut _t) = x;
-   | |               ------    ^ help: consider borrowing here: `&x`
-   | |               |
-   | |               data moved here
-   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^ help: consider borrowing here: `&x`
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:60:38
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         if let Either::One(mut _t) = em { }
-   | |                            ------    ^^ help: consider borrowing here: `&em`
-   | |                            |
-   | |                            data moved here
-   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^ help: consider borrowing here: `&em`
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:64:41
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         while let Either::One(mut _t) = em { }
-   | |                               ------    ^^ help: consider borrowing here: `&em`
-   | |                               |
-   | |                               data moved here
-   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^ help: consider borrowing here: `&em`
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:68:15
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match em {
-   | |               ^^ help: consider borrowing here: `&em`
-...  |
-LL | |             Either::One(mut _t)
-   | |                         ------
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^ help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure
   --> $DIR/move-into-closure.rs:75:15
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fn(|| {
-   |  ________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match em {
-   | |               ^^ help: consider borrowing here: `&em`
-...  |
-LL | |             Either::One(mut _t) => (),
-   | |                         ------
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `Fn` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fn(|| {
+   |                -- captured by this `Fn` closure
+...
+LL |         match em {
+   |               ^^ help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:95:21
    |
-LL |       let x = X(Y);
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-   | |               --    ^ help: consider borrowing here: `&x`
-   | |               |
-   | |               data moved here
-   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-LL | |
-LL | |
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+LL |         let X(_t) = x;
+   |               --    ^ help: consider borrowing here: `&x`
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:99:34
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-LL | |
-LL | |         if let Either::One(_t) = e { }
-   | |                            --    ^ help: consider borrowing here: `&e`
-   | |                            |
-   | |                            data moved here
-   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         if let Either::One(_t) = e { }
+   |                            --    ^ help: consider borrowing here: `&e`
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:103:37
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         while let Either::One(_t) = e { }
-   | |                               --    ^ help: consider borrowing here: `&e`
-   | |                               |
-   | |                               data moved here
-   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         while let Either::One(_t) = e { }
+   |                               --    ^ help: consider borrowing here: `&e`
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:107:15
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match e {
-   | |               ^ help: consider borrowing here: `&e`
-...  |
-LL | |             Either::One(_t)
-   | |                         --
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         match e {
+   |               ^ help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t)
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:114:15
    |
-LL |       let e = Either::One(X(Y));
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match e {
-   | |               ^ help: consider borrowing here: `&e`
-...  |
-LL | |             Either::One(_t) => (),
-   | |                         --
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let e = Either::One(X(Y));
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         match e {
+   |               ^ help: consider borrowing here: `&e`
+...
+LL |             Either::One(_t) => (),
+   |                         --
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:123:25
    |
-LL |       let x = X(Y);
-   |           - captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         let X(mut _t) = x;
-   | |               ------    ^ help: consider borrowing here: `&x`
-   | |               |
-   | |               data moved here
-   | |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let x = X(Y);
+   |         - captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         let X(mut _t) = x;
+   |               ------    ^ help: consider borrowing here: `&x`
+   |               |
+   |               data moved here
+   |               move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:127:38
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         if let Either::One(mut _t) = em { }
-   | |                            ------    ^^ help: consider borrowing here: `&em`
-   | |                            |
-   | |                            data moved here
-   | |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         if let Either::One(mut _t) = em { }
+   |                            ------    ^^ help: consider borrowing here: `&em`
+   |                            |
+   |                            data moved here
+   |                            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:131:41
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         while let Either::One(mut _t) = em { }
-   | |                               ------    ^^ help: consider borrowing here: `&em`
-   | |                               |
-   | |                               data moved here
-   | |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         while let Either::One(mut _t) = em { }
+   |                               ------    ^^ help: consider borrowing here: `&em`
+   |                               |
+   |                               data moved here
+   |                               move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:135:15
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match em {
-   | |               ^^ help: consider borrowing here: `&em`
-...  |
-LL | |             Either::One(mut _t)
-   | |                         ------
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         match em {
+   |               ^^ help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t)
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:142:15
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match em {
-   | |               ^^ help: consider borrowing here: `&em`
-...  |
-LL | |             Either::One(mut _t) => (),
-   | |                         ------
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         match em {
+   |               ^^ help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure
   --> $DIR/move-into-closure.rs:150:15
    |
-LL |       let mut em = Either::One(X(Y));
-   |           ------ captured outer variable
-...
-LL |       consume_fnmut(|| {
-   |  ___________________-
-LL | |         let X(_t) = x;
-LL | |
-LL | |
-...  |
-LL | |         match em {
-   | |               ^^ help: consider borrowing here: `&em`
-...  |
-LL | |             Either::One(mut _t) => (),
-   | |                         ------
-   | |                         |
-   | |                         data moved here
-   | |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
-...  |
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut em = Either::One(X(Y));
+   |         ------ captured outer variable
+...
+LL |     consume_fnmut(|| {
+   |                   -- captured by this `FnMut` closure
+...
+LL |         match em {
+   |               ^^ help: consider borrowing here: `&em`
+...
+LL |             Either::One(mut _t) => (),
+   |                         ------
+   |                         |
+   |                         data moved here
+   |                         move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
 error: aborting due to 21 previous errors
 
diff --git a/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr b/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
index d5af89e3547..4658ecb3a7a 100644
--- a/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
+++ b/src/test/ui/suggestions/dont-wrap-ambiguous-receivers.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `pick` found for struct `Chaenomeles` in the curre
   --> $DIR/dont-wrap-ambiguous-receivers.rs:18:25
    |
 LL |     pub struct Chaenomeles;
-   |                ----------- method `pick` not found for this struct
+   |     ---------------------- method `pick` not found for this struct
 ...
 LL |     banana::Chaenomeles.pick()
    |                         ^^^^ method not found in `Chaenomeles`
diff --git a/src/test/ui/suggestions/field-has-method.stderr b/src/test/ui/suggestions/field-has-method.stderr
index 34b6230e19b..def16401750 100644
--- a/src/test/ui/suggestions/field-has-method.stderr
+++ b/src/test/ui/suggestions/field-has-method.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `kind` found for struct `InferOk` in the current s
   --> $DIR/field-has-method.rs:19:15
    |
 LL | struct InferOk<T> {
-   |        ------- method `kind` not found for this struct
+   | ----------------- method `kind` not found for this struct
 ...
 LL |     let k = i.kind();
    |               ^^^^ method not found in `InferOk<Ty>`
diff --git a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index 101e7aecc02..fb0a6f70bfb 100644
--- a/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/src/test/ui/suggestions/fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -19,13 +19,13 @@ help: use parentheses to call the function
 LL |     bar(foo());
    |            ++
 
-error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]: T` is not satisfied
+error[E0277]: the trait bound `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]: T` is not satisfied
   --> $DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:19:9
    |
 LL |     let closure = || S;
    |                   -- consider calling this closure
 LL |     bar(closure);
-   |     --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:23]`
+   |     --- ^^^^^^^ the trait `T` is not implemented for `[closure@$DIR/fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:18:19: 18:21]`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index 505ed2ad7b3..e75ce0da82e 100644
--- a/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/src/test/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -130,7 +130,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:35:16
    |
 LL |     A(usize),
-   |     -------- fn(usize) -> E {E::A} defined here
+   |     - fn(usize) -> E {E::A} defined here
 ...
 LL |     let _: E = E::A;
    |            -   ^^^^ expected enum `E`, found fn item
@@ -278,14 +278,14 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:46:20
    |
 LL |     let closure = || 42;
-   |                   ----- the found closure
+   |                   -- the found closure
 LL |     let _: usize = closure;
    |            -----   ^^^^^^^ expected `usize`, found closure
    |            |
    |            expected due to this
    |
    = note: expected type `usize`
-           found closure `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:24]`
+           found closure `[closure@$DIR/fn-or-tuple-struct-without-args.rs:45:19: 45:21]`
 help: use parentheses to call this closure
    |
 LL |     let _: usize = closure();
diff --git a/src/test/ui/suggestions/issue-84973-blacklist.stderr b/src/test/ui/suggestions/issue-84973-blacklist.stderr
index 5d8d688a073..ae0d3efca47 100644
--- a/src/test/ui/suggestions/issue-84973-blacklist.stderr
+++ b/src/test/ui/suggestions/issue-84973-blacklist.stderr
@@ -30,11 +30,11 @@ help: consider annotating `S` with `#[derive(Clone)]`
 LL | #[derive(Clone)]
    |
 
-error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` cannot be unpinned
+error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:22]` cannot be unpinned
   --> $DIR/issue-84973-blacklist.rs:17:5
    |
 LL |     f_unpin(static || { yield; });
-   |     ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]`
+   |     ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:22]`
    |
    = note: consider using `Box::pin`
 note: required by a bound in `f_unpin`
diff --git a/src/test/ui/suggestions/issue-99080.rs b/src/test/ui/suggestions/issue-99080.rs
new file mode 100644
index 00000000000..91f574f35b8
--- /dev/null
+++ b/src/test/ui/suggestions/issue-99080.rs
@@ -0,0 +1,16 @@
+// aux-build:meow.rs
+
+extern crate meow;
+
+use meow::Meow;
+
+fn needs_meow<T: Meow>(t: T) {}
+
+fn main() {
+    needs_meow(1usize);
+    //~^ ERROR the trait bound `usize: Meow` is not satisfied
+}
+
+struct LocalMeow;
+
+impl Meow for LocalMeow {}
diff --git a/src/test/ui/suggestions/issue-99080.stderr b/src/test/ui/suggestions/issue-99080.stderr
new file mode 100644
index 00000000000..d1908dd9d0d
--- /dev/null
+++ b/src/test/ui/suggestions/issue-99080.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `usize: Meow` is not satisfied
+  --> $DIR/issue-99080.rs:10:16
+   |
+LL |     needs_meow(1usize);
+   |     ---------- ^^^^^^ the trait `Meow` is not implemented for `usize`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the following other types implement trait `Meow`:
+             GlobalMeow
+             LocalMeow
+note: required by a bound in `needs_meow`
+  --> $DIR/issue-99080.rs:7:18
+   |
+LL | fn needs_meow<T: Meow>(t: T) {}
+   |                  ^^^^ required by this bound in `needs_meow`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 85c534364b6..e3fe25d5f9c 100644
--- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -10,7 +10,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
   --> $DIR/missing-lifetimes-in-signature.rs:19:5
    |
 LL |   fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
-   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 22:6]` captures the anonymous lifetime defined here
+   |                            ------ hidden type `[closure@$DIR/missing-lifetimes-in-signature.rs:19:5: 19:12]` captures the anonymous lifetime defined here
 ...
 LL | /     move || {
 LL | |
diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr
index 16cbbaba512..1d3dff3be34 100644
--- a/src/test/ui/suggestions/option-content-move2.stderr
+++ b/src/test/ui/suggestions/option-content-move2.stderr
@@ -1,22 +1,19 @@
 error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure
   --> $DIR/option-content-move2.rs:9:9
    |
-LL |       let mut var = None;
-   |           ------- captured outer variable
-LL |       func(|| {
-   |  __________-
-LL | |         // Shouldn't suggest `move ||.as_ref()` here
-LL | |         move || {
-   | |         ^^^^^^^ move out of `var` occurs here
-LL | |
-LL | |             var = Some(NotCopyable);
-   | |             ---
-   | |             |
-   | |             variable moved due to use in closure
-   | |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
-LL | |         }
-LL | |     });
-   | |_____- captured by this `FnMut` closure
+LL |     let mut var = None;
+   |         ------- captured outer variable
+LL |     func(|| {
+   |          -- captured by this `FnMut` closure
+LL |         // Shouldn't suggest `move ||.as_ref()` here
+LL |         move || {
+   |         ^^^^^^^ move out of `var` occurs here
+LL |
+LL |             var = Some(NotCopyable);
+   |             ---
+   |             |
+   |             variable moved due to use in closure
+   |             move occurs because `var` has type `Option<NotCopyable>`, which does not implement the `Copy` trait
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parenthesized-deref-suggestion.rs b/src/test/ui/suggestions/parenthesized-deref-suggestion.rs
index 0b4ccdd5a56..0b4ccdd5a56 100644
--- a/src/test/ui/parenthesized-deref-suggestion.rs
+++ b/src/test/ui/suggestions/parenthesized-deref-suggestion.rs
diff --git a/src/test/ui/parenthesized-deref-suggestion.stderr b/src/test/ui/suggestions/parenthesized-deref-suggestion.stderr
index cafddbe2624..cafddbe2624 100644
--- a/src/test/ui/parenthesized-deref-suggestion.stderr
+++ b/src/test/ui/suggestions/parenthesized-deref-suggestion.stderr
diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
index 3497c31826c..3fb418b1c0a 100644
--- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
+++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `default_hello` found for struct `GenericAssocMeth
   --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:9:7
    |
 LL | struct GenericAssocMethod<T>(T);
-   |        ------------------ method `default_hello` not found for this struct
+   | ---------------------------- method `default_hello` not found for this struct
 ...
 LL |     x.default_hello();
    |     --^^^^^^^^^^^^^
diff --git a/src/test/ui/suggestions/suggest-box.stderr b/src/test/ui/suggestions/suggest-box.stderr
index d5c49a477b0..2bdaa4e9780 100644
--- a/src/test/ui/suggestions/suggest-box.stderr
+++ b/src/test/ui/suggestions/suggest-box.stderr
@@ -11,7 +11,7 @@ LL | |     };
    | |_____^ expected struct `Box`, found closure
    |
    = note: expected struct `Box<dyn Fn() -> Result<(), ()>>`
-             found closure `[closure@$DIR/suggest-box.rs:4:47: 7:6]`
+             found closure `[closure@$DIR/suggest-box.rs:4:47: 4:49]`
    = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
 help: store this in the heap by calling `Box::new`
    |
diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr
index dd9010e3295..97d7e6696a8 100644
--- a/src/test/ui/suggestions/suggest-methods.stderr
+++ b/src/test/ui/suggestions/suggest-methods.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `bat` found for struct `Foo` in the current scope
   --> $DIR/suggest-methods.rs:18:7
    |
 LL | struct Foo;
-   |        --- method `bat` not found for this struct
+   | ---------- method `bat` not found for this struct
 ...
 LL |     f.bat(1.0);
    |       ^^^ help: there is an associated function with a similar name: `bar`
diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.rs b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs
index 355708c08ec..496c305bc2a 100644
--- a/src/test/ui/suggestions/suggest-on-bare-closure-call.rs
+++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.rs
@@ -1,4 +1,11 @@
+// edition:2021
+
+#![feature(async_closure)]
+
 fn main() {
     let _ = ||{}();
     //~^ ERROR expected function, found `()`
+
+    let _ = async ||{}();
+    //~^ ERROR expected function, found `()`
 }
diff --git a/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr
index 81f2e498fe5..e65a6eb4939 100644
--- a/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr
+++ b/src/test/ui/suggestions/suggest-on-bare-closure-call.stderr
@@ -1,5 +1,5 @@
 error[E0618]: expected function, found `()`
-  --> $DIR/suggest-on-bare-closure-call.rs:2:15
+  --> $DIR/suggest-on-bare-closure-call.rs:6:15
    |
 LL |     let _ = ||{}();
    |               ^^--
@@ -11,6 +11,19 @@ help: if you meant to create this closure and immediately call it, surround the
 LL |     let _ = (||{})();
    |             +    +
 
-error: aborting due to previous error
+error[E0618]: expected function, found `()`
+  --> $DIR/suggest-on-bare-closure-call.rs:9:21
+   |
+LL |     let _ = async ||{}();
+   |                     ^^--
+   |                     |
+   |                     call expression requires function
+   |
+help: if you meant to create this closure and immediately call it, surround the closure with parentheses
+   |
+LL |     let _ = (async ||{})();
+   |             +          +
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0618`.
diff --git a/src/test/ui/suggestions/suggest-variants.stderr b/src/test/ui/suggestions/suggest-variants.stderr
index cccf9378d4d..0e2e41b85e2 100644
--- a/src/test/ui/suggestions/suggest-variants.stderr
+++ b/src/test/ui/suggestions/suggest-variants.stderr
@@ -2,7 +2,7 @@ error[E0599]: no variant named `Squareee` found for enum `Shape`
   --> $DIR/suggest-variants.rs:12:41
    |
 LL | enum Shape {
-   | ---------- variant `Squareee` not found here
+   | ---------- variant `Squareee` not found for this enum
 ...
 LL |     println!("My shape is {:?}", Shape::Squareee { size: 5});
    |                                         ^^^^^^^^ help: there is a variant with a similar name: `Square`
@@ -11,7 +11,7 @@ error[E0599]: no variant named `Circl` found for enum `Shape`
   --> $DIR/suggest-variants.rs:13:41
    |
 LL | enum Shape {
-   | ---------- variant `Circl` not found here
+   | ---------- variant `Circl` not found for this enum
 ...
 LL |     println!("My shape is {:?}", Shape::Circl { size: 5});
    |                                         ^^^^^ help: there is a variant with a similar name: `Circle`
@@ -20,7 +20,7 @@ error[E0599]: no variant named `Rombus` found for enum `Shape`
   --> $DIR/suggest-variants.rs:14:41
    |
 LL | enum Shape {
-   | ---------- variant `Rombus` not found here
+   | ---------- variant `Rombus` not found for this enum
 ...
 LL |     println!("My shape is {:?}", Shape::Rombus{ size: 5});
    |                                         ^^^^^^ variant not found in `Shape`
@@ -29,7 +29,7 @@ error[E0599]: no variant or associated item named `Squareee` found for enum `Sha
   --> $DIR/suggest-variants.rs:15:12
    |
 LL | enum Shape {
-   |      ----- variant or associated item `Squareee` not found for this enum
+   | ---------- variant or associated item `Squareee` not found for this enum
 ...
 LL |     Shape::Squareee;
    |            ^^^^^^^^
@@ -41,7 +41,7 @@ error[E0599]: no variant or associated item named `Circl` found for enum `Shape`
   --> $DIR/suggest-variants.rs:16:12
    |
 LL | enum Shape {
-   |      ----- variant or associated item `Circl` not found for this enum
+   | ---------- variant or associated item `Circl` not found for this enum
 ...
 LL |     Shape::Circl;
    |            ^^^^^
@@ -53,7 +53,7 @@ error[E0599]: no variant or associated item named `Rombus` found for enum `Shape
   --> $DIR/suggest-variants.rs:17:12
    |
 LL | enum Shape {
-   |      ----- variant or associated item `Rombus` not found for this enum
+   | ---------- variant or associated item `Rombus` not found for this enum
 ...
 LL |     Shape::Rombus;
    |            ^^^^^^ variant or associated item not found in `Shape`
diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr
index 6127446c83e..de64269d1f1 100644
--- a/src/test/ui/suggestions/unnamable-types.stderr
+++ b/src/test/ui/suggestions/unnamable-types.stderr
@@ -19,7 +19,7 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures
 LL | const C: _ = || 42;
    |          ^ not allowed in type signatures
    |
-note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:19]` cannot be named
+note: however, the inferred type `[closure@$DIR/unnamable-types.rs:17:14: 17:16]` cannot be named
   --> $DIR/unnamable-types.rs:17:14
    |
 LL | const C: _ = || 42;
@@ -31,7 +31,7 @@ error: missing type for `const` item
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
    |       ^
    |
-note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:51]>` cannot be named
+note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
   --> $DIR/unnamable-types.rs:23:11
    |
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
@@ -55,7 +55,7 @@ error: missing type for `const` item
 LL | const G = || -> i32 { yield 0; return 1; };
    |       ^
    |
-note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:43]` cannot be named
+note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:20]` cannot be named
   --> $DIR/unnamable-types.rs:37:11
    |
 LL | const G = || -> i32 { yield 0; return 1; };
diff --git a/src/test/ui/suggestions/use-placement-typeck.stderr b/src/test/ui/suggestions/use-placement-typeck.stderr
index aa9880a60b6..3b2749773a1 100644
--- a/src/test/ui/suggestions/use-placement-typeck.stderr
+++ b/src/test/ui/suggestions/use-placement-typeck.stderr
@@ -8,7 +8,7 @@ LL |         fn abc(&self) {}
    |            --- the method is available for `S` here
 LL |     }
 LL |     pub struct S;
-   |                - method `abc` not found for this struct
+   |     ------------ method `abc` not found for this struct
    |
    = help: items from traits can only be used if the trait is in scope
 help: the following trait is implemented but not in scope; perhaps add a `use` for it:
diff --git a/src/test/ui/terminal-width/flag-human.rs b/src/test/ui/terminal-width/flag-human.rs
deleted file mode 100644
index e445a84fd01..00000000000
--- a/src/test/ui/terminal-width/flag-human.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// compile-flags: -Z terminal-width=20
-
-// This test checks that `-Z terminal-width` effects the human error output by restricting it to an
-// arbitrarily low value so that the effect is visible.
-
-fn main() {
-    let _: () = 42;
-    //~^ ERROR mismatched types
-}
diff --git a/src/test/ui/terminal-width/flag-json.rs b/src/test/ui/terminal-width/flag-json.rs
deleted file mode 100644
index 3d2530e204b..00000000000
--- a/src/test/ui/terminal-width/flag-json.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// compile-flags: -Z terminal-width=20 --error-format=json
-
-// This test checks that `-Z terminal-width` effects the JSON error output by restricting it to an
-// arbitrarily low value so that the effect is visible.
-
-fn main() {
-    let _: () = 42;
-    //~^ ERROR arguments to this function are incorrect
-}
diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs
new file mode 100644
index 00000000000..557d890882b
--- /dev/null
+++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.rs
@@ -0,0 +1,33 @@
+struct Victim<'a, T: Perpetrator + ?Sized> {
+  value: u8,
+  perp: &'a T,
+}
+
+trait VictimTrait {
+  type Ret;
+  fn get(self) -> Self::Ret;
+}
+
+// Actual fix is here
+impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+  type Ret = u8;
+  fn get(self) -> Self::Ret {
+    self.value
+  }
+}
+
+trait Perpetrator {
+  fn getter<'a>(&'a self) -> Victim<'a, Self> {
+    Victim {
+      value: 0,
+      perp: self,
+    }
+  }
+
+  fn trigger(&self) {
+    self.getter().get();
+    //~^ ERROR the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied
+  }
+}
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr
new file mode 100644
index 00000000000..543ceac8e91
--- /dev/null
+++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound-2.stderr
@@ -0,0 +1,31 @@
+error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied
+  --> $DIR/impl-derived-implicit-sized-bound-2.rs:28:19
+   |
+LL | struct Victim<'a, T: Perpetrator + ?Sized> {
+   | ------------------------------------------
+   | |
+   | method `get` not found for this struct
+   | doesn't satisfy `Victim<'_, Self>: VictimTrait`
+...
+LL |     self.getter().get();
+   |                   ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds
+   |
+note: trait bound `Self: Sized` was not satisfied
+  --> $DIR/impl-derived-implicit-sized-bound-2.rs:12:10
+   |
+LL | impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+   |          ^                            -----------     -------------
+   |          |
+   |          unsatisfied trait bound introduced here
+help: consider relaxing the type parameter's implicit `Sized` bound
+   |
+LL | impl<'a, T: ?Sized + Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+   |             ++++++++
+help: consider restricting the type parameter to satisfy the trait bound
+   |
+LL | struct Victim<'a, T: Perpetrator + ?Sized> where Self: Sized {
+   |                                            +++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs
new file mode 100644
index 00000000000..28da41a0ca5
--- /dev/null
+++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.rs
@@ -0,0 +1,36 @@
+struct Victim<'a, T: Perpetrator + ?Sized>
+where
+  Self: Sized
+{
+  value: u8,
+  perp: &'a T,
+}
+
+trait VictimTrait {
+  type Ret;
+  fn get(self) -> Self::Ret;
+}
+
+// Actual fix is here
+impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+  type Ret = u8;
+  fn get(self) -> Self::Ret {
+    self.value
+  }
+}
+
+trait Perpetrator {
+  fn getter<'a>(&'a self) -> Victim<'a, Self> {
+    Victim {
+      value: 0,
+      perp: self,
+    }
+  }
+
+  fn trigger(&self) {
+    self.getter().get();
+    //~^ ERROR the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied
+  }
+}
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr
new file mode 100644
index 00000000000..f08d685836e
--- /dev/null
+++ b/src/test/ui/trait-bounds/impl-derived-implicit-sized-bound.stderr
@@ -0,0 +1,31 @@
+error[E0599]: the method `get` exists for struct `Victim<'_, Self>`, but its trait bounds were not satisfied
+  --> $DIR/impl-derived-implicit-sized-bound.rs:31:19
+   |
+LL | struct Victim<'a, T: Perpetrator + ?Sized>
+   | ------------------------------------------
+   | |
+   | method `get` not found for this struct
+   | doesn't satisfy `Victim<'_, Self>: VictimTrait`
+...
+LL |     self.getter().get();
+   |                   ^^^ method cannot be called on `Victim<'_, Self>` due to unsatisfied trait bounds
+   |
+note: trait bound `Self: Sized` was not satisfied
+  --> $DIR/impl-derived-implicit-sized-bound.rs:15:10
+   |
+LL | impl<'a, T: Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+   |          ^                            -----------     -------------
+   |          |
+   |          unsatisfied trait bound introduced here
+help: consider relaxing the type parameter's implicit `Sized` bound
+   |
+LL | impl<'a, T: ?Sized + Perpetrator /*+ ?Sized*/> VictimTrait for Victim<'a, T> {
+   |             ++++++++
+help: consider restricting the type parameter to satisfy the trait bound
+   |
+LL |   Self: Sized, Self: Sized
+   |              +++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs
deleted file mode 100644
index fd975aaaee4..00000000000
--- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-// known-bug: #93008
-// build-fail
-// failure-status: 101
-// compile-flags:--crate-type=lib -Zmir-opt-level=3
-// rustc-env:RUST_BACKTRACE=0
-
-// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked"
-// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
-// normalize-stderr-test "error: internal compiler error.*" -> "error: internal compiler error"
-// normalize-stderr-test "encountered.*with incompatible types:" "encountered ... with incompatible types:"
-// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> ""
-// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
-// normalize-stderr-test "note: compiler flags.*\n\n" -> ""
-// normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
-// normalize-stderr-test "query stack during panic:\n" -> ""
-// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
-// normalize-stderr-test "end of query stack\n" -> ""
-// normalize-stderr-test "#.*\n" -> ""
-
-// This is a known bug that @compiler-errors tried to fix in #94238,
-// but the solution was probably not correct.
-
-pub trait Factory<T> {
-    type Item;
-}
-
-pub struct IntFactory;
-
-impl<T> Factory<T> for IntFactory {
-    type Item = usize;
-}
-
-pub fn foo<T>()
-where
-    IntFactory: Factory<T>,
-{
-    let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
-}
-
-#[inline]
-pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
-    0usize
-}
diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr
deleted file mode 100644
index 56cc5c93c96..00000000000
--- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: internal compiler error
-
-error: internal compiler error
-                                encountered ... with incompatible types:
-                                left-hand side has type: <IntFactory as Factory<T>>::Item
-                                right-hand side has type: usize
-  --> $DIR/select-param-env-instead-of-blanket.rs:42:5
-   |
-LL |     let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
-   |                                                   ---------- in this inlined function call
-...
-LL |     0usize
-   |     ^^^^^^
-   |
-   = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:128:36
-
-thread 'rustc' panicked
-
diff --git a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
index 115539a6dc2..6ce57b6263e 100644
--- a/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
+++ b/src/test/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
@@ -15,7 +15,6 @@ LL |     s.strip_suffix(b'\n').unwrap_or(s)
              &'c &'b str
              [char; N]
              char
-             pattern::MultiCharEqPattern<C>
    = note: required because of the requirements on the impl of `Pattern<'_>` for `u8`
 
 error: aborting due to previous error
diff --git a/src/test/ui/traits/issue-3973.stderr b/src/test/ui/traits/issue-3973.stderr
index 188125d248d..87ee0804930 100644
--- a/src/test/ui/traits/issue-3973.stderr
+++ b/src/test/ui/traits/issue-3973.stderr
@@ -11,7 +11,7 @@ error[E0599]: no function or associated item named `new` found for struct `Point
   --> $DIR/issue-3973.rs:22:20
    |
 LL | struct Point {
-   |        ----- function or associated item `new` not found for this struct
+   | ------------ function or associated item `new` not found for this struct
 ...
 LL |     let p = Point::new(0.0, 0.0);
    |                    ^^^ function or associated item not found in `Point`
diff --git a/src/test/ui/traits/issue-59029-1.stderr b/src/test/ui/traits/issue-59029-1.stderr
index 53cdb8b1baf..203a8928530 100644
--- a/src/test/ui/traits/issue-59029-1.stderr
+++ b/src/test/ui/traits/issue-59029-1.stderr
@@ -2,13 +2,13 @@ error[E0220]: associated type `Res` not found for `Self`
   --> $DIR/issue-59029-1.rs:5:52
    |
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-   |                                                    ^^^ associated type `Res` not found
+   |                                                    ^^^ there is a similarly named associated type `Res` in the trait `Svc`
 
 error[E0220]: associated type `Res` not found for `Self`
   --> $DIR/issue-59029-1.rs:5:52
    |
 LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-   |                                                    ^^^ associated type `Res` not found
+   |                                                    ^^^ there is a similarly named associated type `Res` in the trait `Svc`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/traits/issue-85735.stderr b/src/test/ui/traits/issue-85735.stderr
index fa280135beb..9e80497ca6e 100644
--- a/src/test/ui/traits/issue-85735.stderr
+++ b/src/test/ui/traits/issue-85735.stderr
@@ -4,7 +4,14 @@ error[E0283]: type annotations needed: cannot satisfy `T: FnMut<(&'a (),)>`
 LL |     T: FnMut(&'a ()),
    |        ^^^^^^^^^^^^^
    |
-   = note: cannot satisfy `T: FnMut<(&'a (),)>`
+note: multiple `impl`s or `where` clauses satisfying `T: FnMut<(&'a (),)>` found
+  --> $DIR/issue-85735.rs:7:8
+   |
+LL |     T: FnMut(&'a ()),
+   |        ^^^^^^^^^^^^^
+LL |
+LL |     T: FnMut(&'b ()),
+   |        ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs
index cf2218fe522..499a64f2816 100644
--- a/src/test/ui/traits/issue-91949-hangs-on-recursion.rs
+++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.rs
@@ -1,4 +1,5 @@
 // build-fail
+// compile-flags: -Zinline-mir=no
 // error-pattern: overflow evaluating the requirement `(): Sized`
 // error-pattern: function cannot return without recursing
 
diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
index 6c04616344f..86dbd0aac03 100644
--- a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
+++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
@@ -1,5 +1,5 @@
 warning: function cannot return without recursing
-  --> $DIR/issue-91949-hangs-on-recursion.rs:21:1
+  --> $DIR/issue-91949-hangs-on-recursion.rs:22:1
    |
 LL | / fn recurse<T>(elements: T) -> Vec<char>
 LL | | where
@@ -18,7 +18,7 @@ error[E0275]: overflow evaluating the requirement `(): Sized`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`issue_91949_hangs_on_recursion`)
    = note: required because of the requirements on the impl of `Iterator` for `std::iter::Empty<()>`
    = note: 171 redundant requirements hidden
-   = note: required because of the requirements on the impl of `Iterator` for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:25:45: 25:52]>>`
+   = note: required because of the requirements on the impl of `Iterator` for `IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), Map<IteratorOfWrapped<(), std::iter::Empty<()>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>, [closure@$DIR/issue-91949-hangs-on-recursion.rs:26:45: 26:48]>>`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/traits/item-privacy.stderr b/src/test/ui/traits/item-privacy.stderr
index 06ed5ac081d..7f78b37ba84 100644
--- a/src/test/ui/traits/item-privacy.stderr
+++ b/src/test/ui/traits/item-privacy.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `a` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:67:7
    |
 LL | struct S;
-   |        - method `a` not found for this struct
+   | -------- method `a` not found for this struct
 ...
 LL |     S.a();
    |       ^ method not found in `S`
@@ -18,7 +18,7 @@ error[E0599]: no method named `b` found for struct `S` in the current scope
   --> $DIR/item-privacy.rs:68:7
    |
 LL | struct S;
-   |        - method `b` not found for this struct
+   | -------- method `b` not found for this struct
 ...
 LL |         fn b(&self) { }
    |            - the method is available for `S` here
@@ -45,7 +45,7 @@ error[E0599]: no function or associated item named `a` found for struct `S` in t
   --> $DIR/item-privacy.rs:78:8
    |
 LL | struct S;
-   |        - function or associated item `a` not found for this struct
+   | -------- function or associated item `a` not found for this struct
 ...
 LL |     S::a(&S);
    |        ^ function or associated item not found in `S`
@@ -61,7 +61,7 @@ error[E0599]: no function or associated item named `b` found for struct `S` in t
   --> $DIR/item-privacy.rs:80:8
    |
 LL | struct S;
-   |        - function or associated item `b` not found for this struct
+   | -------- function or associated item `b` not found for this struct
 ...
 LL |     S::b(&S);
    |        ^ function or associated item not found in `S`
@@ -85,7 +85,7 @@ error[E0599]: no associated item named `A` found for struct `S` in the current s
   --> $DIR/item-privacy.rs:97:8
    |
 LL | struct S;
-   |        - associated item `A` not found for this struct
+   | -------- associated item `A` not found for this struct
 ...
 LL |     S::A;
    |        ^ associated item not found in `S`
@@ -101,7 +101,7 @@ error[E0599]: no associated item named `B` found for struct `S` in the current s
   --> $DIR/item-privacy.rs:98:8
    |
 LL | struct S;
-   |        - associated item `B` not found for this struct
+   | -------- associated item `B` not found for this struct
 ...
 LL |     S::B;
    |        ^ associated item not found in `S`
diff --git a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr
index d8f2f8761ff..b29442d7b8f 100644
--- a/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr
+++ b/src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr
@@ -2,7 +2,7 @@ error[E0599]: no method named `clone` found for struct `Qux` in the current scop
   --> $DIR/explicitly-unimplemented-error-message.rs:34:9
    |
 LL | struct Qux;
-   |        --- method `clone` not found for this struct
+   | ---------- method `clone` not found for this struct
 ...
 LL |     Qux.clone();
    |         ^^^^^ method not found in `Qux`
@@ -23,7 +23,7 @@ error[E0599]: no method named `foo` found for struct `Qux` in the current scope
   --> $DIR/explicitly-unimplemented-error-message.rs:44:9
    |
 LL | struct Qux;
-   |        --- method `foo` not found for this struct
+   | ---------- method `foo` not found for this struct
 ...
 LL |     Qux.foo();
    |         ^^^ method not found in `Qux`
diff --git a/src/test/ui/try-block/try-block-opt-init.rs b/src/test/ui/try-block/try-block-opt-init.rs
index ef10b47fd13..f4f45abcc75 100644
--- a/src/test/ui/try-block/try-block-opt-init.rs
+++ b/src/test/ui/try-block/try-block-opt-init.rs
@@ -12,5 +12,5 @@ pub fn main() {
         Ok::<(), ()>(())?;
         use_val(cfg_res);
     };
-    assert_eq!(cfg_res, 5); //~ ERROR borrow of possibly-uninitialized variable: `cfg_res`
+    assert_eq!(cfg_res, 5); //~ ERROR E0381
 }
diff --git a/src/test/ui/try-block/try-block-opt-init.stderr b/src/test/ui/try-block/try-block-opt-init.stderr
index bd145fd64e7..c397385017f 100644
--- a/src/test/ui/try-block/try-block-opt-init.stderr
+++ b/src/test/ui/try-block/try-block-opt-init.stderr
@@ -1,8 +1,14 @@
-error[E0381]: borrow of possibly-uninitialized variable: `cfg_res`
+error[E0381]: used binding `cfg_res` is possibly-uninitialized
   --> $DIR/try-block-opt-init.rs:15:5
    |
+LL |     let cfg_res;
+   |         ------- binding declared here but left uninitialized
+...
+LL |         cfg_res = 5;
+   |         ----------- binding initialized here in some conditions
+...
 LL |     assert_eq!(cfg_res, 5);
-   |     ^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `cfg_res`
+   |     ^^^^^^^^^^^^^^^^^^^^^^ `cfg_res` used here but it is possibly-uninitialized
    |
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr
index 3645d11842f..828ae21b480 100644
--- a/src/test/ui/tuple/wrong_argument_ice-4.stderr
+++ b/src/test/ui/tuple/wrong_argument_ice-4.stderr
@@ -6,7 +6,7 @@ LL |       (|| {})(|| {
 LL | |
 LL | |         let b = 1;
 LL | |     });
-   | |_____- argument of type `[closure@$DIR/wrong_argument_ice-4.rs:2:13: 5:6]` unexpected
+   | |_____- argument of type `[closure@$DIR/wrong_argument_ice-4.rs:2:13: 2:15]` unexpected
    |
 note: closure defined here
   --> $DIR/wrong_argument_ice-4.rs:2:6
diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
index b456b1445e7..5fb7a9473d3 100644
--- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
+++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.rs
@@ -6,7 +6,6 @@
 mod m {
     type Foo = impl std::fmt::Debug;
     //~^ ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
-    //~| ERROR: cycle detected when computing type of `m::Foo::{opaque#0}` [E0391]
 
     pub fn foo() -> Foo {
         22_u32
diff --git a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
index 4c44875b4a5..1e9a45aac79 100644
--- a/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
+++ b/src/test/ui/type-alias-impl-trait/auto-trait-leakage3.stderr
@@ -5,10 +5,11 @@ LL |     type Foo = impl std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires type-checking `m::bar`...
-  --> $DIR/auto-trait-leakage3.rs:15:5
+  --> $DIR/auto-trait-leakage3.rs:15:9
    |
-LL |     pub fn bar() {
-   |     ^^^^^^^^^^^^
+LL |         is_send(foo());
+   |         ^^^^^^^
+   = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`...
    = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in module `m`
   --> $DIR/auto-trait-leakage3.rs:6:1
@@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m`
 LL | mod m {
    | ^^^^^
 
-error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
-  --> $DIR/auto-trait-leakage3.rs:7:16
-   |
-LL |     type Foo = impl std::fmt::Debug;
-   |                ^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires type-checking `m::bar`...
-  --> $DIR/auto-trait-leakage3.rs:15:5
-   |
-LL |     pub fn bar() {
-   |     ^^^^^^^^^^^^
-   = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in module `m`
-  --> $DIR/auto-trait-leakage3.rs:6:1
-   |
-LL | mod m {
-   | ^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.rs b/src/test/ui/type-alias-impl-trait/inference-cycle.rs
index 608572978a3..79caddf7913 100644
--- a/src/test/ui/type-alias-impl-trait/inference-cycle.rs
+++ b/src/test/ui/type-alias-impl-trait/inference-cycle.rs
@@ -4,7 +4,6 @@
 mod m {
     type Foo = impl std::fmt::Debug;
     //~^ ERROR cycle detected
-    //~| ERROR cycle detected
 
     // Cycle: error today, but it'd be nice if it eventually worked
 
diff --git a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
index 3ed86fae8a1..b9d646b927a 100644
--- a/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
+++ b/src/test/ui/type-alias-impl-trait/inference-cycle.stderr
@@ -5,10 +5,11 @@ LL |     type Foo = impl std::fmt::Debug;
    |                ^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires type-checking `m::bar`...
-  --> $DIR/inference-cycle.rs:15:5
+  --> $DIR/inference-cycle.rs:15:9
    |
-LL |     pub fn bar() {
-   |     ^^^^^^^^^^^^
+LL |         is_send(foo()); // Today: error
+   |         ^^^^^^^
+   = note: ...which requires evaluating trait selection obligation `m::Foo: core::marker::Send`...
    = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in module `m`
   --> $DIR/inference-cycle.rs:4:1
@@ -16,24 +17,6 @@ note: cycle used when checking item types in module `m`
 LL | mod m {
    | ^^^^^
 
-error[E0391]: cycle detected when computing type of `m::Foo::{opaque#0}`
-  --> $DIR/inference-cycle.rs:5:16
-   |
-LL |     type Foo = impl std::fmt::Debug;
-   |                ^^^^^^^^^^^^^^^^^^^^
-   |
-note: ...which requires type-checking `m::bar`...
-  --> $DIR/inference-cycle.rs:15:5
-   |
-LL |     pub fn bar() {
-   |     ^^^^^^^^^^^^
-   = note: ...which again requires computing type of `m::Foo::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in module `m`
-  --> $DIR/inference-cycle.rs:4:1
-   |
-LL | mod m {
-   | ^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr
index 6745b8ef69c..1b89d55711d 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-53092-2.stderr
@@ -30,7 +30,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-
 LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
    |                                         ^^^^^^^^^^^^^^^^^^^
    |
-   = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:71]` (0 bits)
+   = note: source type: `[closure@$DIR/issue-53092-2.rs:6:61: 6:68]` (0 bits)
    = note: target type: `Bug<u8, ()>` (size can vary because of [type error])
 
 error[E0277]: the trait bound `U: From<T>` is not satisfied
diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
index ed1cf1852e7..f14bf6b0f7f 100644
--- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr
@@ -10,7 +10,7 @@ note: this closure does not fulfill the lifetime requirements
   --> $DIR/issue-57611-trait-alias.rs:21:9
    |
 LL |         |x| x
-   |         ^^^^^
+   |         ^^^
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-57611-trait-alias.rs:21:9
diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
index 57fc660901c..110b8d1eea4 100644
--- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr
@@ -23,7 +23,7 @@ LL |     || -> Closure { || () }
    |                     ^^^^^ expected `()`, found closure
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/issue-63279.rs:9:21: 9:26]`
+                found closure `[closure@$DIR/issue-63279.rs:9:21: 9:23]`
 help: use parentheses to call this closure
    |
 LL |     || -> Closure { (|| ())() }
@@ -36,7 +36,7 @@ LL |     || -> Closure { || () }
    |     ^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found closure
    |
    = note: expected unit type `()`
-                found closure `[closure@$DIR/issue-63279.rs:9:5: 9:28]`
+                found closure `[closure@$DIR/issue-63279.rs:9:5: 9:18]`
 help: use parentheses to call this closure
    |
 LL |     (|| -> Closure { || () })()
diff --git a/src/test/ui/type-alias-impl-trait/issue-94429.stderr b/src/test/ui/type-alias-impl-trait/issue-94429.stderr
index 57550104087..8d7f7a07b60 100644
--- a/src/test/ui/type-alias-impl-trait/issue-94429.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-94429.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/issue-94429.rs:17:9: 19:10] as Generator>::Yield == ()`
+error[E0271]: type mismatch resolving `<[generator@$DIR/issue-94429.rs:17:9: 17:16] as Generator>::Yield == ()`
   --> $DIR/issue-94429.rs:15:26
    |
 LL |     fn run(&mut self) -> Self::Gen {
diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.rs b/src/test/ui/type-alias-impl-trait/issue-98604.rs
new file mode 100644
index 00000000000..a4fd8a82a04
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-98604.rs
@@ -0,0 +1,13 @@
+// edition:2018
+
+type AsyncFnPtr = Box<
+    dyn Fn() -> std::pin::Pin<Box<dyn std::future::Future<Output = ()>>>,
+>;
+
+async fn test() {}
+
+#[allow(unused_must_use)]
+fn main() {
+    Box::new(test) as AsyncFnPtr;
+    //~^ ERROR type mismatch
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-98604.stderr b/src/test/ui/type-alias-impl-trait/issue-98604.stderr
new file mode 100644
index 00000000000..f04d1b4d787
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-98604.stderr
@@ -0,0 +1,18 @@
+error[E0271]: type mismatch resolving `<fn() -> impl Future<Output = ()> {test} as FnOnce<()>>::Output == Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+  --> $DIR/issue-98604.rs:11:5
+   |
+LL |     Box::new(test) as AsyncFnPtr;
+   |     ^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
+   |
+note: while checking the return type of the `async fn`
+  --> $DIR/issue-98604.rs:7:17
+   |
+LL | async fn test() {}
+   |                 ^ checked the `Output` of this `async fn`, found opaque type
+   = note:   expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+           found opaque type `impl Future<Output = ()>`
+   = note: required for the cast from `fn() -> impl Future<Output = ()> {test}` to the object type `dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.rs b/src/test/ui/type-alias-impl-trait/issue-98608.rs
new file mode 100644
index 00000000000..d75762a8b62
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-98608.rs
@@ -0,0 +1,9 @@
+fn hi() -> impl Sized { std::ptr::null::<u8>() }
+
+fn main() {
+    let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
+    //~^ ERROR type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
+    let boxed = b();
+    let null = *boxed;
+    println!("{null:?}");
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-98608.stderr b/src/test/ui/type-alias-impl-trait/issue-98608.stderr
new file mode 100644
index 00000000000..8f3ec7d9d16
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-98608.stderr
@@ -0,0 +1,16 @@
+error[E0271]: type mismatch resolving `<fn() -> impl Sized {hi} as FnOnce<()>>::Output == Box<u8>`
+  --> $DIR/issue-98608.rs:4:39
+   |
+LL | fn hi() -> impl Sized { std::ptr::null::<u8>() }
+   |            ---------- the found opaque type
+...
+LL |     let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi);
+   |                                       ^^^^^^^^^^^^ expected struct `Box`, found opaque type
+   |
+   = note:   expected struct `Box<u8>`
+           found opaque type `impl Sized`
+   = note: required for the cast from `fn() -> impl Sized {hi}` to the object type `dyn Fn() -> Box<u8>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
index 91c1d031e4e..c36b95f47e8 100644
--- a/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
+++ b/src/test/ui/type-alias-impl-trait/not_well_formed.stderr
@@ -2,7 +2,7 @@ error[E0220]: associated type `Assoc` not found for `V`
   --> $DIR/not_well_formed.rs:9:29
    |
 LL | type Foo<V> = impl Trait<V::Assoc>;
-   |                             ^^^^^ associated type `Assoc` not found
+   |                             ^^^^^ there is a similarly named associated type `Assoc` in the trait `TraitWithAssoc`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.rs b/src/test/ui/type-alias-impl-trait/reveal_local.rs
index 145186baa1f..7ecb5535301 100644
--- a/src/test/ui/type-alias-impl-trait/reveal_local.rs
+++ b/src/test/ui/type-alias-impl-trait/reveal_local.rs
@@ -4,7 +4,6 @@ use std::fmt::Debug;
 
 type Foo = impl Debug;
 //~^ ERROR cycle detected
-//~| ERROR cycle detected
 
 fn is_send<T: Send>() { }
 
diff --git a/src/test/ui/type-alias-impl-trait/reveal_local.stderr b/src/test/ui/type-alias-impl-trait/reveal_local.stderr
index 5d48dd5b2bf..27fded33329 100644
--- a/src/test/ui/type-alias-impl-trait/reveal_local.stderr
+++ b/src/test/ui/type-alias-impl-trait/reveal_local.stderr
@@ -5,10 +5,11 @@ LL | type Foo = impl Debug;
    |            ^^^^^^^^^^
    |
 note: ...which requires type-checking `not_good`...
-  --> $DIR/reveal_local.rs:11:1
+  --> $DIR/reveal_local.rs:13:5
    |
-LL | fn not_good() {
-   | ^^^^^^^^^^^^^
+LL |     is_send::<Foo>();
+   |     ^^^^^^^^^^^^^^
+   = note: ...which requires evaluating trait selection obligation `Foo: core::marker::Send`...
    = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
 note: cycle used when checking item types in top-level module
   --> $DIR/reveal_local.rs:1:1
@@ -22,30 +23,6 @@ LL | |
 LL | | fn main() {}
    | |____________^
 
-error[E0391]: cycle detected when computing type of `Foo::{opaque#0}`
-  --> $DIR/reveal_local.rs:5:12
-   |
-LL | type Foo = impl Debug;
-   |            ^^^^^^^^^^
-   |
-note: ...which requires type-checking `not_gooder`...
-  --> $DIR/reveal_local.rs:17:1
-   |
-LL | fn not_gooder() {
-   | ^^^^^^^^^^^^^^^
-   = note: ...which again requires computing type of `Foo::{opaque#0}`, completing the cycle
-note: cycle used when checking item types in top-level module
-  --> $DIR/reveal_local.rs:1:1
-   |
-LL | / #![feature(type_alias_impl_trait)]
-LL | |
-LL | | use std::fmt::Debug;
-LL | |
-...  |
-LL | |
-LL | | fn main() {}
-   | |____________^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/type/type-check/issue-40294.stderr b/src/test/ui/type/type-check/issue-40294.stderr
index 75feb5698eb..d15fd23418b 100644
--- a/src/test/ui/type/type-check/issue-40294.stderr
+++ b/src/test/ui/type/type-check/issue-40294.stderr
@@ -4,7 +4,13 @@ error[E0283]: type annotations needed: cannot satisfy `&'a T: Foo`
 LL |     where &'a T : Foo,
    |                   ^^^
    |
-   = note: cannot satisfy `&'a T: Foo`
+note: multiple `impl`s or `where` clauses satisfying `&'a T: Foo` found
+  --> $DIR/issue-40294.rs:6:19
+   |
+LL |     where &'a T : Foo,
+   |                   ^^^
+LL |           &'b T : Foo
+   |                   ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs
index c1f3acbecf9..ce6fdf81121 100644
--- a/src/test/ui/type_length_limit.rs
+++ b/src/test/ui/type_length_limit.rs
@@ -1,8 +1,10 @@
 // build-fail
 // error-pattern: reached the type-length limit while instantiating
+// compile-flags: -Copt-level=0
 // normalize-stderr-test: ".nll/" -> "/"
 
 // Test that the type length limit can be changed.
+// The exact type depends on optimizations, so disable them.
 
 #![allow(dead_code)]
 #![type_length_limit="4"]
diff --git a/src/test/ui/typeck/issue-91334.stderr b/src/test/ui/typeck/issue-91334.stderr
index 633c7b11aa2..8508f7a38e2 100644
--- a/src/test/ui/typeck/issue-91334.stderr
+++ b/src/test/ui/typeck/issue-91334.stderr
@@ -43,7 +43,7 @@ LL | fn f(){||yield(((){),
    |       help: a return type might be missing here: `-> _`
    |
    = note: expected unit type `()`
-              found generator `[generator@$DIR/issue-91334.rs:10:8: 10:23]`
+              found generator `[generator@$DIR/issue-91334.rs:10:8: 10:10]`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/typeck/return_type_containing_closure.stderr b/src/test/ui/typeck/return_type_containing_closure.stderr
index ae72b1477c8..101aee39559 100644
--- a/src/test/ui/typeck/return_type_containing_closure.stderr
+++ b/src/test/ui/typeck/return_type_containing_closure.stderr
@@ -5,7 +5,7 @@ LL |     vec!['a'].iter().map(|c| c)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Map`
    |
    = note: expected unit type `()`
-                 found struct `Map<std::slice::Iter<'_, char>, [closure@$DIR/return_type_containing_closure.rs:3:26: 3:31]>`
+                 found struct `Map<std::slice::Iter<'_, char>, [closure@$DIR/return_type_containing_closure.rs:3:26: 3:29]>`
 help: consider using a semicolon here
    |
 LL |     vec!['a'].iter().map(|c| c);
diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
index 482d3e44fe4..bfa3061de08 100644
--- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr
@@ -4,9 +4,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn(|| drop(x));
-   |                       --------^-
-   |                       |       |
-   |                       |       move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       --      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       |
    |                       captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
@@ -15,9 +14,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn_mut(|| drop(x));
-   |                           --------^-
-   |                           |       |
-   |                           |       move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           --      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           |
    |                           captured by this `FnMut` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
@@ -26,9 +24,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn(move || drop(x));
-   |                       -------------^-
-   |                       |            |
-   |                       |            move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       -------      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                       |
    |                       captured by this `Fn` closure
 
 error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
@@ -37,9 +34,8 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure
 LL |         let x = Box::new(0);
    |             - captured outer variable
 LL |         let f = to_fn_mut(move || drop(x));
-   |                           -------------^-
-   |                           |            |
-   |                           |            move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           -------      ^ move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+   |                           |
    |                           captured by this `FnMut` closure
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
index 68ec8d2ba82..85ff49d61a3 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-fn-once-move-from-projection.stderr
@@ -2,9 +2,8 @@ error[E0525]: expected a closure that implements the `Fn` trait, but this closur
   --> $DIR/unboxed-closures-infer-fn-once-move-from-projection.rs:14:13
    |
 LL |     let c = || drop(y.0);
-   |             ^^^^^^^^---^
-   |             |       |
-   |             |       closure is `FnOnce` because it moves the variable `y` out of its environment
+   |             ^^      --- closure is `FnOnce` because it moves the variable `y` out of its environment
+   |             |
    |             this closure implements `FnOnce`, not `Fn`
 LL |     foo(c);
    |     --- the requirement to implement `Fn` derives from here
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
index 48ec620d92e..d6e74b5b8b9 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutate-upvar.stderr
@@ -28,17 +28,15 @@ LL |         n += 1;
 error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure
   --> $DIR/unboxed-closures-mutate-upvar.rs:53:9
    |
-LL |   fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-   |                          - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+   |                        - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       let mut f = to_fn(move || {
-   |  _________________-----_-
-   | |                 |
-   | |                 expects `Fn` instead of `FnMut`
-LL | |         n += 1;
-   | |         ^^^^^^ cannot assign
-LL | |     });
-   | |_____- in this closure
+LL |     let mut f = to_fn(move || {
+   |                 ----- ------- in this closure
+   |                 |
+   |                 expects `Fn` instead of `FnMut`
+LL |         n += 1;
+   |         ^^^^^^ cannot assign
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
index 80e84fb7cad..7d15cd0c882 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-mutated-upvar-from-fn-closure.stderr
@@ -1,18 +1,15 @@
 error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure
   --> $DIR/unboxed-closures-mutated-upvar-from-fn-closure.rs:11:9
    |
-LL |   fn call<F>(f: F) where F : Fn() {
-   |                 - change this to accept `FnMut` instead of `Fn`
+LL | fn call<F>(f: F) where F : Fn() {
+   |               - change this to accept `FnMut` instead of `Fn`
 ...
-LL |       call(|| {
-   |  _____----_-
-   | |     |
-   | |     expects `Fn` instead of `FnMut`
-LL | |         counter += 1;
-   | |         ^^^^^^^^^^^^ cannot assign
-LL | |
-LL | |     });
-   | |_____- in this closure
+LL |     call(|| {
+   |     ---- -- in this closure
+   |     |
+   |     expects `Fn` instead of `FnMut`
+LL |         counter += 1;
+   |         ^^^^^^^^^^^^ cannot assign
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
index e9883903674..4f89afa320d 100644
--- a/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
+++ b/src/test/ui/unboxed-closures/unboxed-closures-static-call-wrong-trait.stderr
@@ -1,8 +1,8 @@
-error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]` in the current scope
+error[E0599]: no method named `call` found for closure `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]` in the current scope
   --> $DIR/unboxed-closures-static-call-wrong-trait.rs:7:10
    |
 LL |     mut_.call((0, ));
-   |     ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:31]`
+   |     ---- ^^^^ method not found in `[closure@$DIR/unboxed-closures-static-call-wrong-trait.rs:6:26: 6:29]`
    |     |
    |     this is a function, perhaps you wish to call it
 
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
index b37ec2696de..2764bb563d3 100644
--- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
+++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
@@ -25,5 +25,5 @@ fn main() {
     widget::Widget::new();
     // Error. Widget type is not known to be uninhabited here,
     // so the following code is considered reachable.
-    *y = 2; //~ ERROR use of possibly-uninitialized variable
+    *y = 2; //~ ERROR E0381
 }
diff --git a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
index fb195341168..95c209f47c9 100644
--- a/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
+++ b/src/test/ui/uninhabited/privately-uninhabited-mir-call.stderr
@@ -1,8 +1,11 @@
-error[E0381]: use of possibly-uninitialized variable: `y`
+error[E0381]: used binding `y` isn't initialized
   --> $DIR/privately-uninhabited-mir-call.rs:28:5
    |
+LL |     let y: &mut u32;
+   |         - binding declared here but left uninitialized
+...
 LL |     *y = 2;
-   |     ^^^^^^ use of possibly-uninitialized `y`
+   |     ^^^^^^ `y` used here but it isn't initialized
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
index c277d5b761d..a4d692f8497 100644
--- a/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
+++ b/src/test/ui/union/union-derive-clone.mirunsafeck.stderr
@@ -3,8 +3,8 @@ error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its tra
    |
 LL | union U5<T> {
    | -----------
-   | |     |
-   | |     method `clone` not found for this union
+   | |
+   | method `clone` not found for this union
    | doesn't satisfy `U5<CloneNoCopy>: Clone`
 ...
 LL | struct CloneNoCopy;
diff --git a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
index c277d5b761d..a4d692f8497 100644
--- a/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
+++ b/src/test/ui/union/union-derive-clone.thirunsafeck.stderr
@@ -3,8 +3,8 @@ error[E0599]: the method `clone` exists for union `U5<CloneNoCopy>`, but its tra
    |
 LL | union U5<T> {
    | -----------
-   | |     |
-   | |     method `clone` not found for this union
+   | |
+   | method `clone` not found for this union
    | doesn't satisfy `U5<CloneNoCopy>: Clone`
 ...
 LL | struct CloneNoCopy;
diff --git a/src/test/ui/unsized/box-instead-of-dyn-fn.stderr b/src/test/ui/unsized/box-instead-of-dyn-fn.stderr
index b9d51d21e9a..c96c59afc5a 100644
--- a/src/test/ui/unsized/box-instead-of-dyn-fn.stderr
+++ b/src/test/ui/unsized/box-instead-of-dyn-fn.stderr
@@ -14,8 +14,8 @@ LL | |
 LL | |     }
    | |_____- `if` and `else` have incompatible types
    |
-   = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:32]`
-               found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:43]>`
+   = note: expected closure `[closure@$DIR/box-instead-of-dyn-fn.rs:8:9: 8:16]`
+               found struct `Box<[closure@$DIR/box-instead-of-dyn-fn.rs:10:18: 10:25]>`
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/box-instead-of-dyn-fn.rs:5:56
diff --git a/src/test/ui/unsized/issue-91801.stderr b/src/test/ui/unsized/issue-91801.stderr
index e8545149586..8795aa1687f 100644
--- a/src/test/ui/unsized/issue-91801.stderr
+++ b/src/test/ui/unsized/issue-91801.stderr
@@ -5,7 +5,7 @@ LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) ->
    |                                                                             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
-help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 12:6]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a`
+help: use `impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a` as the return type, as all return paths are of type `Box<[closure@$DIR/issue-91801.rs:10:21: 10:70]>`, which implements `Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a`
    |
 LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Fn(&'a Something) -> Result<(), ()> + Send + Sync + 'a {
    |                                                                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
index f02a368d4e0..ba72f74f20c 100644
--- a/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
+++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.rs
@@ -1,6 +1,10 @@
 // Test that the "C-unwind" ABI is feature-gated, and cannot be used when the
 // `c_unwind` feature gate is not used.
 
+#![allow(ffi_unwind_calls)]
+//~^ WARNING unknown lint: `ffi_unwind_calls`
+//~| WARNING unknown lint: `ffi_unwind_calls`
+
 extern "C-unwind" fn f() {}
 //~^ ERROR C-unwind ABI is experimental and subject to change [E0658]
 
diff --git a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
index f4c785a235f..a67f46cd2e3 100644
--- a/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
+++ b/src/test/ui/unwind-abis/feature-gate-c-unwind.stderr
@@ -1,5 +1,16 @@
+warning: unknown lint: `ffi_unwind_calls`
+  --> $DIR/feature-gate-c-unwind.rs:4:1
+   |
+LL | #![allow(ffi_unwind_calls)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `ffi_unwind_calls` lint is unstable
+   = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
+   = help: add `#![feature(c_unwind)]` to the crate attributes to enable
+
 error[E0658]: C-unwind ABI is experimental and subject to change
-  --> $DIR/feature-gate-c-unwind.rs:4:8
+  --> $DIR/feature-gate-c-unwind.rs:8:8
    |
 LL | extern "C-unwind" fn f() {}
    |        ^^^^^^^^^^
@@ -7,6 +18,16 @@ LL | extern "C-unwind" fn f() {}
    = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
    = help: add `#![feature(c_unwind)]` to the crate attributes to enable
 
-error: aborting due to previous error
+warning: unknown lint: `ffi_unwind_calls`
+  --> $DIR/feature-gate-c-unwind.rs:4:1
+   |
+LL | #![allow(ffi_unwind_calls)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `ffi_unwind_calls` lint is unstable
+   = note: see issue #74990 <https://github.com/rust-lang/rust/issues/74990> for more information
+   = help: add `#![feature(c_unwind)]` to the crate attributes to enable
+
+error: aborting due to previous error; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs
new file mode 100644
index 00000000000..dadf4b12187
--- /dev/null
+++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.rs
@@ -0,0 +1,27 @@
+// build-pass
+// needs-unwind
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(c_unwind)]
+#![warn(ffi_unwind_calls)]
+
+mod foo {
+    #[no_mangle]
+    pub extern "C-unwind" fn foo() {}
+}
+
+extern "C-unwind" {
+    fn foo();
+}
+
+fn main() {
+    // Call to Rust function is fine.
+    foo::foo();
+    // Call to foreign function should warn.
+    unsafe { foo(); }
+    //~^ WARNING call to foreign function with FFI-unwind ABI
+    let ptr: extern "C-unwind" fn() = foo::foo;
+    // Call to function pointer should also warn.
+    ptr();
+    //~^ WARNING call to function pointer with FFI-unwind ABI
+}
diff --git a/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr
new file mode 100644
index 00000000000..ed41cb74623
--- /dev/null
+++ b/src/test/ui/unwind-abis/ffi-unwind-calls-lint.stderr
@@ -0,0 +1,20 @@
+warning: call to foreign function with FFI-unwind ABI
+  --> $DIR/ffi-unwind-calls-lint.rs:21:14
+   |
+LL |     unsafe { foo(); }
+   |              ^^^^^ call to foreign function with FFI-unwind ABI
+   |
+note: the lint level is defined here
+  --> $DIR/ffi-unwind-calls-lint.rs:6:9
+   |
+LL | #![warn(ffi_unwind_calls)]
+   |         ^^^^^^^^^^^^^^^^
+
+warning: call to function pointer with FFI-unwind ABI
+  --> $DIR/ffi-unwind-calls-lint.rs:25:5
+   |
+LL |     ptr();
+   |     ^^^^^ call to function pointer with FFI-unwind ABI
+
+warning: 2 warnings emitted
+
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject dbff32b27893b899ae2397f3d56d1be111041d5
+Subproject b1dd22e668af5279e13a071ad4b17435bd6bfa4
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 59dcc1ebf19..0f4a2f79ac5 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -15,7 +15,7 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span, Symbol};
 use rustc_trait_selection::infer::InferCtxtExt;
diff --git a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
index c6c7b959d4f..4f49bb879f5 100644
--- a/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
+++ b/src/tools/clippy/clippy_lints/src/duplicate_mod.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Crate, Inline, Item, ItemKind, ModKind};
 use rustc_errors::MultiSpan;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext, Level};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{FileName, Span};
 use std::collections::BTreeMap;
@@ -49,6 +49,7 @@ declare_clippy_lint! {
 struct Modules {
     local_path: PathBuf,
     spans: Vec<Span>,
+    lint_levels: Vec<Level>,
 }
 
 #[derive(Default)]
@@ -70,13 +71,30 @@ impl EarlyLintPass for DuplicateMod {
             let modules = self.modules.entry(absolute_path).or_insert(Modules {
                 local_path,
                 spans: Vec::new(),
+                lint_levels: Vec::new(),
             });
             modules.spans.push(item.span_with_attributes());
+            modules.lint_levels.push(cx.get_lint_level(DUPLICATE_MOD));
         }
     }
 
     fn check_crate_post(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
-        for Modules { local_path, spans } in self.modules.values() {
+        for Modules { local_path, spans, lint_levels } in self.modules.values() {
+            if spans.len() < 2 {
+                continue;
+            }
+
+            // At this point the lint would be emitted
+            assert_eq!(spans.len(), lint_levels.len());
+            let spans: Vec<_> = spans.into_iter().zip(lint_levels).filter_map(|(span, lvl)|{
+                if let Some(id) = lvl.get_expectation_id() {
+                    cx.fulfill_expectation(id);
+                }
+
+                (!matches!(lvl, Level::Allow | Level::Expect(_))).then_some(*span)
+            })
+            .collect();
+
             if spans.len() < 2 {
                 continue;
             }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 7a65b849a66..1ac7bfba06b 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_hir;
 use clippy_utils::ty::contains_ty;
 use rustc_hir::intravisit;
-use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node};
+use rustc_hir::{self, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
@@ -132,7 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
 // TODO: Replace with Map::is_argument(..) when it's fixed
 fn is_argument(map: rustc_middle::hir::map::Map<'_>, id: HirId) -> bool {
     match map.find(id) {
-        Some(Node::Binding(_)) => (),
+        Some(Node::Pat(Pat {
+            kind: PatKind::Binding(..),
+            ..
+        })) => (),
         _ => return false,
     }
 
@@ -144,15 +147,6 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
         if cmt.place.projections.is_empty() {
             if let PlaceBase::Local(lid) = cmt.place.base {
                 self.set.remove(&lid);
-                let map = &self.cx.tcx.hir();
-                if let Some(Node::Binding(_)) = map.find(cmt.hir_id) {
-                    if self.set.contains(&lid) {
-                        // let y = x where x is known
-                        // remove x, insert y
-                        self.set.insert(cmt.hir_id);
-                        self.set.remove(&lid);
-                    }
-                }
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index a5a763c37d1..42fac550ec6 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::binding::BindingMode;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
+use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
 
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index f7a92bc0795..453471c8cdd 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -94,7 +94,7 @@ impl ExcessiveBools {
 
     fn check_fn_sig(&self, cx: &EarlyContext<'_>, fn_sig: &FnSig, span: Span) {
         match fn_sig.header.ext {
-            Extern::Implicit | Extern::Explicit(_) => return,
+            Extern::Implicit(_) | Extern::Explicit(_, _) => return,
             Extern::None => (),
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 12d636cf410..5bf4313b41a 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -125,7 +125,7 @@ fn look_in_block<'tcx, 'hir>(cx: &LateContext<'tcx>, kind: &'tcx ExprKind<'hir>)
         // Find id of the local that expr_end_of_block resolves to
         if let ExprKind::Path(QPath::Resolved(None, expr_path)) = expr_end_of_block.kind;
         if let Res::Local(expr_res) = expr_path.res;
-        if let Some(Node::Binding(res_pat)) = cx.tcx.hir().find(expr_res);
+        if let Some(Node::Pat(res_pat)) = cx.tcx.hir().find(expr_res);
 
         // Find id of the local we found in the block
         if let PatKind::Binding(BindingAnnotation::Unannotated, local_hir_id, _ident, None) = local.pat.kind;
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index d20df830455..aedf3810b23 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -43,7 +43,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
 fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
     if_chain! {
         if let Some(hir_id) = path_to_local(bound);
-        if let Node::Binding(pat) = cx.tcx.hir().get(hir_id);
+        if let Node::Pat(pat) = cx.tcx.hir().get(hir_id);
         if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind;
         then {
             return Some(hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index e048d744fc3..1439f1f4c75 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -63,7 +63,7 @@ pub(super) fn check<'tcx>(
                         Res::Local(hir_id) => {
                             let node = cx.tcx.hir().get(hir_id);
                             if_chain! {
-                                if let Node::Binding(pat) = node;
+                                if let Node::Pat(pat) = node;
                                 if let PatKind::Binding(bind_ann, ..) = pat.kind;
                                 if !matches!(bind_ann, BindingAnnotation::RefMut | BindingAnnotation::Mutable);
                                 let parent_node = cx.tcx.hir().get_parent_node(hir_id);
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index b5698965fc3..2ce9d0e77c1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -71,8 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && let Some(const3) = check_for_unsigned_int_constant(cx, right)
             // Also ensures the const is nonzero since zero can't be a divisor
             && const1 == const2 && const2 == const3
-            && let Some(hir_id) = path_to_local(expr3)
-            && let Some(Node::Binding(_)) = cx.tcx.hir().find(hir_id) {
+            && let Some(hir_id) = path_to_local(expr3) {
                 // Apply only to params or locals with annotated types
                 match cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
                     Some(Node::Param(..)) => (),
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
index f5410c7fd7f..43e9451f7d3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_skip_next.rs
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
             |diag| {
                 if_chain! {
                     if let Some(id) = path_to_local(recv);
-                    if let Node::Binding(pat) = cx.tcx.hir().get(id);
+                    if let Node::Pat(pat) = cx.tcx.hir().get(id);
                     if let PatKind::Binding(ann, _, _, _)  = pat.kind;
                     if ann != BindingAnnotation::Mutable;
                     then {
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index df2430ced6b..be7df08d89f 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -301,7 +301,7 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::MacroKind;
     if expr.span.from_expansion() {
         let data = expr.span.ctxt().outer_expn_data();
-        matches!(data.kind, ExpnKind::Macro(MacroKind::Attr, _))
+        matches!(data.kind, ExpnKind::Macro(MacroKind::Attr|MacroKind::Derive, _))
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 7e2531c7ca5..4db103bbc13 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::trait_ref_of_method;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::TypeVisitable;
 use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 8b273aca7d0..0cbef1c95fe 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -13,7 +13,7 @@ use rustc_hir::{HirIdMap, HirIdSet};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, TypeFoldable};
+use rustc_middle::ty::{self, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Span};
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index 3b11cbc3760..eddca604575 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -14,7 +14,7 @@ use rustc_middle::mir::{
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
     Mutability,
 };
-use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
+use rustc_middle::ty::{self, visit::TypeVisitor, Ty};
 use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
@@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 // `arg` is a reference as it is `.deref()`ed in the previous block.
                 // Look into the predecessor block and find out the source of deref.
 
-                let ps = &mir.predecessors()[bb];
+                let ps = &mir.basic_blocks.predecessors()[bb];
                 if ps.len() != 1 {
                     continue;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 3ed5d5c6950..5eb03275b8e 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -5,7 +5,7 @@ use clippy_utils::{meets_msrv, msrvs, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, GenericArg, Mutability, Path, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
 use rustc_semver::RustcVersion;
 
 /// Checks for `transmute_ptr_to_ref` lint.
diff --git a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
index 8ea985a8984..8122cd716e0 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
@@ -4,7 +4,7 @@ use clippy_utils::sugg;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TypeVisitable};
 
 /// Checks for `useless_transmute` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
index c632f822544..b2f536ca781 100644
--- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{self as hir, def_id::DefId, GenericArg, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::TypeVisitable;
 use rustc_span::symbol::sym;
 use rustc_typeck::hir_ty_to_ty;
 
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 27678c8ba3c..cf509455aad 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, Ty, TypeFoldable, TypeSuperFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TypeVisitable, TypeSuperVisitable, TypeVisitor};
 
 use super::LET_UNIT_VALUE;
 
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 70b0560e676..8dc43c0e294 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
 use rustc_hir::{self as hir, HirId, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf as _;
-use rustc_middle::ty::{Adt, Ty, TypeFoldable};
+use rustc_middle::ty::{Adt, Ty, TypeVisitable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 use rustc_typeck::hir_ty_to_ty;
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 6487199172e..177e754ee09 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -600,8 +600,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
 pub fn eq_ext(l: &Extern, r: &Extern) -> bool {
     use Extern::*;
     match (l, r) {
-        (None, None) | (Implicit, Implicit) => true,
-        (Explicit(l), Explicit(r)) => eq_str_lit(l, r),
+        (None, None) | (Implicit(_), Implicit(_)) => true,
+        (Explicit(l,_), Explicit(r,_)) => eq_str_lit(l, r),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9fa28e137f9..1b32f0aaeb8 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -93,7 +93,7 @@ use rustc_middle::ty::fast_reject::SimplifiedTypeGen::{
     ArraySimplifiedType, BoolSimplifiedType, CharSimplifiedType, FloatSimplifiedType, IntSimplifiedType,
     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 };
-use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
+use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitable, UpvarCapture};
 use rustc_middle::ty::{FloatTy, IntTy, UintTy};
 use rustc_semver::RustcVersion;
 use rustc_session::Session;
@@ -183,7 +183,7 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr
 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
     let hir = cx.tcx.hir();
     if_chain! {
-        if let Some(Node::Binding(pat)) = hir.find(hir_id);
+        if let Some(Node::Pat(pat)) = hir.find(hir_id);
         if matches!(pat.kind, PatKind::Binding(BindingAnnotation::Unannotated, ..));
         let parent = hir.get_parent_node(hir_id);
         if let Some(Node::Local(local)) = hir.find(parent);
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 6ca36eed4e6..a426fa1b0ff 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -15,7 +15,7 @@ use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{
     self, AdtDef, Binder, BoundRegion, DefIdTree, FnSig, IntTy, ParamEnv, Predicate, PredicateKind, ProjectionTy,
-    Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitor, UintTy, VariantDef, VariantDiscr,
+    Region, RegionKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -765,7 +765,7 @@ pub fn for_each_top_level_late_bound_region<B>(
                 ControlFlow::Continue(())
             }
         }
-        fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
+        fn visit_binder<T: TypeVisitable<'tcx>>(&mut self, t: &Binder<'tcx, T>) -> ControlFlow<Self::BreakTy> {
             self.index += 1;
             let res = t.super_visit_with(self);
             self.index -= 1;
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/d.rs
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
index 79b343da247..99ca538b6e4 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.rs
@@ -1,3 +1,5 @@
+#[feature(lint_reasons)]
+
 mod a;
 
 mod b;
@@ -13,4 +15,15 @@ mod c3;
 mod from_other_module;
 mod other_module;
 
+mod d;
+#[path = "d.rs"]
+mod d2;
+#[path = "d.rs"]
+#[expect(clippy::duplicate_mod)]
+mod d3;
+#[path = "d.rs"]
+#[allow(clippy::duplicate_mod)]
+mod d4;
+
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
index 00d7739c8a2..61df1ad5d50 100644
--- a/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
+++ b/src/tools/clippy/tests/ui-cargo/duplicate_mod/fail/src/main.stderr
@@ -1,5 +1,5 @@
 error: file is loaded as a module multiple times: `$DIR/b.rs`
-  --> $DIR/main.rs:3:1
+  --> $DIR/main.rs:5:1
    |
 LL |   mod b;
    |   ^^^^^^ first loaded here
@@ -11,7 +11,7 @@ LL | | mod b2;
    = help: replace all but one `mod` item with `use` items
 
 error: file is loaded as a module multiple times: `$DIR/c.rs`
-  --> $DIR/main.rs:7:1
+  --> $DIR/main.rs:9:1
    |
 LL |   mod c;
    |   ^^^^^^ first loaded here
@@ -25,7 +25,7 @@ LL | | mod c3;
    = help: replace all but one `mod` item with `use` items
 
 error: file is loaded as a module multiple times: `$DIR/from_other_module.rs`
-  --> $DIR/main.rs:13:1
+  --> $DIR/main.rs:15:1
    |
 LL |   mod from_other_module;
    |   ^^^^^^^^^^^^^^^^^^^^^^ first loaded here
@@ -38,5 +38,16 @@ LL | | mod m;
    |
    = help: replace all but one `mod` item with `use` items
 
-error: aborting due to 3 previous errors
+error: file is loaded as a module multiple times: `$DIR/b.rs`
+  --> $DIR/main.rs:18:1
+   |
+LL |   mod d;
+   |   ^^^^^^ first loaded here
+LL | / #[path = "d.rs"]
+LL | | mod d2;
+   | |_______^ loaded again here
+   |
+   = help: replace all but one `mod` item with `use` items
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr
index 77a3c2ba4ad..8da2965c635 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6251.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6251.stderr
@@ -33,7 +33,7 @@ LL | fn bug<T>() -> impl Iterator<Item = [(); { |x: [u8]| x }]> {
    |                                            ^^^^^^^^^^^ expected `usize`, found closure
    |
    = note: expected type `usize`
-           found closure `[closure@$DIR/ice-6251.rs:4:44: 4:55]`
+           found closure `[closure@$DIR/ice-6251.rs:4:44: 4:53]`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index a6a767483ed..a1e37e7317b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -28,7 +28,7 @@ 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
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
 
 error: constant expression depends on a generic parameter
   --> $DIR/ice-6252.rs:13:9
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs
index 21d66d5df79..d20977d55d2 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs
@@ -44,6 +44,12 @@ fn in_struct_field() {
     s._underscore_field += 1;
 }
 
+/// Tests that we do not lint if the struct field is used in code created with derive.
+#[derive(Clone, Debug)]
+pub struct UnderscoreInStruct {
+    _foo: u32,
+}
+
 /// Tests that we do not lint if the underscore is not a prefix
 fn non_prefix_underscore(some_foo: u32) -> u32 {
     some_foo + 1
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
index 790b849210c..61a9161d212 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr
@@ -31,7 +31,7 @@ LL |     s._underscore_field += 1;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
-  --> $DIR/used_underscore_binding.rs:99:16
+  --> $DIR/used_underscore_binding.rs:105:16
    |
 LL |         uses_i(_i);
    |                ^^
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index bdf26d040ad..be81ff881f3 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -269,6 +269,10 @@ pub struct Config {
     /// Flags to pass to the compiler when building for the target
     pub target_rustcflags: Option<String>,
 
+    /// Whether tests should be optimized by default. Individual test-suites and test files may
+    /// override this setting.
+    pub optimize_tests: bool,
+
     /// What panic strategy the target is built with.  Unwind supports Abort, but
     /// not vice versa.
     pub target_panic: PanicStrategy,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 31e979a574b..7cf4a88c470 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -244,6 +244,7 @@ impl TestProps {
 
         // copy over select properties to the aux build:
         props.incremental_dir = self.incremental_dir.clone();
+        props.ignore_pass = true;
         props.load_from(testfile, cfg, config);
 
         props
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index 4e8e5afd4bb..a8a151ca114 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -102,6 +102,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS")
         .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS")
+        .optflag("", "optimize-tests", "run tests with optimizations enabled")
         .optopt("", "target-panic", "what panic strategy the target supports", "unwind | abort")
         .optflag("", "verbose", "run tests verbosely, showing all output")
         .optflag(
@@ -253,6 +254,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         runtool: matches.opt_str("runtool"),
         host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
         target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
+        optimize_tests: matches.opt_present("optimize-tests"),
         target_panic: match matches.opt_str("target-panic").as_deref() {
             Some("unwind") | None => PanicStrategy::Unwind,
             Some("abort") => PanicStrategy::Abort,
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 160b9785d97..dd9e2a6687e 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1862,6 +1862,31 @@ impl<'test> TestCx<'test> {
             }
         }
 
+        if self.config.optimize_tests && !is_rustdoc {
+            match self.config.mode {
+                Ui => {
+                    // If optimize-tests is true we still only want to optimize tests that actually get
+                    // executed and that don't specify their own optimization levels.
+                    // Note: aux libs don't have a pass-mode, so they won't get optimized
+                    // unless compile-flags are set in the aux file.
+                    if self.config.optimize_tests
+                        && self.props.pass_mode(&self.config) == Some(PassMode::Run)
+                        && !self
+                            .props
+                            .compile_flags
+                            .iter()
+                            .any(|arg| arg == "-O" || arg.contains("opt-level"))
+                    {
+                        rustc.arg("-O");
+                    }
+                }
+                DebugInfo => { /* debuginfo tests must be unoptimized */ }
+                _ => {
+                    rustc.arg("-O");
+                }
+            }
+        }
+
         match self.config.mode {
             Incremental => {
                 // If we are extracting and matching errors in the new
@@ -3245,7 +3270,8 @@ impl<'test> TestCx<'test> {
 
             if !self.props.error_patterns.is_empty() {
                 // "// error-pattern" comments
-                self.check_error_patterns(&proc_res.stderr, &proc_res, pm);
+                let output_to_check = self.get_output(&proc_res);
+                self.check_error_patterns(&output_to_check, &proc_res, pm);
             }
         }
 
@@ -3266,7 +3292,8 @@ impl<'test> TestCx<'test> {
 
             if check_patterns {
                 // "// error-pattern" comments
-                self.check_error_patterns(&proc_res.stderr, &proc_res, pm);
+                let output_to_check = self.get_output(&proc_res);
+                self.check_error_patterns(&output_to_check, &proc_res, pm);
             }
 
             if check_annotations {
diff --git a/src/tools/miri b/src/tools/miri
-Subproject ff62c3ac98eb85816190afa1c1ec5d0ad2e4423
+Subproject cde87d18239b8d9afa9c6bf1051bf5573dbf326
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject b74e96f509baf0be70281c55f14cb18fefbc6b2
+Subproject 75b22326dad1914c22484ab6672de5cae94f745
diff --git a/src/tools/rust-installer b/src/tools/rust-installer
-Subproject 5254dbfd25d5284728ab624dca1969d61427a0d
+Subproject 300b5ec61ef38855a07e6bb4955a37aa1c414c0
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index f074eb941dc..bd08e0ede0b 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0"
 edition = "2021"
 
 [dependencies]
-clap = "2.25.0"
+clap = "3.1.1"
 env_logger = "0.7.1"
 
 [dependencies.mdbook]
diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs
index 63d84ae9732..3c7dc0183d7 100644
--- a/src/tools/rustbook/src/main.rs
+++ b/src/tools/rustbook/src/main.rs
@@ -3,54 +3,57 @@ use clap::crate_version;
 use std::env;
 use std::path::{Path, PathBuf};
 
-use clap::{App, AppSettings, ArgMatches, SubCommand};
+use clap::{arg, ArgMatches, Command};
 
 use mdbook::errors::Result as Result3;
 use mdbook::MDBook;
 
 fn main() {
+    let crate_version = format!("v{}", crate_version!());
     env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
-    let d_message = "-d, --dest-dir=[dest-dir]
-'The output directory for your book{n}(Defaults to ./book when omitted)'";
-    let dir_message = "[dir]
-'A directory for your book{n}(Defaults to Current Directory when omitted)'";
+    let d_arg = arg!(-d --"dest-dir" <DEST_DIR>
+"The output directory for your book\n(Defaults to ./book when omitted)")
+    .required(false);
+    let dir_arg = arg!([dir]
+"A directory for your book\n(Defaults to Current Directory when omitted)");
 
-    let matches = App::new("rustbook")
+    let matches = Command::new("rustbook")
         .about("Build a book with mdBook")
         .author("Steve Klabnik <steve@steveklabnik.com>")
-        .version(&*format!("v{}", crate_version!()))
-        .setting(AppSettings::SubcommandRequired)
+        .version(&*crate_version)
+        .subcommand_required(true)
+        .arg_required_else_help(true)
         .subcommand(
-            SubCommand::with_name("build")
+            Command::new("build")
                 .about("Build the book from the markdown files")
-                .arg_from_usage(d_message)
-                .arg_from_usage(dir_message),
+                .arg(d_arg)
+                .arg(&dir_arg),
         )
         .subcommand(
-            SubCommand::with_name("test")
+            Command::new("test")
                 .about("Tests that a book's Rust code samples compile")
-                .arg_from_usage(dir_message),
+                .arg(dir_arg),
         )
         .get_matches();
 
     // Check which subcomamnd the user ran...
     match matches.subcommand() {
-        ("build", Some(sub_matches)) => {
+        Some(("build", sub_matches)) => {
             if let Err(e) = build(sub_matches) {
                 handle_error(e);
             }
         }
-        ("test", Some(sub_matches)) => {
+        Some(("test", sub_matches)) => {
             if let Err(e) = test(sub_matches) {
                 handle_error(e);
             }
         }
-        (_, _) => unreachable!(),
+        _ => unreachable!(),
     };
 }
 
 // Build command implementation
-pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
+pub fn build(args: &ArgMatches) -> Result3<()> {
     let book_dir = get_book_dir(args);
     let mut book = load_book(&book_dir)?;
 
@@ -66,13 +69,13 @@ pub fn build(args: &ArgMatches<'_>) -> Result3<()> {
     Ok(())
 }
 
-fn test(args: &ArgMatches<'_>) -> Result3<()> {
+fn test(args: &ArgMatches) -> Result3<()> {
     let book_dir = get_book_dir(args);
     let mut book = load_book(&book_dir)?;
     book.test(vec![])
 }
 
-fn get_book_dir(args: &ArgMatches<'_>) -> PathBuf {
+fn get_book_dir(args: &ArgMatches) -> PathBuf {
     if let Some(dir) = args.value_of("dir") {
         // Check if path is relative from current dir, or absolute...
         let p = Path::new(dir);
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index d7acae2ff2a..22c2d28d9f6 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -79,6 +79,8 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] }
 libc = { version = "0.2.79", features = ["align"] }
 # Ensure default features of libz-sys, which are disabled in some scenarios.
 libz-sys = { version = "1.1.2" }
+# same for regex
+regex = { version = "1.5.5" }
 proc-macro2 = { version = "1", features = ["default"] }
 quote = { version = "1", features = ["default"] }
 rand_core_0_5 = { package = "rand_core", version = "0.5.1", features = ["getrandom", "alloc", "std"] }
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index bab881f4b4e..8f35068e35f 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -148,7 +148,7 @@ impl<'a> Item<'a> {
         Item {
             unsafety: fm.unsafety,
             abi: format_extern(
-                ast::Extern::from_abi(fm.abi),
+                ast::Extern::from_abi(fm.abi, DUMMY_SP),
                 config.force_explicit_abi(),
                 true,
             ),
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 58fd95c656e..4b26f4e40df 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -138,8 +138,8 @@ pub(crate) fn format_extern(
 ) -> Cow<'static, str> {
     let abi = match ext {
         ast::Extern::None => "Rust".to_owned(),
-        ast::Extern::Implicit => "C".to_owned(),
-        ast::Extern::Explicit(abi) => abi.symbol_unescaped.to_string(),
+        ast::Extern::Implicit(_) => "C".to_owned(),
+        ast::Extern::Explicit(abi, _) => abi.symbol_unescaped.to_string(),
     };
 
     if abi == "Rust" && !is_mod {
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 503df537047..9615c4db6b4 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -96,9 +96,25 @@ mod os_impl {
 
     #[cfg(unix)]
     pub fn check(path: &Path, bad: &mut bool) {
+        const ALLOWED: &[&str] = &["configure"];
+
         crate::walk_no_read(
             path,
-            &mut |path| crate::filter_dirs(path) || path.ends_with("src/etc"),
+            &mut |path| {
+                crate::filter_dirs(path)
+                    || path.ends_with("src/etc")
+                    // This is a list of directories that we almost certainly
+                    // don't need to walk. A future PR will likely want to
+                    // remove these in favor of crate::walk_no_read using git
+                    // ls-files to discover the paths we should check, which
+                    // would naturally ignore all of these directories. It's
+                    // also likely faster than walking the directory tree
+                    // directly (since git is just reading from a couple files
+                    // to produce the results).
+                    || path.ends_with("target")
+                    || path.ends_with("build")
+                    || path.ends_with(".git")
+            },
             &mut |entry| {
                 let file = entry.path();
                 let filename = file.file_name().unwrap().to_string_lossy();
@@ -110,6 +126,11 @@ mod os_impl {
                 if t!(is_executable(&file), file) {
                     let rel_path = file.strip_prefix(path).unwrap();
                     let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
+
+                    if ALLOWED.contains(&git_friendly_path.as_str()) {
+                        return;
+                    }
+
                     let output = Command::new("git")
                         .arg("ls-files")
                         .arg(&git_friendly_path)
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index d555f7c8e34..aa8d8b4f64d 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -78,13 +78,8 @@ fn main() {
         check!(unit_tests, &compiler_path);
         check!(unit_tests, &library_path);
 
-        if bins::check_filesystem_support(
-            &[&src_path, &compiler_path, &library_path],
-            &output_directory,
-        ) {
-            check!(bins, &src_path);
-            check!(bins, &compiler_path);
-            check!(bins, &library_path);
+        if bins::check_filesystem_support(&[&root_path], &output_directory) {
+            check!(bins, &root_path);
         }
 
         check!(style, &src_path);
diff --git a/suggest-blanket-impl-local-trait b/suggest-blanket-impl-local-trait
deleted file mode 100755
index 0a357e006c3..00000000000
--- a/suggest-blanket-impl-local-trait
+++ /dev/null
Binary files differ