about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Cargo.lock62
-rw-r--r--RELEASES.md96
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs4
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs12
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs36
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/find_use.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs28
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs6
-rw-r--r--compiler/rustc_borrowck/src/nll.rs32
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs154
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs25
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs8
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs8
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs7
-rw-r--r--compiler/rustc_borrowck/src/used_muts.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs15
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs35
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs11
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs16
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs11
-rw-r--r--compiler/rustc_errors/src/emitter.rs10
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_hir_analysis/locales/en-US.ftl8
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs31
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs35
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/test.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs47
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs2
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs67
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs13
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs10
-rw-r--r--compiler/rustc_metadata/src/locator.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs8
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs12
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/query.rs60
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs2
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs9
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs6
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs30
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs33
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_middle/src/values.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs9
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs32
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs9
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs19
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs14
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs6
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs8
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs116
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs13
-rw-r--r--compiler/rustc_parse/src/parser/item.rs24
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs17
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs2
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs9
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs12
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs10
-rw-r--r--compiler/rustc_resolve/src/late.rs9
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs5
-rw-r--r--compiler/rustc_resolve/src/lib.rs11
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs11
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs4
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs2
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs1
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs25
-rw-r--r--config.toml.example16
-rw-r--r--library/core/benches/lib.rs1
-rw-r--r--library/core/benches/tuple.rs22
-rw-r--r--library/core/src/intrinsics.rs19
-rw-r--r--library/core/src/slice/index.rs14
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/core/src/str/traits.rs72
-rw-r--r--library/core/src/tuple.rs48
-rw-r--r--library/std/src/f32.rs30
-rw-r--r--library/std/src/f32/tests.rs16
-rw-r--r--library/std/src/f64.rs30
-rw-r--r--library/std/src/f64/tests.rs16
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--src/bootstrap/CHANGELOG.md1
-rw-r--r--src/bootstrap/bolt.rs27
-rw-r--r--src/bootstrap/config.rs17
-rwxr-xr-xsrc/bootstrap/configure.py23
-rw-r--r--src/bootstrap/defaults/config.codegen.toml2
-rw-r--r--src/bootstrap/dist.rs139
-rw-r--r--src/bootstrap/flags.rs13
-rw-r--r--src/bootstrap/format.rs12
-rw-r--r--src/bootstrap/native.rs36
-rw-r--r--src/bootstrap/setup.rs10
-rw-r--r--src/bootstrap/setup/tests.rs6
-rw-r--r--src/ci/stage-build.py4
-rw-r--r--src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md1
-rw-r--r--src/doc/unstable-book/src/compiler-flags/cf-protection.md4
-rw-r--r--src/etc/rust_analyzer_settings.json (renamed from src/etc/vscode_settings.json)0
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/askama.toml1
-rw-r--r--src/librustdoc/clean/mod.rs2
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/clean/utils.rs2
-rw-r--r--src/librustdoc/html/format.rs1
-rw-r--r--src/librustdoc/html/render/print_item.rs6
-rw-r--r--src/librustdoc/html/render/search_index.rs34
-rw-r--r--src/librustdoc/html/templates/STYLE.md27
-rw-r--r--src/librustdoc/html/templates/page.html294
-rw-r--r--src/librustdoc/html/templates/print_item.html52
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs1
-rw-r--r--src/librustdoc/passes/check_doc_test_visibility.rs1
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/librustdoc/passes/propagate_doc_cfg.rs1
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/rustdoc-json-types/Cargo.toml1
-rw-r--r--src/rustdoc-json-types/lib.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs2
-rw-r--r--src/tools/jsondoclint/Cargo.toml1
-rw-r--r--src/tools/jsondoclint/src/validator/tests.rs29
-rw-r--r--src/tools/replace-version-placeholder/src/main.rs2
-rw-r--r--src/tools/rustdoc-js/tester.js113
-rw-r--r--src/tools/tidy/src/alphabetical.rs2
-rw-r--r--src/tools/tidy/src/bins.rs74
-rw-r--r--src/tools/tidy/src/debug_artifacts.rs2
-rw-r--r--src/tools/tidy/src/edition.rs37
-rw-r--r--src/tools/tidy/src/error_codes.rs10
-rw-r--r--src/tools/tidy/src/features.rs8
-rw-r--r--src/tools/tidy/src/main.rs2
-rw-r--r--src/tools/tidy/src/pal.rs2
-rw-r--r--src/tools/tidy/src/rustdoc_gui_tests.rs2
-rw-r--r--src/tools/tidy/src/style.rs2
-rw-r--r--src/tools/tidy/src/target_specific_tests.rs2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--src/tools/tidy/src/unit_tests.rs19
-rw-r--r--src/tools/tidy/src/walk.rs39
-rw-r--r--tests/codegen/comparison-operators-2-tuple.rs121
-rw-r--r--tests/codegen/slice-indexing.rs35
-rw-r--r--tests/mir-opt/basic_assignment.main.ElaborateDrops.diff85
-rw-r--r--tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir28
-rw-r--r--tests/mir-opt/basic_assignment.rs2
-rw-r--r--tests/mir-opt/building/custom/as_cast.float_to_int.built.after.mir10
-rw-r--r--tests/mir-opt/building/custom/as_cast.int_to_int.built.after.mir10
-rw-r--r--tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir10
-rw-r--r--tests/mir-opt/building/custom/as_cast.rs43
-rw-r--r--tests/mir-opt/issue_41110.test.ElaborateDrops.diff46
-rw-r--r--tests/mir-opt/issue_41888.main.ElaborateDrops.diff91
-rw-r--r--tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir18
-rw-r--r--tests/mir-opt/sroa.constant.ScalarReplacementOfAggregates.diff46
-rw-r--r--tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff91
-rw-r--r--tests/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff43
-rw-r--r--tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff80
-rw-r--r--tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff56
-rw-r--r--tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff33
-rw-r--r--tests/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff23
-rw-r--r--tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff214
-rw-r--r--tests/mir-opt/sroa/lifetimes.rs37
-rw-r--r--tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff46
-rw-r--r--tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff91
-rw-r--r--tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff43
-rw-r--r--tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff44
-rw-r--r--tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff80
-rw-r--r--tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff56
-rw-r--r--tests/mir-opt/sroa/structs.rs (renamed from tests/mir-opt/sroa.rs)18
-rw-r--r--tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff33
-rw-r--r--tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff23
-rw-r--r--tests/run-make/coverage-reports/expected_show_coverage.closure.txt4
-rw-r--r--tests/run-make/rustdoc-verify-output-files/Makefile14
-rw-r--r--tests/run-make/translation/Makefile16
-rw-r--r--tests/rustdoc-js-std/option-type-signatures.js7
-rw-r--r--tests/rustdoc-js/where-clause.js19
-rw-r--r--tests/rustdoc-js/where-clause.rs16
-rw-r--r--tests/rustdoc/type-layout.rs8
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs13
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr86
-rw-r--r--tests/ui/associated-types/issue-67684.rs8
-rw-r--r--tests/ui/async-await/issue-108572.rs12
-rw-r--r--tests/ui/async-await/issue-108572.stderr12
-rw-r--r--tests/ui/auto-traits/suspicious-negative-impls-lint.rs21
-rw-r--r--tests/ui/auto-traits/suspicious-negative-impls-lint.stderr52
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.rs2
-rw-r--r--tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr18
-rw-r--r--tests/ui/borrowck/drop-in-loop.rs24
-rw-r--r--tests/ui/borrowck/drop-in-loop.stderr14
-rw-r--r--tests/ui/borrowck/issue-45199.rs3
-rw-r--r--tests/ui/borrowck/issue-45199.stderr4
-rw-r--r--tests/ui/borrowck/issue-58776-borrowck-scans-children.rs1
-rw-r--r--tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr19
-rw-r--r--tests/ui/borrowck/issue-70919-drop-in-loop.rs25
-rw-r--r--tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs2
-rw-r--r--tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr18
-rw-r--r--tests/ui/coherence/coherence-orphan.rs5
-rw-r--r--tests/ui/coherence/coherence-orphan.stderr15
-rw-r--r--tests/ui/consts/const-eval/ub-slice-get-unchecked.rs9
-rw-r--r--tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr18
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs14
-rw-r--r--tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs16
-rw-r--r--tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr21
-rw-r--r--tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr3
-rw-r--r--tests/ui/issues/issue-106755.rs2
-rw-r--r--tests/ui/issues/issue-106755.stderr18
-rw-r--r--tests/ui/lint/unconditional_panic_98444.rs7
-rw-r--r--tests/ui/lint/unconditional_panic_98444.stderr10
-rw-r--r--tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs1
-rw-r--r--tests/ui/mir/unsize-trait.rs15
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs19
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs18
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-opaque-2.rs17
-rw-r--r--tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs24
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-closure.stderr2
-rw-r--r--tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr2
-rw-r--r--tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr28
-rw-r--r--tests/ui/parser/issues/issue-108242-semicolon-recovery.rs5
-rw-r--r--tests/ui/parser/issues/issue-108242-semicolon-recovery.stderr13
-rw-r--r--tests/ui/stability-attribute/auxiliary/const-stability-attribute-implies.rs12
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs16
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr8
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.rs16
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr10
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.rs19
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.stderr22
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.rs21
-rw-r--r--tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.stderr22
-rw-r--r--tests/ui/suggestions/issue-107860.rs6
-rw-r--r--tests/ui/suggestions/issue-107860.stderr12
-rw-r--r--tests/ui/suggestions/multiline-multipart-suggestion.rs19
-rw-r--r--tests/ui/suggestions/multiline-multipart-suggestion.stderr46
-rw-r--r--tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs9
-rw-r--r--tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr24
-rw-r--r--triagebot.toml5
310 files changed, 3687 insertions, 1979 deletions
diff --git a/.gitignore b/.gitignore
index e5ca3e50313..ce797a7a837 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,7 +41,7 @@ no_llvm_build
 /inst/
 /llvm/
 /mingw-build/
-/build/
+build/
 /build-rust-analyzer/
 /dist/
 /unicode-downloads
diff --git a/Cargo.lock b/Cargo.lock
index 5530541cdd0..82530c019a9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,48 +132,37 @@ checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7"
 
 [[package]]
 name = "askama"
-version = "0.11.0"
+version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d8f355701c672c2ba3d718acbd213f740beea577cc4eae66accdffe15be1882"
+checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
 dependencies = [
  "askama_derive",
  "askama_escape",
- "askama_shared",
 ]
 
 [[package]]
 name = "askama_derive"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84704cab5b7ae0fd3a9f78ee5eb7b27f3749df445f04623db6633459ae283267"
-dependencies = [
- "askama_shared",
- "proc-macro2",
- "syn",
-]
-
-[[package]]
-name = "askama_escape"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5"
-
-[[package]]
-name = "askama_shared"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dae03eebba55a2697a376e58b573a29fe36893157173ac8df312ad85f3c0e012"
+checksum = "e80b5ad1afe82872b7aa3e9de9b206ecb85584aa324f0f60fa4c903ce935936b"
 dependencies = [
- "askama_escape",
+ "basic-toml",
+ "mime",
+ "mime_guess",
  "nom",
  "proc-macro2",
  "quote",
  "serde",
  "syn",
- "toml 0.5.7",
 ]
 
 [[package]]
+name = "askama_escape"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
+
+[[package]]
 name = "atty"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -224,6 +213,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf"
 
 [[package]]
+name = "basic-toml"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "bitflags"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2287,6 +2285,7 @@ dependencies = [
  "anyhow",
  "clap 4.1.4",
  "fs-err",
+ "rustc-hash",
  "rustdoc-json-types",
  "serde",
  "serde_json",
@@ -2614,6 +2613,22 @@ dependencies = [
 ]
 
 [[package]]
+name = "mime"
+version = "0.3.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef"
+dependencies = [
+ "mime",
+ "unicase",
+]
+
+[[package]]
 name = "minifier"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4850,6 +4865,7 @@ dependencies = [
 name = "rustdoc-json-types"
 version = "0.1.0"
 dependencies = [
+ "rustc-hash",
  "serde",
  "serde_json",
 ]
diff --git a/RELEASES.md b/RELEASES.md
index 00d0171de6d..f418ab23d10 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,99 @@
+Version 1.68.0 (2023-03-09)
+==========================
+
+<a id="1.68.0-Language"></a>
+
+Language
+--------
+
+- [Stabilize default_alloc_error_handler](https://github.com/rust-lang/rust/pull/102318/)
+  This allows usage of `alloc` on stable without requiring the 
+  definition of a handler for allocation failure. Defining custom handlers is still unstable.
+- [Stabilize `efiapi` calling convention.](https://github.com/rust-lang/rust/pull/105795/)
+- [Remove implicit promotion for types with drop glue](https://github.com/rust-lang/rust/pull/105085/)
+
+<a id="1.68.0-Compiler"></a>
+
+Compiler
+--------
+
+- [Change `bindings_with_variant_name` to deny-by-default](https://github.com/rust-lang/rust/pull/104154/)
+- [Allow .. to be parsed as let initializer](https://github.com/rust-lang/rust/pull/105701/)
+- [Add `armv7-sony-vita-newlibeabihf` as a tier 3 target](https://github.com/rust-lang/rust/pull/105712/)
+- [Always check alignment during compile-time const evaluation](https://github.com/rust-lang/rust/pull/104616/)
+- [Disable "split dwarf inlining" by default.](https://github.com/rust-lang/rust/pull/106709/)
+- [Add vendor to Fuchsia's target triple](https://github.com/rust-lang/rust/pull/106429/)
+- [Enable sanitizers for s390x-linux](https://github.com/rust-lang/rust/pull/107127/)
+
+<a id="1.68.0-Libraries"></a>
+
+Libraries
+---------
+
+- [Loosen the bound on the Debug implementation of Weak.](https://github.com/rust-lang/rust/pull/90291/)
+- [Make `std::task::Context` !Send and !Sync](https://github.com/rust-lang/rust/pull/95985/)
+- [PhantomData layout guarantees](https://github.com/rust-lang/rust/pull/104081/)
+- [Don't derive Debug for `OnceWith` & `RepeatWith`](https://github.com/rust-lang/rust/pull/104163/)
+- [Implement DerefMut for PathBuf](https://github.com/rust-lang/rust/pull/105018/)
+- [Add O(1) `Vec -> VecDeque` conversion guarantee](https://github.com/rust-lang/rust/pull/105128/)
+- [Leak amplification for peek_mut() to ensure BinaryHeap's invariant is always met](https://github.com/rust-lang/rust/pull/105851/)
+
+<a id="1.68.0-Stabilized-APIs"></a>
+
+Stabilized APIs
+---------------
+
+- [`{core,std}::pin::pin!`](https://doc.rust-lang.org/stable/std/pin/macro.pin.html)
+- [`impl From<bool> for {f32,f64}`](https://doc.rust-lang.org/stable/std/primitive.f32.html#impl-From%3Cbool%3E-for-f32)
+- [`std::path::MAIN_SEPARATOR_STR`](https://doc.rust-lang.org/stable/std/path/constant.MAIN_SEPARATOR_STR.html)
+- [`impl DerefMut for PathBuf`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#impl-DerefMut-for-PathBuf)
+
+These APIs are now stable in const contexts:
+
+- [`VecDeque::new`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.new)
+
+<a id="1.68.0-Cargo"></a>
+
+Cargo
+-----
+
+- [Stabilize sparse registry support for crates.io](https://github.com/rust-lang/cargo/pull/11224/)
+- [`cargo build --verbose` tells you more about why it recompiles.](https://github.com/rust-lang/cargo/pull/11407/)
+- [Show progress of crates.io index update even `net.git-fetch-with-cli` option enabled](https://github.com/rust-lang/cargo/pull/11579/)
+
+<a id="1.68.0-Misc"></a>
+
+Misc
+----
+
+<a id="1.68.0-Compatibility-Notes"></a>
+
+Compatibility Notes
+-------------------
+
+- [Add `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` to future-incompat report](https://github.com/rust-lang/rust/pull/103418/)
+- [Only specify `--target` by default for `-Zgcc-ld=lld` on wasm](https://github.com/rust-lang/rust/pull/101792/)
+- [Bump `IMPLIED_BOUNDS_ENTAILMENT` to Deny + ReportNow](https://github.com/rust-lang/rust/pull/106465/)
+- [`std::task::Context` no longer implements Send and Sync](https://github.com/rust-lang/rust/pull/95985)
+
+<a id="1.68.0-Internal-Changes"></a>
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Encode spans relative to the enclosing item](https://github.com/rust-lang/rust/pull/84762/)
+- [Don't normalize in AstConv](https://github.com/rust-lang/rust/pull/101947/)
+- [Find the right lower bound region in the scenario of partial order relations](https://github.com/rust-lang/rust/pull/104765/)
+- [Fix impl block in const expr](https://github.com/rust-lang/rust/pull/104889/)
+- [Check ADT fields for copy implementations considering regions](https://github.com/rust-lang/rust/pull/105102/)
+- [rustdoc: simplify JS search routine by not messing with lev distance](https://github.com/rust-lang/rust/pull/105796/)
+- [Enable ThinLTO for rustc on `x86_64-pc-windows-msvc`](https://github.com/rust-lang/rust/pull/103591/)
+- [Enable ThinLTO for rustc on `x86_64-apple-darwin`](https://github.com/rust-lang/rust/pull/103647/)
+
 Version 1.67.1 (2023-02-09)
 ===========================
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 41295f2b7b6..debe0acb04e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::PredicateOrigin;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::ty::{DefIdTree, ResolverAstLowering, TyCtxt};
+use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::{kw, sym, Ident};
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 2cc009410f4..539c822ea09 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -12,7 +12,7 @@ use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
 use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
@@ -643,7 +643,7 @@ fn validate_generic_param_order(
     span: Span,
 ) {
     let mut max_param: Option<ParamKindOrd> = None;
-    let mut out_of_order = FxHashMap::default();
+    let mut out_of_order = FxIndexMap::default();
     let mut param_idents = Vec::with_capacity(generics.len());
 
     for (idx, param) in generics.iter().enumerate() {
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index b9dcaee2373..6207a32b28d 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,7 +4,6 @@
 //!
 //! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
 
-#![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
 #![feature(if_let_guard)]
 #![feature(iter_is_partitioned)]
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 5bb92a35826..fa0552e012d 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -4,7 +4,7 @@ use crate::nll::ToRegionVid;
 use crate::path_utils::allow_two_phase_borrow;
 use crate::place_ext::PlaceExt;
 use crate::BorrowIndex;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
@@ -26,10 +26,10 @@ pub struct BorrowSet<'tcx> {
     /// NOTE: a given location may activate more than one borrow in the future
     /// when more general two-phase borrow support is introduced, but for now we
     /// only need to store one borrow index.
-    pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+    pub activation_map: FxIndexMap<Location, Vec<BorrowIndex>>,
 
     /// Map from local to all the borrows on that local.
-    pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+    pub local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
 
     pub(crate) locals_state_at_exit: LocalsStateAtExit,
 }
@@ -175,8 +175,8 @@ struct GatherBorrows<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     location_map: FxIndexMap<Location, BorrowData<'tcx>>,
-    activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
-    local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+    activation_map: FxIndexMap<Location, Vec<BorrowIndex>>,
+    local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
 
     /// When we encounter a 2-phase borrow statement, it will always
     /// be assigning into a temporary TEMP:
@@ -186,7 +186,7 @@ struct GatherBorrows<'a, 'tcx> {
     /// We add TEMP into this map with `b`, where `b` is the index of
     /// the borrow. When we find a later use of this activation, we
     /// remove from the map (and add to the "tombstone" set below).
-    pending_activations: FxHashMap<mir::Local, BorrowIndex>,
+    pending_activations: FxIndexMap<mir::Local, BorrowIndex>,
 
     locals_state_at_exit: LocalsStateAtExit,
 }
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 2821677c537..d2574aa58c2 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -1,6 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, BasicBlock, Body, Location, Place};
 use rustc_middle::ty::RegionVid;
@@ -124,7 +124,7 @@ pub struct Borrows<'a, 'tcx> {
     body: &'a Body<'tcx>,
 
     borrow_set: &'a BorrowSet<'tcx>,
-    borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
+    borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
 struct StackEntry {
@@ -138,7 +138,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
     visit_stack: Vec<StackEntry>,
     body: &'a Body<'tcx>,
     regioncx: &'a RegionInferenceContext<'tcx>,
-    borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
+    borrows_out_of_scope_at_location: FxIndexMap<Location, Vec<BorrowIndex>>,
 }
 
 impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
@@ -148,7 +148,7 @@ impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
             visit_stack: vec![],
             body,
             regioncx,
-            borrows_out_of_scope_at_location: FxHashMap::default(),
+            borrows_out_of_scope_at_location: FxIndexMap::default(),
         }
     }
 }
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index cb97699d7d2..f43b611f54e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,7 +1,7 @@
 use either::Either;
 use rustc_const_eval::util::CallKind;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
     struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
@@ -173,7 +173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
             let mut is_loop_move = false;
             let mut in_pattern = false;
-            let mut seen_spans = FxHashSet::default();
+            let mut seen_spans = FxIndexSet::default();
 
             for move_site in &move_site_vec {
                 let move_out = self.move_data.moves[(*move_site).moi];
@@ -1467,6 +1467,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
     ///
+    /// Depending on the origin of the StorageDeadOrDrop, this may be
+    /// reported as either a drop or an illegal mutation of a borrowed value.
+    /// The latter is preferred when the this is a drop triggered by a
+    /// reassignment, as it's more user friendly to report a problem with the
+    /// explicit assignment than the implicit drop.
+    #[instrument(level = "debug", skip(self))]
+    pub(crate) fn report_storage_dead_or_drop_of_borrowed(
+        &mut self,
+        location: Location,
+        place_span: (Place<'tcx>, Span),
+        borrow: &BorrowData<'tcx>,
+    ) {
+        // It's sufficient to check the last desugaring as Replace is the last
+        // one to be applied.
+        if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() {
+            self.report_illegal_mutation_of_borrowed(location, place_span, borrow)
+        } else {
+            self.report_borrowed_value_does_not_live_long_enough(
+                location,
+                borrow,
+                place_span,
+                Some(WriteKind::StorageDeadOrDrop),
+            )
+        }
+    }
+
     /// This means that some data referenced by `borrow` needs to live
     /// past the point where the StorageDeadOrDrop of `place` occurs.
     /// This is usually interpreted as meaning that `place` has too
@@ -2197,8 +2223,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
         }
 
-        let mut visited = FxHashSet::default();
-        let mut move_locations = FxHashSet::default();
+        let mut visited = FxIndexSet::default();
+        let mut move_locations = FxIndexSet::default();
         let mut reinits = vec![];
         let mut result = vec![];
 
@@ -2325,7 +2351,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let reinits_reachable = reinits
             .into_iter()
             .filter(|reinit| {
-                let mut visited = FxHashSet::default();
+                let mut visited = FxIndexSet::default();
                 let mut stack = vec![*reinit];
                 while let Some(location) = stack.pop() {
                     if !visited.insert(location) {
diff --git a/compiler/rustc_borrowck/src/diagnostics/find_use.rs b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
index 15f42e26cbf..fd1fda2ee4b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/find_use.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/find_use.rs
@@ -9,7 +9,7 @@ use crate::{
     nll::ToRegionVid,
     region_infer::{Cause, RegionInferenceContext},
 };
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
 use rustc_middle::ty::{RegionVid, TyCtxt};
@@ -37,7 +37,7 @@ struct UseFinder<'cx, 'tcx> {
 impl<'cx, 'tcx> UseFinder<'cx, 'tcx> {
     fn find(&mut self) -> Option<Cause> {
         let mut queue = VecDeque::new();
-        let mut visited = FxHashSet::default();
+        let mut visited = FxIndexSet::default();
 
         queue.push_back(self.start_point);
         while let Some(p) = queue.pop_front() {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index a99fd594a07..af705e6a80f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
     Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
 use rustc_middle::ty::print::Print;
-use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
@@ -925,7 +925,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             return OtherUse(use_span);
         }
 
-        for stmt in &self.body[location.block].statements[location.statement_index + 1..] {
+        // drop and replace might have moved the assignment to the next block
+        let maybe_additional_statement =
+            if let TerminatorKind::Drop { target: drop_target, .. } =
+                self.body[location.block].terminator().kind
+            {
+                self.body[drop_target].statements.first()
+            } else {
+                None
+            };
+
+        let statements =
+            self.body[location.block].statements[location.statement_index + 1..].iter();
+
+        for stmt in statements.chain(maybe_additional_statement) {
             if let StatementKind::Assign(box (_, Rvalue::Aggregate(kind, places))) = &stmt.kind {
                 let (&def_id, is_generator) = match kind {
                     box AggregateKind::Closure(def_id, _) => (def_id, false),
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 328ac880dd4..eded913ae96 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -828,7 +828,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             let Some(hir::Node::Item(item)) = node else { return; };
             let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
             let body = self.infcx.tcx.hir().body(body_id);
-            let mut v = V { assign_span: span, err, ty, suggested: false };
+            let mut assign_span = span;
+            // Drop desugaring is done at MIR build so it's not in the HIR
+            if let Some(DesugaringKind::Replace) = span.desugaring_kind() {
+                assign_span.remove_mark();
+            }
+
+            let mut v = V { assign_span, err, ty, suggested: false };
             v.visit_body(body);
             if !v.suggested {
                 err.help(&format!(
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 1eaf0a2f15c..d5ece57437e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -1,7 +1,7 @@
 //! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
 //! outlives constraints.
 
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_middle::ty::RegionVid;
 use smallvec::SmallVec;
@@ -87,7 +87,7 @@ impl OutlivesSuggestionBuilder {
 
         // Keep track of variables that we have already suggested unifying so that we don't print
         // out silly duplicate messages.
-        let mut unified_already = FxHashSet::default();
+        let mut unified_already = FxIndexSet::default();
 
         for (fr, outlived) in &self.constraints_to_add {
             let Some(fr_name) = self.region_vid_to_name(mbcx, *fr) else {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index f6881a2e5bc..cc5a1f5ab12 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -6,7 +6,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, RegionVid, Ty};
+use rustc_middle::ty::{self, RegionVid, Ty};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 0f591460e9d..0fc3240c560 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1,6 +1,5 @@
 //! This query borrow-checks the MIR to (further) ensure it is not broken.
 
-#![allow(rustc::potential_query_instability)]
 #![feature(associated_type_bounds)]
 #![feature(box_patterns)]
 #![feature(let_chains)]
@@ -18,7 +17,7 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate tracing;
 
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
@@ -404,7 +403,7 @@ fn do_mir_borrowck<'tcx>(
     // Note that this set is expected to be small - only upvars from closures
     // would have a chance of erroneously adding non-user-defined mutable vars
     // to the set.
-    let temporary_used_locals: FxHashSet<Local> = mbcx
+    let temporary_used_locals: FxIndexSet<Local> = mbcx
         .used_mut
         .iter()
         .filter(|&local| !mbcx.body.local_decls[*local].is_user_variable())
@@ -491,7 +490,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
 
 pub struct BorrowckInferCtxt<'cx, 'tcx> {
     pub(crate) infcx: &'cx InferCtxt<'tcx>,
-    pub(crate) reg_var_to_origin: RefCell<FxHashMap<ty::RegionVid, RegionCtxt>>,
+    pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
 }
 
 impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
@@ -588,7 +587,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
     /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
     /// of the `Span` type (while required to mute some errors) stops the muting of the reservation
     /// errors.
-    access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>,
+    access_place_error_reported: FxIndexSet<(Place<'tcx>, Span)>,
     /// This field keeps track of when borrow conflict errors are reported
     /// for reservations, so that we don't report seemingly duplicate
     /// errors for corresponding activations.
@@ -596,17 +595,17 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
     // FIXME: ideally this would be a set of `BorrowIndex`, not `Place`s,
     // but it is currently inconvenient to track down the `BorrowIndex`
     // at the time we detect and report a reservation error.
-    reservation_error_reported: FxHashSet<Place<'tcx>>,
+    reservation_error_reported: FxIndexSet<Place<'tcx>>,
     /// This fields keeps track of the `Span`s that we have
     /// used to report extra information for `FnSelfUse`, to avoid
     /// unnecessarily verbose errors.
-    fn_self_span_reported: FxHashSet<Span>,
+    fn_self_span_reported: FxIndexSet<Span>,
     /// This field keeps track of errors reported in the checking of uninitialized variables,
     /// so that we don't report seemingly duplicate errors.
-    uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
+    uninitialized_error_reported: FxIndexSet<PlaceRef<'tcx>>,
     /// This field keeps track of all the local variables that are declared mut and are mutated.
     /// Used for the warning issued by an unused mutable local variable.
-    used_mut: FxHashSet<Local>,
+    used_mut: FxIndexSet<Local>,
     /// If the function we're checking is a closure, then we'll need to report back the list of
     /// mutable upvars that have been used. This field keeps track of them.
     used_mut_upvars: SmallVec<[Field; 8]>,
@@ -628,7 +627,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
 
     /// Record the region names generated for each region in the given
     /// MIR def so that we can reuse them later in help/error messages.
-    region_names: RefCell<FxHashMap<RegionVid, RegionName>>,
+    region_names: RefCell<FxIndexMap<RegionVid, RegionName>>,
 
     /// The counter for generating new region names.
     next_region_name: RefCell<usize>,
@@ -1185,12 +1184,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             this.buffer_error(err);
                         }
                         WriteKind::StorageDeadOrDrop => this
-                            .report_borrowed_value_does_not_live_long_enough(
-                                location,
-                                borrow,
-                                place_span,
-                                Some(kind),
-                            ),
+                            .report_storage_dead_or_drop_of_borrowed(location, place_span, borrow),
                         WriteKind::Mutate => {
                             this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
                         }
@@ -2334,7 +2328,7 @@ mod error {
         /// same primary span come out in a consistent order.
         buffered_move_errors:
             BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx, ErrorGuaranteed>)>,
-        buffered_mut_errors: FxHashMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
+        buffered_mut_errors: FxIndexMap<Span, (DiagnosticBuilder<'tcx, ErrorGuaranteed>, usize)>,
         /// Diagnostics to be reported buffer.
         buffered: Vec<Diagnostic>,
         /// Set to Some if we emit an error during borrowck
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index 4af324f740a..b6c5d4245d7 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -1,7 +1,7 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::MemberConstraint;
 use rustc_middle::ty::{self, Ty};
@@ -18,7 +18,7 @@ where
 {
     /// Stores the first "member" constraint for a given `R0`. This is an
     /// index into the `constraints` vector below.
-    first_constraints: FxHashMap<R, NllMemberConstraintIndex>,
+    first_constraints: FxIndexMap<R, NllMemberConstraintIndex>,
 
     /// Stores the data about each `R0 member of [R1..Rn]` constraint.
     /// These are organized into a linked list, so each constraint
@@ -132,7 +132,7 @@ where
 
         let MemberConstraintSet { first_constraints, mut constraints, choice_regions } = self;
 
-        let mut first_constraints2 = FxHashMap::default();
+        let mut first_constraints2 = FxIndexMap::default();
         first_constraints2.reserve(first_constraints.len());
 
         for (r1, start1) in first_constraints {
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index e5dbb83dd07..96228338a4c 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -10,10 +10,9 @@ use rustc_middle::mir::{
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid};
+use rustc_middle::ty::{self, OpaqueHiddenType, Region, RegionVid, TyCtxt};
 use rustc_span::symbol::sym;
 use std::env;
-use std::fmt::Debug;
 use std::io;
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -325,7 +324,7 @@ pub(super) fn dump_mir_results<'tcx>(
     infcx: &BorrowckInferCtxt<'_, 'tcx>,
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
-    closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
+    closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
 ) {
     if !dump_enabled(infcx.tcx, "nll", body.source.def_id()) {
         return;
@@ -340,9 +339,11 @@ pub(super) fn dump_mir_results<'tcx>(
 
                 if let Some(closure_region_requirements) = closure_region_requirements {
                     writeln!(out, "| Free Region Constraints")?;
-                    for_each_region_constraint(closure_region_requirements, &mut |msg| {
-                        writeln!(out, "| {}", msg)
-                    })?;
+                    for_each_region_constraint(
+                        infcx.tcx,
+                        closure_region_requirements,
+                        &mut |msg| writeln!(out, "| {}", msg),
+                    )?;
                     writeln!(out, "|")?;
                 }
             }
@@ -375,7 +376,7 @@ pub(super) fn dump_annotation<'tcx>(
     infcx: &BorrowckInferCtxt<'_, 'tcx>,
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
-    closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
+    closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
     opaque_type_values: &VecMap<LocalDefId, OpaqueHiddenType<'tcx>>,
     errors: &mut crate::error::BorrowckErrors<'tcx>,
 ) {
@@ -405,7 +406,7 @@ pub(super) fn dump_annotation<'tcx>(
 
         // Dump the region constraints we are imposing *between* those
         // newly created variables.
-        for_each_region_constraint(closure_region_requirements, &mut |msg| {
+        for_each_region_constraint(tcx, closure_region_requirements, &mut |msg| {
             err.note(msg);
             Ok(())
         })
@@ -426,16 +427,19 @@ pub(super) fn dump_annotation<'tcx>(
     errors.buffer_non_error_diag(err);
 }
 
-fn for_each_region_constraint(
-    closure_region_requirements: &ClosureRegionRequirements<'_>,
+fn for_each_region_constraint<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    closure_region_requirements: &ClosureRegionRequirements<'tcx>,
     with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
 ) -> io::Result<()> {
     for req in &closure_region_requirements.outlives_requirements {
-        let subject: &dyn Debug = match &req.subject {
-            ClosureOutlivesSubject::Region(subject) => subject,
-            ClosureOutlivesSubject::Ty(ty) => ty,
+        let subject = match req.subject {
+            ClosureOutlivesSubject::Region(subject) => format!("{:?}", subject),
+            ClosureOutlivesSubject::Ty(ty) => {
+                format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid)))
+            }
         };
-        with_msg(&format!("where {:?}: {:?}", subject, req.outlived_free_region,))?;
+        with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?;
     }
     Ok(())
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 21b5bd7cb94..905d8c42b28 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -3,7 +3,7 @@ use std::rc::Rc;
 
 use rustc_data_structures::binary_search_util;
 use rustc_data_structures::frozen::Frozen;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::scc::Sccs;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::CRATE_DEF_ID;
@@ -12,8 +12,9 @@ use rustc_infer::infer::outlives::test_type_match;
 use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
 use rustc_middle::mir::{
-    Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
-    ConstraintCategory, Local, Location, ReturnConstraint, TerminatorKind,
+    Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
+    ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
+    TerminatorKind,
 };
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::ObligationCauseCode;
@@ -87,7 +88,7 @@ pub struct RegionInferenceContext<'tcx> {
     member_constraints_applied: Vec<AppliedMemberConstraint>,
 
     /// Map universe indexes to information on why we created it.
-    universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
+    universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
     /// Contains the minimum universe of any variable within the same
     /// SCC. We will ensure that no SCC contains values that are not
@@ -262,7 +263,7 @@ fn sccs_info<'cx, 'tcx>(
     debug!(debug_str);
 
     let num_components = sccs.scc_data().ranges().len();
-    let mut components = vec![FxHashSet::default(); num_components];
+    let mut components = vec![FxIndexSet::default(); num_components];
 
     for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
         let reg_var = ty::RegionVid::from_usize(reg_var_idx);
@@ -294,9 +295,9 @@ fn sccs_info<'cx, 'tcx>(
 
             (ConstraintSccIndex::from_usize(scc_idx), repr)
         })
-        .collect::<FxHashMap<_, _>>();
+        .collect::<FxIndexMap<_, _>>();
 
-    let mut scc_node_to_edges = FxHashMap::default();
+    let mut scc_node_to_edges = FxIndexMap::default();
     for (scc_idx, repr) in components_representatives.iter() {
         let edges_range = sccs.scc_data().ranges()[*scc_idx].clone();
         let edges = &sccs.scc_data().all_successors()[edges_range];
@@ -324,7 +325,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
         outlives_constraints: OutlivesConstraintSet<'tcx>,
         member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
-        universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
+        universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
         type_tests: Vec<TypeTest<'tcx>>,
         liveness_constraints: LivenessValues<RegionVid>,
         elements: &Rc<RegionValueElements>,
@@ -521,6 +522,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// outlives `'a` and hence contains R0 and R1.
     fn init_free_and_bound_regions(&mut self) {
         // Update the names (if any)
+        // This iterator has unstable order but we collect it all into an IndexVec
         for (external_name, variable) in self.universal_regions.named_universal_regions() {
             debug!(
                 "init_universal_regions: region {:?} has external name {:?}",
@@ -917,7 +919,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // Sometimes we register equivalent type-tests that would
         // result in basically the exact same error being reported to
         // the user. Avoid that.
-        let mut deduplicate_errors = FxHashSet::default();
+        let mut deduplicate_errors = FxIndexSet::default();
 
         for type_test in &self.type_tests {
             debug!("check_type_test: {:?}", type_test);
@@ -1084,18 +1086,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         true
     }
 
-    /// When we promote a type test `T: 'r`, we have to convert the
-    /// type `T` into something we can store in a query result (so
-    /// something allocated for `'tcx`). This is problematic if `ty`
-    /// contains regions. During the course of NLL region checking, we
-    /// will have replaced all of those regions with fresh inference
-    /// variables. To create a test subject, we want to replace those
-    /// inference variables with some region from the closure
-    /// signature -- this is not always possible, so this is a
-    /// fallible process. Presuming we do find a suitable region, we
-    /// will use it's *external name*, which will be a `RegionKind`
-    /// variant that can be used in query responses such as
-    /// `ReEarlyBound`.
+    /// When we promote a type test `T: 'r`, we have to replace all region
+    /// variables in the type `T` with an equal universal region from the
+    /// closure signature.
+    /// This is not always possible, so this is a fallible process.
     #[instrument(level = "debug", skip(self, infcx))]
     fn try_promote_type_test_subject(
         &self,
@@ -1104,91 +1098,63 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> Option<ClosureOutlivesSubject<'tcx>> {
         let tcx = infcx.tcx;
 
+        // Opaque types' substs may include useless lifetimes.
+        // We will replace them with ReStatic.
+        struct OpaqueFolder<'tcx> {
+            tcx: TyCtxt<'tcx>,
+        }
+        impl<'tcx> ty::TypeFolder<TyCtxt<'tcx>> for OpaqueFolder<'tcx> {
+            fn interner(&self) -> TyCtxt<'tcx> {
+                self.tcx
+            }
+            fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+                use ty::TypeSuperFoldable as _;
+                let tcx = self.tcx;
+                let &ty::Alias(ty::Opaque, ty::AliasTy { substs, def_id, .. }) = t.kind() else {
+                    return t.super_fold_with(self);
+                };
+                let substs =
+                    std::iter::zip(substs, tcx.variances_of(def_id)).map(|(arg, v)| {
+                        match (arg.unpack(), v) {
+                            (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => {
+                                tcx.lifetimes.re_static.into()
+                            }
+                            _ => arg.fold_with(self),
+                        }
+                    });
+                tcx.mk_opaque(def_id, tcx.mk_substs_from_iter(substs))
+            }
+        }
+
+        let ty = ty.fold_with(&mut OpaqueFolder { tcx });
+
         let ty = tcx.fold_regions(ty, |r, _depth| {
-            let region_vid = self.to_region_vid(r);
+            let r_vid = self.to_region_vid(r);
+            let r_scc = self.constraint_sccs.scc(r_vid);
 
             // The challenge if this. We have some region variable `r`
             // whose value is a set of CFG points and universal
             // regions. We want to find if that set is *equivalent* to
             // any of the named regions found in the closure.
-            //
-            // To do so, we compute the
-            // `non_local_universal_upper_bound`. This will be a
-            // non-local, universal region that is greater than `r`.
-            // However, it might not be *contained* within `r`, so
-            // then we further check whether this bound is contained
-            // in `r`. If so, we can say that `r` is equivalent to the
-            // bound.
-            //
-            // Let's work through a few examples. For these, imagine
-            // that we have 3 non-local regions (I'll denote them as
-            // `'static`, `'a`, and `'b`, though of course in the code
-            // they would be represented with indices) where:
-            //
-            // - `'static: 'a`
-            // - `'static: 'b`
-            //
-            // First, let's assume that `r` is some existential
-            // variable with an inferred value `{'a, 'static}` (plus
-            // some CFG nodes). In this case, the non-local upper
-            // bound is `'static`, since that outlives `'a`. `'static`
-            // is also a member of `r` and hence we consider `r`
-            // equivalent to `'static` (and replace it with
-            // `'static`).
-            //
-            // Now let's consider the inferred value `{'a, 'b}`. This
-            // means `r` is effectively `'a | 'b`. I'm not sure if
-            // this can come about, actually, but assuming it did, we
-            // would get a non-local upper bound of `'static`. Since
-            // `'static` is not contained in `r`, we would fail to
-            // find an equivalent.
-            let upper_bound = self.non_local_universal_upper_bound(region_vid);
-            if self.region_contains(region_vid, upper_bound) {
-                self.definitions[upper_bound].external_name.unwrap_or(r)
-            } else {
-                // In the case of a failure, use a `ReVar` result. This will
-                // cause the `needs_infer` later on to return `None`.
-                r
-            }
+            // To do so, we simply check every candidate `u_r` for equality.
+            self.scc_values
+                .universal_regions_outlived_by(r_scc)
+                .filter(|&u_r| !self.universal_regions.is_local_free_region(u_r))
+                .find(|&u_r| self.eval_equal(u_r, r_vid))
+                .map(|u_r| tcx.mk_re_var(u_r))
+                // In the case of a failure, use `ReErased`. We will eventually
+                // return `None` in this case.
+                .unwrap_or(tcx.lifetimes.re_erased)
         });
 
         debug!("try_promote_type_test_subject: folded ty = {:?}", ty);
 
-        // `needs_infer` will only be true if we failed to promote some region.
-        if ty.needs_infer() {
+        // This will be true if we failed to promote some region.
+        if ty.has_erased_regions() {
             return None;
         }
 
-        Some(ClosureOutlivesSubject::Ty(ty))
-    }
-
-    /// Given some universal or existential region `r`, finds a
-    /// non-local, universal region `r+` that outlives `r` at entry to (and
-    /// exit from) the closure. In the worst case, this will be
-    /// `'static`.
-    ///
-    /// This is used for two purposes. First, if we are propagated
-    /// some requirement `T: r`, we can use this method to enlarge `r`
-    /// to something we can encode for our creator (which only knows
-    /// about non-local, universal regions). It is also used when
-    /// encoding `T` as part of `try_promote_type_test_subject` (see
-    /// that fn for details).
-    ///
-    /// This is based on the result `'y` of `universal_upper_bound`,
-    /// except that it converts further takes the non-local upper
-    /// bound of `'y`, so that the final result is non-local.
-    fn non_local_universal_upper_bound(&self, r: RegionVid) -> RegionVid {
-        debug!("non_local_universal_upper_bound(r={:?}={})", r, self.region_value_str(r));
-
-        let lub = self.universal_upper_bound(r);
-
-        // Grow further to get smallest universal region known to
-        // creator.
-        let non_local_lub = self.universal_region_relations.non_local_upper_bound(lub);
-
-        debug!("non_local_universal_upper_bound: non_local_lub={:?}", non_local_lub);
-
-        non_local_lub
+        Some(ClosureOutlivesSubject::Ty(ClosureOutlivesSubjectTy::bind(tcx, ty)))
     }
 
     /// Returns a universally quantified region that outlives the
@@ -1539,6 +1505,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         // the outlives suggestions or the debug output from `#[rustc_regions]` would be
         // duplicated. The polonius subset errors are deduplicated here, while keeping the
         // CFG-location ordering.
+        // We can iterate the HashMap here because the result is sorted afterwards.
+        #[allow(rustc::potential_query_instability)]
         let mut subset_errors: Vec<_> = polonius_output
             .subset_errors
             .iter()
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index c550e37c63e..ec4b2e9d3e4 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::vec_map::VecMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::LocalDefId;
@@ -65,7 +65,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> VecMap<LocalDefId, OpaqueHiddenType<'tcx>> {
         let mut result: VecMap<LocalDefId, OpaqueHiddenType<'tcx>> = VecMap::new();
 
-        let member_constraints: FxHashMap<_, _> = self
+        let member_constraints: FxIndexMap<_, _> = self
             .member_constraints
             .all_indices()
             .map(|ci| (self.member_constraints[ci].key, ci))
@@ -364,7 +364,7 @@ fn check_opaque_type_parameter_valid(
         OpaqueTyOrigin::TyAlias => {}
     }
     let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
-    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+    let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::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(_)),
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 167f6646096..23a59c12865 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -3,7 +3,7 @@
 use crate::constraints::ConstraintSccIndex;
 use crate::RegionInferenceContext;
 use itertools::Itertools;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::graph::vec_graph::VecGraph;
 use rustc_data_structures::graph::WithSuccessors;
 use rustc_middle::ty::RegionVid;
@@ -14,7 +14,7 @@ pub(crate) struct ReverseSccGraph {
     graph: VecGraph<ConstraintSccIndex>,
     /// For each SCC, the range of `universal_regions` that use that SCC as
     /// their value.
-    scc_regions: FxHashMap<ConstraintSccIndex, Range<usize>>,
+    scc_regions: FxIndexMap<ConstraintSccIndex, Range<usize>>,
     /// All of the universal regions, in grouped so that `scc_regions` can
     /// index into here.
     universal_regions: Vec<RegionVid>,
@@ -26,7 +26,7 @@ impl ReverseSccGraph {
         &'a self,
         scc0: ConstraintSccIndex,
     ) -> impl Iterator<Item = RegionVid> + 'a {
-        let mut duplicates = FxHashSet::default();
+        let mut duplicates = FxIndexSet::default();
         self.graph
             .depth_first_search(scc0)
             .flat_map(move |scc1| {
@@ -55,7 +55,7 @@ impl RegionInferenceContext<'_> {
         paired_scc_regions.sort();
         let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
 
-        let mut scc_regions = FxHashMap::default();
+        let mut scc_regions = FxIndexMap::default();
         let mut start = 0;
         for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) {
             let group_size = group.count();
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 504633c6a5c..a9356135006 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -116,7 +116,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
             let subject = match outlives_requirement.subject {
                 ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
-                ClosureOutlivesSubject::Ty(ty) => ty.into(),
+                ClosureOutlivesSubject::Ty(subject_ty) => {
+                    subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
+                }
             };
 
             self.category = outlives_requirement.category;
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index e2f897a89e8..4004966c40a 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -93,31 +93,6 @@ impl UniversalRegionRelations<'_> {
         res
     }
 
-    /// Returns the "postdominating" bound of the set of
-    /// `non_local_upper_bounds` for the given region.
-    pub(crate) fn non_local_upper_bound(&self, fr: RegionVid) -> RegionVid {
-        let upper_bounds = self.non_local_upper_bounds(fr);
-
-        // In case we find more than one, reduce to one for
-        // convenience. This is to prevent us from generating more
-        // complex constraints, but it will cause spurious errors.
-        let post_dom = self.inverse_outlives.mutual_immediate_postdominator(upper_bounds);
-
-        debug!("non_local_bound: post_dom={:?}", post_dom);
-
-        post_dom
-            .and_then(|post_dom| {
-                // If the mutual immediate postdom is not local, then
-                // there is no non-local result we can return.
-                if !self.universal_regions.is_local_free_region(post_dom) {
-                    Some(post_dom)
-                } else {
-                    None
-                }
-            })
-            .unwrap_or(self.universal_regions.fr_static)
-    }
-
     /// Finds a "lower bound" for `fr` that is not local. In other
     /// words, returns the largest (*) known region `fr1` that (a) is
     /// outlived by `fr` and (b) is not local.
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 717020ea5b8..17e702eb8c5 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -19,7 +19,7 @@ use super::{Locations, TypeChecker};
 
 impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     /// Check explicit closure signature annotation,
-    /// e.g., `|x: FxHashMap<_, &'static u32>| ...`.
+    /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`.
     #[instrument(skip(self, body), level = "debug")]
     pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) {
         let mir_def_id = body.source.def_id().expect_local();
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 473c0596300..a687d3f5352 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_index::bit_set::HybridBitSet;
 use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
@@ -56,7 +56,7 @@ pub(super) fn trace<'mir, 'tcx>(
         elements,
         local_use_map,
         move_data,
-        drop_data: FxHashMap::default(),
+        drop_data: FxIndexMap::default(),
     };
 
     let mut results = LivenessResults::new(cx);
@@ -85,7 +85,7 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
     move_data: &'me MoveData<'tcx>,
 
     /// Cache for the results of `dropck_outlives` query.
-    drop_data: FxHashMap<Ty<'tcx>, DropData<'tcx>>,
+    drop_data: FxIndexMap<Ty<'tcx>, DropData<'tcx>>,
 
     /// Results of dataflow tracking which variables (and paths) have been
     /// initialized.
@@ -185,7 +185,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> {
     fn add_extra_drop_facts(
         &mut self,
         drop_used: Vec<(Local, Location)>,
-        relevant_live_locals: FxHashSet<Local>,
+        relevant_live_locals: FxIndexSet<Local>,
     ) {
         let locations = IntervalSet::new(self.cx.elements.num_points());
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a49da3da6c0..06c7b8b8f87 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -9,7 +9,7 @@ use either::Either;
 
 use hir::OpaqueTyOrigin;
 use rustc_data_structures::frozen::Frozen;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -145,7 +145,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
         outlives_constraints: OutlivesConstraintSet::default(),
         member_constraints: MemberConstraintSet::default(),
         type_tests: Vec::default(),
-        universe_causes: FxHashMap::default(),
+        universe_causes: FxIndexMap::default(),
     };
 
     let CreateResult {
@@ -875,7 +875,7 @@ struct TypeChecker<'a, 'tcx> {
     user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
     region_bound_pairs: &'a RegionBoundPairs<'tcx>,
     implicit_region_bound: ty::Region<'tcx>,
-    reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
+    reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
     borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
 }
 
@@ -925,7 +925,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
 
     pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
 
-    pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
+    pub(crate) universe_causes: FxIndexMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
 
     pub(crate) type_tests: Vec<TypeTest<'tcx>>,
 }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 15d7613a812..68c86051364 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -22,9 +22,7 @@ use rustc_hir::BodyOwnerKind;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{
-    self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_span::Symbol;
 use std::iter;
@@ -314,6 +312,9 @@ impl<'tcx> UniversalRegions<'tcx> {
     }
 
     /// Gets an iterator over all the early-bound regions that have names.
+    /// Iteration order may be unstable, so this should only be used when
+    /// iteration order doesn't affect anything
+    #[allow(rustc::potential_query_instability)]
     pub fn named_universal_regions<'s>(
         &'s self,
     ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's {
diff --git a/compiler/rustc_borrowck/src/used_muts.rs b/compiler/rustc_borrowck/src/used_muts.rs
index e297b1230ea..18dbe24d3b8 100644
--- a/compiler/rustc_borrowck/src/used_muts.rs
+++ b/compiler/rustc_borrowck/src/used_muts.rs
@@ -1,6 +1,6 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,
@@ -26,8 +26,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     ///  See #55344 for context.
     pub(crate) fn gather_used_muts(
         &mut self,
-        temporary_used_locals: FxHashSet<Local>,
-        mut never_initialized_mut_locals: FxHashSet<Local>,
+        temporary_used_locals: FxIndexSet<Local>,
+        mut never_initialized_mut_locals: FxIndexSet<Local>,
     ) {
         {
             let mut visitor = GatherUsedMutsVisitor {
@@ -48,8 +48,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 /// MIR visitor for collecting used mutable variables.
 /// The 'visit lifetime represents the duration of the MIR walk.
 struct GatherUsedMutsVisitor<'visit, 'cx, 'tcx> {
-    temporary_used_locals: FxHashSet<Local>,
-    never_initialized_mut_locals: &'visit mut FxHashSet<Local>,
+    temporary_used_locals: FxIndexSet<Local>,
+    never_initialized_mut_locals: &'visit mut FxIndexSet<Local>,
     mbcx: &'visit mut MirBorrowckCtxt<'cx, 'tcx>,
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index e74aabf2fcb..24f8d5e464e 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -281,8 +281,12 @@ fn codegen_float_intrinsic_call<'tcx>(
         sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64),
         sym::truncf32 => ("truncf", 1, fx.tcx.types.f32),
         sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
+        sym::rintf32 => ("rintf", 1, fx.tcx.types.f32),
+        sym::rintf64 => ("rint", 1, fx.tcx.types.f64),
         sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
         sym::roundf64 => ("round", 1, fx.tcx.types.f64),
+        sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32),
+        sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64),
         sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
         sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
         sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 2590e0e3af4..94dc8c9e93b 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -79,6 +79,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) ->
         sym::nearbyintf64 => "nearbyint",
         sym::roundf32 => "roundf",
         sym::roundf64 => "round",
+        sym::roundevenf32 => "roundevenf",
+        sym::roundevenf64 => "roundeven",
         sym::abort => "abort",
         _ => return None,
     };
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3d29968d5d6..f0d729d4779 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -735,9 +735,13 @@ impl<'ll> CodegenCx<'ll, '_> {
 
         ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
+
         ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
 
+        ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
+        ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
+
         ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
         ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 5cd0e1cb63a..6bcd3e5bf58 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -5,7 +5,7 @@ use super::CodegenUnitDebugContext;
 
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, Ty};
 use trace;
 
 use crate::common::CodegenCx;
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 39afb4af6f6..9c921989ca9 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -71,6 +71,8 @@ fn get_simple_intrinsic<'ll>(
         sym::roundf32 => "llvm.round.f32",
         sym::roundf64 => "llvm.round.f64",
         sym::ptr_mask => "llvm.ptrmask",
+        sym::roundevenf32 => "llvm.roundeven.f32",
+        sym::roundevenf64 => "llvm.roundeven.f64",
         _ => return None,
     };
     Some(cx.get_intrinsic(llvm_name))
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index 019ec0758d6..4ab56699922 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -306,7 +306,13 @@ pub fn create_compressed_metadata_file(
     symbol_name: &str,
 ) -> Vec<u8> {
     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
+    // Our length will be backfilled once we're done writing
+    compressed.write_all(&[0; 4]).unwrap();
     FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
+    let meta_len = rustc_metadata::METADATA_HEADER.len();
+    let data_len = (compressed.len() - meta_len - 4) as u32;
+    compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
+
     let Some(mut file) = create_object_file(sess) else {
         return compressed.to_vec();
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 067a3e167fe..fd81b1c6fe1 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -11,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::Instance;
-use rustc_middle::ty::{self, DefIdTree, SymbolName, TyCtxt};
+use rustc_middle::ty::{self, SymbolName, TyCtxt};
 use rustc_session::config::{CrateType, OomStrategy};
 use rustc_target::spec::SanitizerSet;
 
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 7d5c0048626..c62968e5354 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -8,7 +8,7 @@ use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self as ty, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self as ty, TyCtxt};
 use rustc_session::{lint, parse::feature_err};
 use rustc_span::{sym, Span};
 use rustc_target::spec::{abi, SanitizerSet};
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index e59fad99ad7..4301e4fe69b 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 9eaab1f47a7..6dcfdc14790 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -1,15 +1,22 @@
+use rustc_attr as attr;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
 
-/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
-pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
+/// Whether the `def_id` is an unstable const fn and what feature gate(s) are necessary to enable
+/// it.
+pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<(Symbol, Option<Symbol>)> {
     if tcx.is_const_fn_raw(def_id) {
         let const_stab = tcx.lookup_const_stability(def_id)?;
-        if const_stab.is_const_unstable() { Some(const_stab.feature) } else { None }
+        match const_stab.level {
+            attr::StabilityLevel::Unstable { implied_by, .. } => {
+                Some((const_stab.feature, implied_by))
+            }
+            attr::StabilityLevel::Stable { .. } => None,
+        }
     } else {
         None
     }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 2be5ed896ec..c14152a916a 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -67,12 +67,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Pointer(PointerCast::ReifyFnPointer) => {
+                // All reifications must be monomorphic, bail out otherwise.
+                ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
+
                 // The src operand does not matter, just its type
                 match *src.layout.ty.kind() {
                     ty::FnDef(def_id, substs) => {
-                        // All reifications must be monomorphic, bail out otherwise.
-                        ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
-
                         let instance = ty::Instance::resolve_for_fn_ptr(
                             *self.tcx,
                             self.param_env,
@@ -100,12 +100,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Pointer(PointerCast::ClosureFnPointer(_)) => {
+                // All reifications must be monomorphic, bail out otherwise.
+                ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
+
                 // The src operand does not matter, just its type
                 match *src.layout.ty.kind() {
                     ty::Closure(def_id, substs) => {
-                        // All reifications must be monomorphic, bail out otherwise.
-                        ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
-
                         let instance = ty::Instance::resolve_closure(
                             *self.tcx,
                             def_id,
@@ -359,8 +359,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
                 self.write_immediate(val, dest)
             }
-
             _ => {
+                // Do not ICE if we are not monomorphic enough.
+                ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
+                ensure_monomorphic_enough(*self.tcx, cast_ty)?;
+
                 span_bug!(
                     self.cur_span(),
                     "invalid pointer unsizing {:?} -> {:?}",
@@ -404,12 +407,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
                 Ok(())
             }
-            _ => span_bug!(
-                self.cur_span(),
-                "unsize_into: invalid conversion: {:?} -> {:?}",
-                src.layout,
-                dest.layout
-            ),
+            _ => {
+                // Do not ICE if we are not monomorphic enough.
+                ensure_monomorphic_enough(*self.tcx, src.layout.ty)?;
+                ensure_monomorphic_enough(*self.tcx, cast_ty.ty)?;
+
+                span_bug!(
+                    self.cur_span(),
+                    "unsize_into: invalid conversion: {:?} -> {:?}",
+                    src.layout,
+                    dest.layout
+                )
+            }
         }
     }
 }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 3db102e484d..39c74191258 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -7,7 +7,7 @@ use either::{Either, Left, Right};
 use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidProgramInfo};
+use rustc_middle::mir::interpret::{ErrorHandled, InterpError};
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
     TyAndLayout,
@@ -508,14 +508,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         frame
             .instance
             .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
-            .map_err(|e| {
-                self.tcx.sess.delay_span_bug(
-                    self.cur_span(),
-                    format!("failed to normalize {}", e.get_type_for_failure()).as_str(),
-                );
-
-                InterpError::InvalidProgram(InvalidProgramInfo::TooGeneric)
-            })
+            .map_err(|_| err_inval!(TooGeneric))
     }
 
     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
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 aa24d9053b9..cc3aa84bd71 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -926,15 +926,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
 
                 // If the `const fn` we are trying to call is not const-stable, ensure that we have
                 // the proper feature gate enabled.
-                if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+                if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
                     trace!(?gate, "calling unstable const fn");
                     if self.span.allows_unstable(gate) {
                         return;
                     }
+                    if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
+                        return;
+                    }
 
                     // Calling an unstable function *always* requires that the corresponding gate
-                    // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
-                    if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
+                    // (or implied gate) be enabled, even if the function has
+                    // `#[rustc_allow_const_fn_unstable(the_gate)]`.
+                    let gate_declared = |gate| {
+                        tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
+                    };
+                    let feature_gate_declared = gate_declared(gate);
+                    let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
+                    if !feature_gate_declared && !implied_gate_declared {
                         self.check_op(ops::FnCallUnstable(callee, Some(gate)));
                         return;
                     }
@@ -947,7 +956,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                     }
 
                     // Otherwise, we are something const-stable calling a const-unstable fn.
-
                     if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
                         trace!("rustc_allow_const_fn_unstable gate active");
                         return;
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 3e416b89ca6..e586720a0d0 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -12,9 +12,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{
-    suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty,
-};
+use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
 use rustc_middle::ty::{Binder, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index fb37eb79a33..272fe3d1b31 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -72,6 +72,17 @@ impl<'tcx> MirPass<'tcx> for Validator {
         };
         checker.visit_body(body);
         checker.check_cleanup_control_flow();
+
+        if let MirPhase::Runtime(_) = body.phase {
+            if let ty::InstanceDef::Item(_) = body.source.instance {
+                if body.has_free_regions() {
+                    checker.fail(
+                        Location::START,
+                        format!("Free regions in optimized {} MIR", body.phase.name()),
+                    );
+                }
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 211bbf4f50e..1b2e7b7e083 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1895,7 +1895,7 @@ impl EmitterWriter {
                         self.draw_code_line(
                             &mut buffer,
                             &mut row_num,
-                            &Vec::new(),
+                            &[],
                             p + line_start,
                             l,
                             show_code_change,
@@ -1919,7 +1919,7 @@ impl EmitterWriter {
                             self.draw_code_line(
                                 &mut buffer,
                                 &mut row_num,
-                                &Vec::new(),
+                                &[],
                                 p + line_start,
                                 l,
                                 show_code_change,
@@ -1936,7 +1936,7 @@ impl EmitterWriter {
                             self.draw_code_line(
                                 &mut buffer,
                                 &mut row_num,
-                                &Vec::new(),
+                                &[],
                                 p + line_start,
                                 l,
                                 show_code_change,
@@ -1951,7 +1951,7 @@ impl EmitterWriter {
                 self.draw_code_line(
                     &mut buffer,
                     &mut row_num,
-                    highlight_parts,
+                    &highlight_parts,
                     line_pos + line_start,
                     line,
                     show_code_change,
@@ -2176,7 +2176,7 @@ impl EmitterWriter {
         &self,
         buffer: &mut StyledBuffer,
         row_num: &mut usize,
-        highlight_parts: &Vec<SubstitutionHighlight>,
+        highlight_parts: &[SubstitutionHighlight],
         line_num: usize,
         line_to_add: &str,
         show_code_change: DisplaySuggestion,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index cbf595089cc..99af872f07f 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -331,7 +331,7 @@ impl CodeSuggestion {
                     });
                     buf.push_str(&part.snippet);
                     let cur_hi = sm.lookup_char_pos(part.span.hi());
-                    if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line {
+                    if cur_hi.line == cur_lo.line {
                         // Account for the difference between the width of the current code and the
                         // snippet being suggested, so that the *later* suggestions are correctly
                         // aligned on the screen.
diff --git a/compiler/rustc_hir_analysis/locales/en-US.ftl b/compiler/rustc_hir_analysis/locales/en-US.ftl
index 1d313945b52..50e857ef60d 100644
--- a/compiler/rustc_hir_analysis/locales/en-US.ftl
+++ b/compiler/rustc_hir_analysis/locales/en-US.ftl
@@ -155,3 +155,11 @@ hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
 hir_analysis_cannot_capture_late_bound_const_in_anon_const =
     cannot capture late-bound const parameter in a constant
     .label = parameter defined here
+
+hir_analysis_variances_of = {$variances_of}
+
+hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
+    .suggestion = cast the value to `{$cast_ty}`
+    .help = cast the value to `{$cast_ty}`
+
+hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index f5ce02c9e61..899029d98e0 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -35,7 +35,7 @@ use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
 use rustc_middle::ty::DynKind;
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, Const, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 848828175e2..3449d3d439d 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -22,8 +22,7 @@ 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, AdtDef, DefIdTree, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt,
+    self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
@@ -1511,6 +1510,14 @@ fn opaque_type_cycle_error(
                     {
                         label_match(interior_ty.ty, interior_ty.span);
                     }
+                    if tcx.sess.opts.unstable_opts.drop_tracking_mir
+                        && let DefKind::Generator = tcx.def_kind(closure_def_id)
+                    {
+                        let generator_layout = tcx.mir_generator_witnesses(closure_def_id);
+                        for interior_ty in &generator_layout.field_tys {
+                            label_match(interior_ty.ty, interior_ty.source_info.span);
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 691d3f8d942..5adc7a87323 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -16,8 +16,7 @@ use rustc_infer::traits::util;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::util::ExplicitSelf;
 use rustc_middle::ty::{
-    self, DefIdTree, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
+    self, InternalSubsts, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
 use rustc_span::Span;
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 054284cced5..20b6561f8b2 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -300,6 +300,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
             sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
             sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64),
 
             sym::volatile_load | sym::unaligned_volatile_load => {
                 (1, vec![tcx.mk_imm_ptr(param(0))], param(0))
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 1f2de3f21f8..47c47de8ced 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -478,10 +478,6 @@ fn lint_auto_trait_impl<'tcx>(
     trait_ref: ty::TraitRef<'tcx>,
     impl_def_id: LocalDefId,
 ) {
-    if tcx.impl_polarity(impl_def_id) != ImplPolarity::Positive {
-        return;
-    }
-
     assert_eq!(trait_ref.substs.len(), 1);
     let self_ty = trait_ref.self_ty();
     let (self_type_did, substs) = match self_ty.kind() {
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 9cf3ff65a91..6f6f993f727 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -3,7 +3,7 @@ use crate::astconv::AstConv;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 65a9052a60a..e9963e67741 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -17,7 +17,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_session::lint;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 50073d94ea5..7fc0711a155 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{
-    self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
@@ -344,8 +344,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
                     in_trait,
                     ..
                 }) => {
-                    if in_trait {
-                        assert!(tcx.impl_defaultness(owner).has_value());
+                    if in_trait && !tcx.impl_defaultness(owner).has_value() {
+                        span_bug!(tcx.def_span(def_id), "tried to get type of this RPITIT with no definition");
                     }
                     find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
                 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 3e069275775..74fec93d91e 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -399,3 +399,34 @@ pub(crate) enum CannotCaptureLateBoundInAnonConst {
         def_span: Span,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_variances_of)]
+pub(crate) struct VariancesOf {
+    #[primary_span]
+    pub span: Span,
+    pub variances_of: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_pass_to_variadic_function, code = "E0617")]
+pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
+    #[primary_span]
+    pub span: Span,
+    pub ty: Ty<'tcx>,
+    pub cast_ty: &'a str,
+    #[suggestion(code = "{replace}", applicability = "machine-applicable")]
+    pub sugg_span: Option<Span>,
+    pub replace: String,
+    #[help]
+    pub help: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = "E0607")]
+pub(crate) struct CastThinPointerToFatPointer<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub expr_ty: Ty<'tcx>,
+    pub cast_ty: String,
+}
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index a8b33c74bc1..d53c429ca15 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -1,7 +1,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
 use rustc_span::Span;
 
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 089491bef5e..0bfbf99cb0b 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -1,5 +1,5 @@
-use crate::structured_errors::StructuredDiagnostic;
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
+use crate::{errors, structured_errors::StructuredDiagnostic};
+use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
 use rustc_middle::ty::{Ty, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::Span;
@@ -21,27 +21,26 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
     }
 
     fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = self.sess.struct_span_err_with_code(
-            self.span,
-            &format!("can't pass `{}` to variadic function", self.ty),
-            self.code(),
-        );
+        let (sugg_span, replace, help) =
+            if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
+                (Some(self.span), format!("{} as {}", snippet, self.cast_ty), None)
+            } else {
+                (None, "".to_string(), Some(()))
+            };
+
+        let mut err = self.sess.create_err(errors::PassToVariadicFunction {
+            span: self.span,
+            ty: self.ty,
+            cast_ty: self.cast_ty,
+            help,
+            replace,
+            sugg_span,
+        });
 
         if self.ty.references_error() {
             err.downgrade_to_delayed_bug();
         }
 
-        if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
-            err.span_suggestion(
-                self.span,
-                &format!("cast the value to `{}`", self.cast_ty),
-                format!("{} as {}", snippet, self.cast_ty),
-                Applicability::MachineApplicable,
-            );
-        } else {
-            err.help(&format!("cast the value to `{}`", self.cast_ty));
-        }
-
         err
     }
 
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index 3b9fb367813..910417abe6e 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
@@ -1,4 +1,4 @@
-use crate::structured_errors::StructuredDiagnostic;
+use crate::{errors, structured_errors::StructuredDiagnostic};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorGuaranteed};
 use rustc_middle::ty::{Ty, TypeVisitableExt};
 use rustc_session::Session;
@@ -21,14 +21,11 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
     }
 
     fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        let mut err = self.sess.struct_span_err_with_code(
-            self.span,
-            &format!(
-                "cannot cast thin pointer `{}` to fat pointer `{}`",
-                self.expr_ty, self.cast_ty
-            ),
-            self.code(),
-        );
+        let mut err = self.sess.create_err(errors::CastThinPointerToFatPointer {
+            span: self.span,
+            expr_ty: self.expr_ty,
+            cast_ty: self.cast_ty.to_owned(),
+        });
 
         if self.expr_ty.references_error() {
             err.downgrade_to_delayed_bug();
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 5d5c8ca604a..a8b7699b667 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
-use rustc_middle::ty::{DefIdTree, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
 use std::ops::ControlFlow;
 
 /// Defines the `TermsContext` basically houses an arena where we can
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index 5feeb92d337..64614831f56 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -1,6 +1,8 @@
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::sym;
 
+use crate::errors;
+
 pub fn test_variance(tcx: TyCtxt<'_>) {
     // For unit testing: check for a special "rustc_variance"
     // attribute and report an error with various results if found.
@@ -8,7 +10,10 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
         if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
             let variances_of = tcx.variances_of(id.owner_id);
 
-            tcx.sess.struct_span_err(tcx.def_span(id.owner_id), format!("{variances_of:?}")).emit();
+            tcx.sess.emit_err(errors::VariancesOf {
+                span: tcx.def_span(id.owner_id),
+                variances_of: format!("{variances_of:?}"),
+            });
         }
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 60e55c7b0cf..a8f8121153f 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -25,7 +25,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, TyCtxt, UserType,
+    self, AdtKind, CanonicalUserType, GenericParamDefKind, Ty, TyCtxt, UserType,
 };
 use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
 use rustc_session::lint;
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index b09886fe3a9..ec14bd3c6f4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -3,9 +3,7 @@ use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::{
-    self, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_span::{self, Span};
 use rustc_trait_selection::traits;
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index a46bdeb417d..ea54b76bdec 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -28,7 +28,7 @@ use rustc_infer::infer::InferOk;
 use rustc_infer::infer::TypeTrace;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty};
+use rustc_middle::ty::{self, IsSuggestable, Ty};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{self, sym, Span};
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index c49621b7c24..690d8a23826 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::{self, StatementAsExpression};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, suggest_constraining_type_params, Binder, DefIdTree, IsSuggestable, ToPredicate, Ty,
+    self, suggest_constraining_type_params, Binder, IsSuggestable, ToPredicate, Ty,
     TypeVisitableExt,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
@@ -669,6 +669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// This routine checks if the return type is left as default, the method is not part of an
     /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
     /// type.
+    #[instrument(level = "trace", skip(self, err))]
     pub(in super::super) fn suggest_missing_return_type(
         &self,
         err: &mut Diagnostic,
@@ -705,28 +706,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return true
                 }
             }
-            hir::FnRetTy::Return(ty) => {
-                let span = ty.span;
-
-                if let hir::TyKind::OpaqueDef(item_id, ..) = ty.kind
-                && let hir::Node::Item(hir::Item {
-                    kind: hir::ItemKind::OpaqueTy(op_ty),
-                    ..
-                }) = self.tcx.hir().get(item_id.hir_id())
-                && let hir::OpaqueTy {
-                    bounds: [bound], ..
-                } = op_ty
-                && let hir::GenericBound::LangItemTrait(
-                    hir::LangItem::Future, _, _, generic_args) = bound
-                && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
-                && let hir::TypeBinding { kind, .. } = ty_binding
-                && let hir::TypeBindingKind::Equality { term } = kind
-                && let hir::Term::Ty(term_ty) = term {
+            hir::FnRetTy::Return(hir_ty) => {
+                let span = hir_ty.span;
+
+                if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
+                    && let hir::Node::Item(hir::Item {
+                        kind: hir::ItemKind::OpaqueTy(op_ty),
+                        ..
+                    }) = self.tcx.hir().get(item_id.hir_id())
+                    && let [hir::GenericBound::LangItemTrait(
+                        hir::LangItem::Future, _, _, generic_args)] = op_ty.bounds
+                    && let hir::GenericArgs { bindings: [ty_binding], .. } = generic_args
+                    && let hir::TypeBindingKind::Equality { term: hir::Term::Ty(term) } = ty_binding.kind
+                {
                     // Check if async function's return type was omitted.
                     // Don't emit suggestions if the found type is `impl Future<...>`.
-                    debug!("suggest_missing_return_type: found = {:?}", found);
+                    debug!(?found);
                     if found.is_suggestable(self.tcx, false) {
-                        if term_ty.span.is_empty() {
+                        if term.span.is_empty() {
                             err.subdiagnostic(AddReturnTypeSuggestion::Add { span, found: found.to_string() });
                             return true;
                         } else {
@@ -737,11 +734,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // Only point to return type if the expected type is the return type, as if they
                 // are not, the expectation must have been caused by something else.
-                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let ty = self.astconv().ast_ty_to_ty(ty);
-                debug!("suggest_missing_return_type: return type {:?}", ty);
-                debug!("suggest_missing_return_type: expected type {:?}", ty);
-                let bound_vars = self.tcx.late_bound_vars(fn_id);
+                debug!("return type {:?}", hir_ty);
+                let ty = self.astconv().ast_ty_to_ty(hir_ty);
+                debug!("return type {:?}", ty);
+                debug!("expected type {:?}", expected);
+                let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into());
                 let ty = Binder::bind_with_vars(ty, bound_vars);
                 let ty = self.normalize(span, ty);
                 let ty = self.tcx.erase_late_bound_regions(ty);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 60d56263d2e..e6d6586d5ee 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -27,7 +27,7 @@ use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
-use rustc_middle::ty::{self, DefIdTree, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
@@ -348,6 +348,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.downgrade_to_delayed_bug();
         }
 
+        if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
+            err.help(&format!(
+                "method `poll` found on `Pin<&mut {ty_str}>`, \
+                see documentation for `std::pin::Pin`"
+            ));
+            err.help("self type must be pinned to call `Future::poll`, \
+                see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice"
+            );
+        }
+
         if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source {
             self.suggest_await_before_method(
                 &mut err, item_name, rcvr_ty, cal, span, expected.only_has_type(self),
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 80279ed969a..eecded557a5 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -13,7 +13,7 @@ use rustc_middle::ty::adjustment::{
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, DefIdTree, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, IsSuggestable, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
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 e242900fd23..a3151d2d365 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
@@ -17,7 +17,7 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
-use rustc_middle::ty::{self, DefIdTree, InferConst};
+use rustc_middle::ty::{self, InferConst};
 use rustc_middle::ty::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{IsSuggestable, Ty, TyCtxt, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident};
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 db4b8af4683..c5ef48fe3da 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, TypeVisitable};
+use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable};
 use rustc_span::Span;
 
 /// Information about the anonymous region we are searching for.
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bd1f96635a6..fb067e7ac21 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -94,10 +94,10 @@ pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
 /// call to `start_snapshot` and `rollback_to`.
 #[derive(Clone)]
 pub struct InferCtxtInner<'tcx> {
-    /// Cache for projections. This cache is snapshotted along with the infcx.
+    /// Cache for projections.
     ///
-    /// Public so that `traits::project` can use it.
-    pub projection_cache: traits::ProjectionCacheStorage<'tcx>,
+    /// This cache is snapshotted along with the infcx.
+    projection_cache: traits::ProjectionCacheStorage<'tcx>,
 
     /// We instantiate `UnificationTable` with `bounds<Ty>` because the types
     /// that might instantiate a general type variable have an order,
@@ -114,24 +114,26 @@ pub struct InferCtxtInner<'tcx> {
     float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
 
     /// Tracks the set of region variables and the constraints between them.
+    ///
     /// This is initially `Some(_)` but when
     /// `resolve_regions_and_report_errors` is invoked, this gets set to `None`
     /// -- further attempts to perform unification, etc., may fail if new
     /// region constraints would've been added.
     region_constraint_storage: Option<RegionConstraintStorage<'tcx>>,
 
-    /// A set of constraints that regionck must validate. Each
-    /// constraint has the form `T:'a`, meaning "some type `T` must
+    /// A set of constraints that regionck must validate.
+    ///
+    /// Each constraint has the form `T:'a`, meaning "some type `T` must
     /// outlive the lifetime 'a". These constraints derive from
     /// instantiated type parameters. So if you had a struct defined
-    /// like
+    /// like the following:
     /// ```ignore (illustrative)
-    ///     struct Foo<T:'static> { ... }
+    /// struct Foo<T: 'static> { ... }
     /// ```
-    /// then in some expression `let x = Foo { ... }` it will
+    /// In some expression `let x = Foo { ... }`, it will
     /// instantiate the type parameter `T` with a fresh type `$0`. At
     /// the same time, it will record a region obligation of
-    /// `$0:'static`. This will get checked later by regionck. (We
+    /// `$0: 'static`. This will get checked later by regionck. (We
     /// can't generally check these things right away because we have
     /// to wait until types are resolved.)
     ///
@@ -268,7 +270,7 @@ pub struct InferCtxt<'tcx> {
     /// Caches the results of trait evaluation.
     pub evaluation_cache: select::EvaluationCache<'tcx>,
 
-    /// the set of predicates on which errors have been reported, to
+    /// The set of predicates on which errors have been reported, to
     /// avoid reporting the same error twice.
     pub reported_trait_errors: RefCell<FxIndexMap<Span, Vec<ty::Predicate<'tcx>>>>,
 
@@ -291,7 +293,7 @@ pub struct InferCtxt<'tcx> {
     tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
 
     /// Track how many errors were reported when this infcx is created.
-    /// If the number of errors increases, that's also a sign (line
+    /// If the number of errors increases, that's also a sign (like
     /// `tainted_by_errors`) to avoid reporting certain kinds of errors.
     // FIXME(matthewjasper) Merge into `tainted_by_errors`
     err_count_on_creation: usize,
@@ -313,7 +315,7 @@ pub struct InferCtxt<'tcx> {
     /// During coherence we have to assume that other crates may add
     /// additional impls which we currently don't know about.
     ///
-    /// To deal with this evaluation should be conservative
+    /// To deal with this evaluation, we should be conservative
     /// and consider the possibility of impls from outside this crate.
     /// This comes up primarily when resolving ambiguity. Imagine
     /// there is some trait reference `$0: Bar` where `$0` is an
@@ -323,7 +325,7 @@ pub struct InferCtxt<'tcx> {
     /// bound to some type that in a downstream crate that implements
     /// `Bar`.
     ///
-    /// Outside of coherence we set this to false because we are only
+    /// Outside of coherence, we set this to false because we are only
     /// interested in types that the user could actually have written.
     /// In other words, we consider `$0: Bar` to be unimplemented if
     /// there is no type that the user could *actually name* that
@@ -373,7 +375,7 @@ pub enum SubregionOrigin<'tcx> {
     Subtype(Box<TypeTrace<'tcx>>),
 
     /// When casting `&'a T` to an `&'b Trait` object,
-    /// relating `'a` to `'b`
+    /// relating `'a` to `'b`.
     RelateObjectBound(Span),
 
     /// Some type parameter was instantiated with the given type,
@@ -384,7 +386,7 @@ pub enum SubregionOrigin<'tcx> {
     /// that must outlive some other region.
     RelateRegionParamBound(Span),
 
-    /// Creating a pointer `b` to contents of another reference
+    /// Creating a pointer `b` to contents of another reference.
     Reborrow(Span),
 
     /// (&'a &'b T) where a >= b
@@ -398,7 +400,7 @@ pub enum SubregionOrigin<'tcx> {
         trait_item_def_id: DefId,
     },
 
-    /// Checking that the bounds of a trait's associated type hold for a given impl
+    /// Checking that the bounds of a trait's associated type hold for a given impl.
     CheckAssociatedTypeBounds {
         parent: Box<SubregionOrigin<'tcx>>,
         impl_item_def_id: LocalDefId,
@@ -435,32 +437,33 @@ pub enum LateBoundRegionConversionTime {
     AssocTypeProjection(DefId),
 }
 
-/// Reasons to create a region inference variable
+/// Reasons to create a region inference variable.
 ///
-/// See `error_reporting` module for more details
+/// See `error_reporting` module for more details.
 #[derive(Copy, Clone, Debug)]
 pub enum RegionVariableOrigin {
-    /// Region variables created for ill-categorized reasons,
-    /// mostly indicates places in need of refactoring
+    /// Region variables created for ill-categorized reasons.
+    ///
+    /// They mostly indicate places in need of refactoring.
     MiscVariable(Span),
 
-    /// Regions created by a `&P` or `[...]` pattern
+    /// Regions created by a `&P` or `[...]` pattern.
     PatternRegion(Span),
 
-    /// Regions created by `&` operator
+    /// Regions created by `&` operator.
+    ///
     AddrOfRegion(Span),
-
-    /// Regions created as part of an autoref of a method receiver
+    /// Regions created as part of an autoref of a method receiver.
     Autoref(Span),
 
-    /// Regions created as part of an automatic coercion
+    /// Regions created as part of an automatic coercion.
     Coercion(Span),
 
-    /// Region variables created as the values for early-bound regions
+    /// Region variables created as the values for early-bound regions.
     EarlyBoundRegion(Span, Symbol),
 
     /// Region variables created for bound regions
-    /// in a function or method that is called
+    /// in a function or method that is called.
     LateBoundRegion(Span, ty::BoundRegionKind, LateBoundRegionConversionTime),
 
     UpvarRegion(ty::UpvarId, Span),
@@ -534,7 +537,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
     }
 }
 
-/// Used to configure inference contexts before their creation
+/// Used to configure inference contexts before their creation.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     defining_use_anchor: DefiningAnchor,
@@ -835,9 +838,9 @@ impl<'tcx> InferCtxt<'tcx> {
 
     /// Scan the constraints produced since `snapshot` began and returns:
     ///
-    /// - `None` -- if none of them involve "region outlives" constraints
-    /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder
-    /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders
+    /// - `None` -- if none of them involves "region outlives" constraints.
+    /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder.
+    /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders.
     pub fn region_constraints_added_in_snapshot(
         &self,
         snapshot: &CombinedSnapshot<'tcx>,
@@ -1770,7 +1773,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     }
 }
 
-/// Helper for `ty_or_const_infer_var_changed` (see comment on that), currently
+/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
 /// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
 #[derive(Copy, Clone, Debug)]
 pub enum TyOrConstInferVar<'tcx> {
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 85958c41705..7ca50f5a2db 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -17,7 +17,7 @@ use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{
-    self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
+    self, AdtKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map;
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 3a92f5806c9..c43162f6325 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -14,7 +14,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::util::elaborate_predicates_with_span;
 use rustc_middle::ty::adjustment;
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
 use rustc_span::{BytePos, Span};
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 46068f8c868..7fbe3bc2888 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -6,8 +6,8 @@ use crate::diagnostics::error::{
 };
 use crate::diagnostics::utils::{
     build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error,
-    should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap,
-    HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
+    should_generate_set_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo,
+    FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
 };
 use proc_macro2::{Ident, Span, TokenStream};
 use quote::{format_ident, quote};
@@ -414,12 +414,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                 Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
             SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
-                if type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) {
+                let inner = info.ty.inner_type();
+                if type_matches_path(inner, &["rustc_span", "Span"]) {
                     Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
-                } else if type_is_unit(info.ty.inner_type()) {
+                } else if type_is_unit(inner)
+                    || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner))
+                {
                     Ok(self.add_subdiagnostic(&fn_ident, slug))
                 } else {
-                    report_type_error(attr, "`Span` or `()`")?
+                    report_type_error(attr, "`Span`, `bool` or `()`")?
                 }
             }
             SubdiagnosticKind::Suggestion {
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 27b8f676f3f..65bb154d7f3 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -50,6 +50,11 @@ pub(crate) fn type_is_unit(ty: &Type) -> bool {
     if let Type::Tuple(TypeTuple { elems, .. }) = ty { elems.is_empty() } else { false }
 }
 
+/// Checks whether the type `ty` is `bool`.
+pub(crate) fn type_is_bool(ty: &Type) -> bool {
+    type_matches_path(ty, &["bool"])
+}
+
 /// Reports a type error for field with `attr`.
 pub(crate) fn report_type_error(
     attr: &Attribute,
@@ -192,6 +197,11 @@ impl<'ty> FieldInnerTy<'ty> {
                     #inner
                 }
             },
+            FieldInnerTy::Plain(t) if type_is_bool(t) => quote! {
+                if #binding {
+                    #inner
+                }
+            },
             FieldInnerTy::Plain(..) => quote! { #inner },
         }
     }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 755a2425350..c48e681eb94 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -789,6 +789,9 @@ fn get_metadata_section<'p>(
                 loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
             // The header is uncompressed
             let header_len = METADATA_HEADER.len();
+            // header + u32 length of data
+            let data_start = header_len + 4;
+
             debug!("checking {} bytes of metadata-version stamp", header_len);
             let header = &buf[..cmp::min(header_len, buf.len())];
             if header != METADATA_HEADER {
@@ -798,8 +801,14 @@ fn get_metadata_section<'p>(
                 )));
             }
 
+            // Length of the compressed stream - this allows linkers to pad the section if they want
+            let Ok(len_bytes) = <[u8; 4]>::try_from(&buf[header_len..cmp::min(data_start, buf.len())]) else {
+                return Err(MetadataError::LoadFailure("invalid metadata length found".to_string()));
+            };
+            let compressed_len = u32::from_be_bytes(len_bytes) as usize;
+
             // Header is okay -> inflate the actual metadata
-            let compressed_bytes = &buf[header_len..];
+            let compressed_bytes = &buf[data_start..(data_start + compressed_len)];
             debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
             // Assume the decompressed data will be at least the size of the compressed data, so we
             // don't have to grow the buffer as much.
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a7ec2d790b7..1d2541a6788 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -55,13 +55,13 @@ pub(crate) fn rustc_version() -> String {
 /// Metadata encoding version.
 /// N.B., increment this if you change the format of metadata such that
 /// the rustc version can't be found to compare with `rustc_version()`.
-const METADATA_VERSION: u8 = 6;
+const METADATA_VERSION: u8 = 7;
 
 /// Metadata header which includes `METADATA_VERSION`.
 ///
-/// This header is followed by the position of the `CrateRoot`,
-/// which is encoded as a 32-bit big-endian unsigned integer,
-/// and further followed by the rustc version string.
+/// This header is followed by the length of the compressed data, then
+/// the position of the `CrateRoot`, which is encoded as a 32-bit big-endian
+/// unsigned integer, and further followed by the rustc version string.
 pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
 /// A value of type T referred to by its absolute position
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 4b5bacac814..43eef1c770c 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,5 +1,5 @@
 use crate::hir::{ModuleItems, Owner};
-use crate::ty::{DefIdTree, TyCtxt};
+use crate::ty::TyCtxt;
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index c9da711e556..6706b9db3f5 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -7,7 +7,7 @@ pub mod nested_filter;
 pub mod place;
 
 use crate::ty::query::Providers;
-use crate::ty::{DefIdTree, ImplSubject, TyCtxt};
+use crate::ty::{ImplSubject, TyCtxt};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 893bf54b866..171cf1c1ab1 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -1,7 +1,7 @@
 //! A pass that checks to make sure private fields and methods aren't used
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
-use crate::ty::{DefIdTree, TyCtxt, Visibility};
+use crate::ty::{TyCtxt, Visibility};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
@@ -112,7 +112,7 @@ impl EffectiveVisibilities {
         &mut self,
         def_id: LocalDefId,
         eff_vis: &EffectiveVisibility,
-        tree: impl DefIdTree,
+        tcx: TyCtxt<'_>,
     ) {
         use std::collections::hash_map::Entry;
         match self.map.entry(def_id) {
@@ -122,7 +122,7 @@ impl EffectiveVisibilities {
                     let vis_at_level = eff_vis.at_level(l);
                     let old_vis_at_level = old_eff_vis.at_level_mut(l);
                     if vis_at_level != old_vis_at_level
-                        && vis_at_level.is_at_least(*old_vis_at_level, tree)
+                        && vis_at_level.is_at_least(*old_vis_at_level, tcx)
                     {
                         *old_vis_at_level = *vis_at_level
                     }
@@ -219,7 +219,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
         lazy_private_vis: impl FnOnce() -> Visibility,
         inherited_effective_vis: EffectiveVisibility,
         level: Level,
-        tree: impl DefIdTree,
+        tcx: TyCtxt<'_>,
     ) -> bool {
         let mut changed = false;
         let mut current_effective_vis = self
@@ -240,7 +240,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
                     && level != l)
                 {
                     calculated_effective_vis =
-                        if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
+                        if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
                             inherited_effective_vis_at_level
                         } else {
                             nominal_vis
@@ -249,7 +249,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
                 // effective visibility can't be decreased at next update call for the
                 // same id
                 if *current_effective_vis_at_level != calculated_effective_vis
-                    && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tree)
+                    && calculated_effective_vis.is_at_least(*current_effective_vis_at_level, tcx)
                 {
                     changed = true;
                     *current_effective_vis_at_level = calculated_effective_vis;
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 354c84e2209..b61f7806b7a 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -3,7 +3,7 @@
 
 pub use self::StabilityLevel::*;
 
-use crate::ty::{self, DefIdTree, TyCtxt};
+use crate::ty::{self, TyCtxt};
 use rustc_ast::NodeId;
 use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
 use rustc_data_structures::fx::FxHashMap;
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 99cdb769da1..6e6bb8ce95e 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -10,7 +10,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
 use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
-use crate::ty::{self, DefIdTree, List, Ty, TyCtxt};
+use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index e2ab3fd35b3..b964c1852d2 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
 use smallvec::SmallVec;
@@ -289,13 +289,6 @@ pub struct ConstQualifs {
 /// instance of the closure is created, the corresponding free regions
 /// can be extracted from its type and constrained to have the given
 /// outlives relationship.
-///
-/// In some cases, we have to record outlives requirements between types and
-/// regions as well. In that case, if those types include any regions, those
-/// regions are recorded using their external names (`ReStatic`,
-/// `ReEarlyBound`, `ReFree`). We use these because in a query response we
-/// cannot use `ReVar` (which is what we use internally within the rest of the
-/// NLL code).
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct ClosureRegionRequirements<'tcx> {
     /// The number of external regions defined on the closure. In our
@@ -392,16 +385,59 @@ pub enum ClosureOutlivesSubject<'tcx> {
     /// Subject is a type, typically a type parameter, but could also
     /// be a projection. Indicates a requirement like `T: 'a` being
     /// passed to the caller, where the type here is `T`.
-    ///
-    /// The type here is guaranteed not to contain any free regions at
-    /// present.
-    Ty(Ty<'tcx>),
+    Ty(ClosureOutlivesSubjectTy<'tcx>),
 
     /// Subject is a free region from the closure. Indicates a requirement
     /// like `'a: 'b` being passed to the caller; the region here is `'a`.
     Region(ty::RegionVid),
 }
 
+/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
+///
+/// This abstraction is necessary because the type may include `ReVar` regions,
+/// which is what we use internally within NLL code, and they can't be used in
+/// a query response.
+///
+/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
+/// type is not recognized as a binder for late-bound region.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ClosureOutlivesSubjectTy<'tcx> {
+    inner: Ty<'tcx>,
+}
+
+impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
+    /// All regions of `ty` must be of kind `ReVar` and must represent
+    /// universal regions *external* to the closure.
+    pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
+        let inner = tcx.fold_regions(ty, |r, depth| match r.kind() {
+            ty::ReVar(vid) => {
+                let br = ty::BoundRegion {
+                    var: ty::BoundVar::new(vid.index()),
+                    kind: ty::BrAnon(vid.as_u32(), None),
+                };
+                tcx.mk_re_late_bound(depth, br)
+            }
+            _ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
+        });
+
+        Self { inner }
+    }
+
+    pub fn instantiate(
+        self,
+        tcx: TyCtxt<'tcx>,
+        mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
+    ) -> Ty<'tcx> {
+        tcx.fold_regions(self.inner, |r, depth| match r.kind() {
+            ty::ReLateBound(debruijn, br) => {
+                debug_assert_eq!(debruijn, depth);
+                map(ty::RegionVid::new(br.var.index()))
+            }
+            _ => bug!("unexpected region {r:?}"),
+        })
+    }
+}
+
 /// The constituent parts of a mir constant of kind ADT or array.
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConstant<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index f1a9e50a4f0..dfe23cf991f 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -1,6 +1,6 @@
 pub use self::AssocItemContainer::*;
 
-use crate::ty::{self, DefIdTree};
+use crate::ty;
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 527ec9f6e1c..5d0cf23280b 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,6 @@
 use crate::middle::resolve_bound_vars as rbv;
 use crate::mir::interpret::LitToConstInput;
-use crate::ty::{self, DefIdTree, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{self, InternalSubsts, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d9af2fd74ce..70091477e39 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -20,11 +20,10 @@ use crate::traits;
 use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::{
-    self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, DefIdTree, FloatTy, FloatVar,
-    FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
-    ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind,
-    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy,
-    Visibility,
+    self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
+    GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
+    PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
+    TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
 };
 use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
 use rustc_ast as ast;
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index e894e1aaf36..3ca17e7273e 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -3,9 +3,9 @@
 use std::ops::ControlFlow;
 
 use crate::ty::{
-    AliasTy, Const, ConstKind, DefIdTree, FallibleTypeFolder, InferConst, InferTy, Opaque,
-    PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate,
+    Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
+    TypeVisitor,
 };
 
 use rustc_data_structures::fx::FxHashMap;
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
index e268553f826..ac42d6e0510 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs
@@ -1,5 +1,5 @@
 use crate::ty::context::TyCtxt;
-use crate::ty::{self, DefId, DefIdTree, ParamEnv, Ty};
+use crate::ty::{self, DefId, ParamEnv, Ty};
 
 /// Represents whether some type is inhabited in a given context.
 /// Examples of uninhabited types are `!`, `enum Void {}`, or a struct
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dce18a5850f..8cc8a0573bb 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -325,12 +325,15 @@ pub struct ClosureSizeProfileData<'tcx> {
     pub after_feature_tys: Ty<'tcx>,
 }
 
-pub trait DefIdTree: Copy {
-    fn opt_parent(self, id: DefId) -> Option<DefId>;
+impl TyCtxt<'_> {
+    #[inline]
+    pub fn opt_parent(self, id: DefId) -> Option<DefId> {
+        self.def_key(id).parent.map(|index| DefId { index, ..id })
+    }
 
     #[inline]
     #[track_caller]
-    fn parent(self, id: DefId) -> DefId {
+    pub fn parent(self, id: DefId) -> DefId {
         match self.opt_parent(id) {
             Some(id) => id,
             // not `unwrap_or_else` to avoid breaking caller tracking
@@ -340,17 +343,17 @@ pub trait DefIdTree: Copy {
 
     #[inline]
     #[track_caller]
-    fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
+    pub fn opt_local_parent(self, id: LocalDefId) -> Option<LocalDefId> {
         self.opt_parent(id.to_def_id()).map(DefId::expect_local)
     }
 
     #[inline]
     #[track_caller]
-    fn local_parent(self, id: LocalDefId) -> LocalDefId {
+    pub fn local_parent(self, id: LocalDefId) -> LocalDefId {
         self.parent(id.to_def_id()).expect_local()
     }
 
-    fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
+    pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool {
         if descendant.krate != ancestor.krate {
             return false;
         }
@@ -365,13 +368,6 @@ pub trait DefIdTree: Copy {
     }
 }
 
-impl<'tcx> DefIdTree for TyCtxt<'tcx> {
-    #[inline]
-    fn opt_parent(self, id: DefId) -> Option<DefId> {
-        self.def_key(id).parent.map(|index| DefId { index, ..id })
-    }
-}
-
 impl<Id> Visibility<Id> {
     pub fn is_public(self) -> bool {
         matches!(self, Visibility::Public)
@@ -391,19 +387,19 @@ impl<Id: Into<DefId>> Visibility<Id> {
     }
 
     /// Returns `true` if an item with this visibility is accessible from the given module.
-    pub fn is_accessible_from(self, module: impl Into<DefId>, tree: impl DefIdTree) -> bool {
+    pub fn is_accessible_from(self, module: impl Into<DefId>, tcx: TyCtxt<'_>) -> bool {
         match self {
             // Public items are visible everywhere.
             Visibility::Public => true,
-            Visibility::Restricted(id) => tree.is_descendant_of(module.into(), id.into()),
+            Visibility::Restricted(id) => tcx.is_descendant_of(module.into(), id.into()),
         }
     }
 
     /// Returns `true` if this visibility is at least as accessible as the given visibility
-    pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tree: impl DefIdTree) -> bool {
+    pub fn is_at_least(self, vis: Visibility<impl Into<DefId>>, tcx: TyCtxt<'_>) -> bool {
         match vis {
             Visibility::Public => self.is_public(),
-            Visibility::Restricted(id) => self.is_accessible_from(id, tree),
+            Visibility::Restricted(id) => self.is_accessible_from(id, tcx),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 021c20b5854..d947d96041e 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,5 +1,5 @@
 use crate::ty::GenericArg;
-use crate::ty::{self, DefIdTree, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 6a053c368d8..b3139d23d36 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,6 +1,6 @@
 use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::{
-    self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
+    self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
     TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
 };
 use crate::ty::{GenericArg, GenericArgKind};
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index e6a73e8bb1c..52d114bae30 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -7,7 +7,7 @@ use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef};
 use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
-    self, AdtDef, DefIdTree, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
+    self, AdtDef, Discr, FallibleTypeFolder, Term, Ty, TyCtxt, TypeFlags, TypeFoldable,
     TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
 use crate::ty::{List, ParamEnv};
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 233c0df2d3c..649a58c9170 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -100,8 +100,9 @@ impl<'tcx> TraitDef {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn for_each_impl<F: FnMut(DefId)>(self, def_id: DefId, mut f: F) {
-        let impls = self.trait_impls_of(def_id);
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
+    pub fn for_each_impl<F: FnMut(DefId)>(self, trait_def_id: DefId, mut f: F) {
+        let impls = self.trait_impls_of(trait_def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
             f(impl_def_id);
@@ -114,26 +115,28 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Iterate over every impl that could possibly match the
-    /// self type `self_ty`.
+    /// Iterate over every impl that could possibly match the self type `self_ty`.
+    ///
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
     pub fn for_each_relevant_impl<F: FnMut(DefId)>(
         self,
-        def_id: DefId,
+        trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         mut f: F,
     ) {
-        let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
+        let _: Option<()> = self.find_map_relevant_impl(trait_def_id, self_ty, |did| {
             f(did);
             None
         });
     }
 
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
     pub fn non_blanket_impls_for_ty(
         self,
-        def_id: DefId,
+        trait_def_id: DefId,
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
-        let impls = self.trait_impls_of(def_id);
+        let impls = self.trait_impls_of(trait_def_id);
         if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsInfer) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
@@ -145,9 +148,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
     /// Applies function to every impl that could possibly match the self type `self_ty` and returns
     /// the first non-none value.
+    ///
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
     pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
         self,
-        def_id: DefId,
+        trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         mut f: F,
     ) -> Option<T> {
@@ -156,7 +161,7 @@ impl<'tcx> TyCtxt<'tcx> {
         //
         // If we want to be faster, we could have separate queries for
         // blanket and non-blanket impls, and compare them separately.
-        let impls = self.trait_impls_of(def_id);
+        let impls = self.trait_impls_of(trait_def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
             if let result @ Some(_) = f(impl_def_id) {
@@ -190,9 +195,11 @@ impl<'tcx> TyCtxt<'tcx> {
         None
     }
 
-    /// Returns an iterator containing all impls
-    pub fn all_impls(self, def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
-        let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id);
+    /// Returns an iterator containing all impls for `trait_def_id`.
+    ///
+    /// `trait_def_id` MUST BE the `DefId` of a trait.
+    pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
+        let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(trait_def_id);
 
         blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned()
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 90270e0ee9d..8b5469743da 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -4,8 +4,8 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
 use crate::ty::layout::IntegerExt;
 use crate::ty::{
-    self, DefIdTree, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt,
+    self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
 };
 use crate::ty::{GenericArgKind, SubstsRef};
 use rustc_apfloat::Float as _;
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index c4f526dbdc8..55aa4fcff2c 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -4,7 +4,7 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::Representability;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::query::QueryInfo;
 use rustc_query_system::Value;
 use rustc_span::def_id::LocalDefId;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index dbba529aef7..09d2eb96d0f 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -1,5 +1,6 @@
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::mir::tcx::PlaceTy;
+use rustc_middle::ty::cast::mir_cast_kind;
 use rustc_middle::{mir::*, thir::*, ty};
 use rustc_span::Span;
 use rustc_target::abi::VariantIdx;
@@ -142,7 +143,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
     }
 
     fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
-        parse_by_kind!(self, expr_id, _, "rvalue",
+        parse_by_kind!(self, expr_id, expr, "rvalue",
             @call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
             @call("mir_checked", args) => {
                 parse_by_kind!(self, args[0], _, "binary op",
@@ -167,6 +168,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
             ExprKind::Repeat { value, count } => Ok(
                 Rvalue::Repeat(self.parse_operand(*value)?, *count)
             ),
+            ExprKind::Cast { source } => {
+                let source = self.parse_operand(*source)?;
+                let source_ty = source.ty(self.body.local_decls(), self.tcx);
+                let cast_kind = mir_cast_kind(source_ty, expr.ty);
+                Ok(Rvalue::Cast(cast_kind, source, expr.ty))
+            },
             _ => self.parse_operand(expr_id).map(Rvalue::Use),
         )
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index 78083685193..ea5aeb67d85 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Generate better code for things that don't need to be
                 // dropped.
                 if lhs.ty.needs_drop(this.tcx, this.param_env) {
-                    let rhs = unpack!(block = this.as_local_operand(block, rhs));
+                    let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
                     let lhs = unpack!(block = this.as_place(block, lhs));
                     unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
                 } else {
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 591b416337b..770701b3750 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -91,7 +91,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{Expr, LintLevel};
 
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{DesugaringKind, Span, DUMMY_SP};
 
 #[derive(Debug)]
 pub struct Scopes<'tcx> {
@@ -1118,24 +1118,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 
     /// Utility function for *non*-scope code to build their own drops
+    /// Force a drop at this point in the MIR by creating a new block.
     pub(crate) fn build_drop_and_replace(
         &mut self,
         block: BasicBlock,
         span: Span,
         place: Place<'tcx>,
-        value: Operand<'tcx>,
+        value: Rvalue<'tcx>,
     ) -> BlockAnd<()> {
+        let span = self.tcx.with_stable_hashing_context(|hcx| {
+            span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
+        });
         let source_info = self.source_info(span);
-        let next_target = self.cfg.start_new_block();
+
+        // create the new block for the assignment
+        let assign = self.cfg.start_new_block();
+        self.cfg.push_assign(assign, source_info, place, value.clone());
+
+        // create the new block for the assignment in the case of unwinding
+        let assign_unwind = self.cfg.start_new_cleanup_block();
+        self.cfg.push_assign(assign_unwind, source_info, place, value.clone());
 
         self.cfg.terminate(
             block,
             source_info,
-            TerminatorKind::DropAndReplace { place, value, target: next_target, unwind: None },
+            TerminatorKind::Drop { place, target: assign, unwind: Some(assign_unwind) },
         );
         self.diverge_from(block);
 
-        next_target.unit()
+        assign.unit()
     }
 
     /// Creates an `Assert` terminator and return the success block.
@@ -1413,8 +1424,15 @@ impl<'tcx> DropTreeBuilder<'tcx> for Unwind {
     fn add_entry(cfg: &mut CFG<'tcx>, from: BasicBlock, to: BasicBlock) {
         let term = &mut cfg.block_data_mut(from).terminator_mut();
         match &mut term.kind {
-            TerminatorKind::Drop { unwind, .. }
-            | TerminatorKind::DropAndReplace { unwind, .. }
+            TerminatorKind::Drop { unwind, .. } => {
+                if let Some(unwind) = *unwind {
+                    let source_info = term.source_info;
+                    cfg.terminate(unwind, source_info, TerminatorKind::Goto { target: to });
+                } else {
+                    *unwind = Some(to);
+                }
+            }
+            TerminatorKind::DropAndReplace { unwind, .. }
             | TerminatorKind::FalseUnwind { unwind, .. }
             | TerminatorKind::Call { cleanup: unwind, .. }
             | TerminatorKind::Assert { cleanup: unwind, .. }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 41306dd80fb..f356c8a6838 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -25,7 +25,7 @@ use rustc_middle::mir::{BorrowKind, Field, Mutability};
 use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
-use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType};
 use rustc_span::{Span, Symbol};
 
 use std::cmp::Ordering;
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 401db890a98..34c60b5ff3c 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -690,7 +690,7 @@ impl Map {
         }
 
         // Recurse with all fields of this place.
-        iter_fields(ty, tcx, |variant, field, ty| {
+        iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
             if let Some(variant) = variant {
                 projection.push(PlaceElem::Downcast(None, variant));
                 let _ = self.make_place(local, projection);
@@ -939,6 +939,7 @@ impl<V, T> TryFrom<ProjectionElem<V, T>> for TrackElem {
 pub fn iter_fields<'tcx>(
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     mut f: impl FnMut(Option<VariantIdx>, Field, Ty<'tcx>),
 ) {
     match ty.kind() {
@@ -956,14 +957,14 @@ pub fn iter_fields<'tcx>(
                 for (f_index, f_def) in v_def.fields.iter().enumerate() {
                     let field_ty = f_def.ty(tcx, substs);
                     let field_ty = tcx
-                        .try_normalize_erasing_regions(ty::ParamEnv::reveal_all(), field_ty)
-                        .unwrap_or(field_ty);
+                        .try_normalize_erasing_regions(param_env, field_ty)
+                        .unwrap_or_else(|_| tcx.erase_regions(field_ty));
                     f(variant, f_index.into(), field_ty);
                 }
             }
         }
         ty::Closure(_, substs) => {
-            iter_fields(substs.as_closure().tupled_upvars_ty(), tcx, f);
+            iter_fields(substs.as_closure().tupled_upvars_ty(), tcx, param_env, f);
         }
         _ => (),
     }
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index bdfd8dc6e99..29424f09695 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer;
 use rustc_mir_dataflow::MoveDataParamEnv;
 use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
-use rustc_span::Span;
+use rustc_span::{DesugaringKind, Span};
 use rustc_target::abi::VariantIdx;
 use std::fmt;
 
@@ -425,10 +425,19 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                             bb,
                         ),
                         LookupResult::Parent(..) => {
-                            self.tcx.sess.delay_span_bug(
-                                terminator.source_info.span,
-                                &format!("drop of untracked value {:?}", bb),
-                            );
+                            if !matches!(
+                                terminator.source_info.span.desugaring_kind(),
+                                Some(DesugaringKind::Replace),
+                            ) {
+                                self.tcx.sess.delay_span_bug(
+                                    terminator.source_info.span,
+                                    &format!("drop of untracked value {:?}", bb),
+                                );
+                            }
+                            // A drop and replace behind a pointer/array/whatever.
+                            // The borrow checker requires that these locations are initialized before the assignment,
+                            // so we just leave an unconditional drop.
+                            assert!(!data.is_cleanup);
                         }
                     }
                 }
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 2e97312ee50..746326f9bde 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -1872,12 +1872,14 @@ fn check_must_not_suspend_def(
     data: SuspendCheckData<'_>,
 ) -> bool {
     if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
-        let msg = format!(
-            "{}`{}`{} held across a suspend point, but should not be",
-            data.descr_pre,
-            tcx.def_path_str(def_id),
-            data.descr_post,
-        );
+        let msg = rustc_errors::DelayDm(|| {
+            format!(
+                "{}`{}`{} held across a suspend point, but should not be",
+                data.descr_pre,
+                tcx.def_path_str(def_id),
+                data.descr_post,
+            )
+        });
         tcx.struct_span_lint_hir(
             rustc_session::lint::builtin::MUST_NOT_SUSPEND,
             hir_id,
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index cdd28ae0c01..5fd923190ef 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -416,8 +416,6 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
 
     pm::run_passes(tcx, &mut body, &[&ctfe_limit::CtfeLimit], None);
 
-    debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
-
     body
 }
 
@@ -626,8 +624,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
     debug!("body: {:#?}", body);
     run_optimization_passes(tcx, &mut body);
 
-    debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
-
     body
 }
 
@@ -651,7 +647,5 @@ fn promoted_mir(
         run_analysis_to_runtime_passes(tcx, body);
     }
 
-    debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
-
     tcx.arena.alloc(promoted)
 }
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 13168e9a268..ca2221520c8 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -4,7 +4,7 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields};
 
 pub struct ScalarReplacementOfAggregates;
@@ -18,11 +18,12 @@ impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!(def_id = ?body.source.def_id());
         let mut excluded = excluded_locals(body);
+        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         loop {
             debug!(?excluded);
             let escaping = escaping_locals(&excluded, body);
             debug!(?escaping);
-            let replacements = compute_flattening(tcx, body, escaping);
+            let replacements = compute_flattening(tcx, param_env, body, escaping);
             debug!(?replacements);
             let all_dead_locals = replace_flattened_locals(tcx, body, replacements);
             if !all_dead_locals.is_empty() {
@@ -144,6 +145,7 @@ impl<'tcx> ReplacementMap<'tcx> {
 /// The replacement will be done later in `ReplacementVisitor`.
 fn compute_flattening<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     body: &mut Body<'tcx>,
     escaping: BitSet<Local>,
 ) -> ReplacementMap<'tcx> {
@@ -155,7 +157,7 @@ fn compute_flattening<'tcx>(
         }
         let decl = body.local_decls[local].clone();
         let ty = decl.ty;
-        iter_fields(ty, tcx, |variant, field, field_ty| {
+        iter_fields(ty, tcx, param_env, |variant, field, field_ty| {
             if variant.is_some() {
                 // Downcasts are currently not supported.
                 return;
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 2c56edd89bc..3c7425d83c4 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, visit::TypeVisitableExt, DefIdTree, InstanceDef, TyCtxt};
+use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt};
 use rustc_span::symbol::Symbol;
 
 use super::PartitioningCx;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a051dbe9ff5..0a65c37ea7b 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -19,7 +19,6 @@ use crate::errors::{
 };
 
 use crate::fluent_generated as fluent;
-use crate::lexer::UnmatchedDelim;
 use crate::parser;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
@@ -220,7 +219,6 @@ impl MultiSugg {
 /// is dropped.
 pub struct SnapshotParser<'a> {
     parser: Parser<'a>,
-    unclosed_delims: Vec<UnmatchedDelim>,
 }
 
 impl<'a> Deref for SnapshotParser<'a> {
@@ -255,27 +253,15 @@ impl<'a> Parser<'a> {
         &self.sess.span_diagnostic
     }
 
-    /// Replace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`.
-    /// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears.
+    /// Replace `self` with `snapshot.parser`.
     pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
         *self = snapshot.parser;
-        self.unclosed_delims.extend(snapshot.unclosed_delims);
-    }
-
-    pub fn unclosed_delims(&self) -> &[UnmatchedDelim] {
-        &self.unclosed_delims
     }
 
     /// Create a snapshot of the `Parser`.
     pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> {
-        let mut snapshot = self.clone();
-        let unclosed_delims = self.unclosed_delims.clone();
-        // Clear `unclosed_delims` in snapshot to avoid
-        // duplicate errors being emitted when the `Parser`
-        // is dropped (which may or may not happen, depending
-        // if the parsing the snapshot is created for is successful)
-        snapshot.unclosed_delims.clear();
-        SnapshotParser { parser: snapshot, unclosed_delims }
+        let snapshot = self.clone();
+        SnapshotParser { parser: snapshot }
     }
 
     pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> {
@@ -579,21 +565,6 @@ impl<'a> Parser<'a> {
         } else {
             label_sp
         };
-        match self.recover_closing_delimiter(
-            &expected
-                .iter()
-                .filter_map(|tt| match tt {
-                    TokenType::Token(t) => Some(t.clone()),
-                    _ => None,
-                })
-                .collect::<Vec<_>>(),
-            err,
-        ) {
-            Err(e) => err = e,
-            Ok(recovered) => {
-                return Ok(recovered);
-            }
-        }
 
         if self.check_too_many_raw_str_terminators(&mut err) {
             if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
@@ -1573,12 +1544,6 @@ impl<'a> Parser<'a> {
         );
         let mut err = self.struct_span_err(sp, &msg);
         let label_exp = format!("expected `{token_str}`");
-        match self.recover_closing_delimiter(&[t.clone()], err) {
-            Err(e) => err = e,
-            Ok(recovered) => {
-                return Ok(recovered);
-            }
-        }
         let sm = self.sess.source_map();
         if !sm.is_multiline(prev_sp.until(sp)) {
             // When the spans are in the same line, it means that the only content
@@ -1795,81 +1760,6 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub(super) fn recover_closing_delimiter(
-        &mut self,
-        tokens: &[TokenKind],
-        mut err: DiagnosticBuilder<'a, ErrorGuaranteed>,
-    ) -> PResult<'a, bool> {
-        let mut pos = None;
-        // We want to use the last closing delim that would apply.
-        for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() {
-            if tokens.contains(&token::CloseDelim(unmatched.expected_delim))
-                && Some(self.token.span) > unmatched.unclosed_span
-            {
-                pos = Some(i);
-            }
-        }
-        match pos {
-            Some(pos) => {
-                // Recover and assume that the detected unclosed delimiter was meant for
-                // this location. Emit the diagnostic and act as if the delimiter was
-                // present for the parser's sake.
-
-                // Don't attempt to recover from this unclosed delimiter more than once.
-                let unmatched = self.unclosed_delims.remove(pos);
-                let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim));
-                if unmatched.found_delim.is_none() {
-                    // We encountered `Eof`, set this fact here to avoid complaining about missing
-                    // `fn main()` when we found place to suggest the closing brace.
-                    *self.sess.reached_eof.borrow_mut() = true;
-                }
-
-                // We want to suggest the inclusion of the closing delimiter where it makes
-                // the most sense, which is immediately after the last token:
-                //
-                //  {foo(bar {}}
-                //      ^      ^
-                //      |      |
-                //      |      help: `)` may belong here
-                //      |
-                //      unclosed delimiter
-                if let Some(sp) = unmatched.unclosed_span {
-                    let mut primary_span: Vec<Span> =
-                        err.span.primary_spans().iter().cloned().collect();
-                    primary_span.push(sp);
-                    let mut primary_span: MultiSpan = primary_span.into();
-                    for span_label in err.span.span_labels() {
-                        if let Some(label) = span_label.label {
-                            primary_span.push_span_label(span_label.span, label);
-                        }
-                    }
-                    err.set_span(primary_span);
-                    err.span_label(sp, "unclosed delimiter");
-                }
-                // Backticks should be removed to apply suggestions.
-                let mut delim = delim.to_string();
-                delim.retain(|c| c != '`');
-                err.span_suggestion_short(
-                    self.prev_token.span.shrink_to_hi(),
-                    &format!("`{delim}` may belong here"),
-                    delim,
-                    Applicability::MaybeIncorrect,
-                );
-                if unmatched.found_delim.is_none() {
-                    // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown
-                    // errors which would be emitted elsewhere in the parser and let other error
-                    // recovery consume the rest of the file.
-                    Err(err)
-                } else {
-                    err.emit();
-                    self.expected_tokens.clear(); // Reduce the number of errors.
-                    Ok(true)
-                }
-            }
-            _ => Err(err),
-        }
-    }
-
     /// Eats tokens until we can be relatively sure we reached the end of the
     /// statement. This is something of a best-effort heuristic.
     ///
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 95a7ca80d5d..e00eda47c66 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1394,19 +1394,6 @@ impl<'a> Parser<'a> {
             self.parse_expr_let()
         } else if self.eat_keyword(kw::Underscore) {
             Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore))
-        } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) {
-            // Don't complain about bare semicolons after unclosed braces
-            // recovery in order to keep the error count down. Fixing the
-            // delimiters will possibly also fix the bare semicolon found in
-            // expression context. For example, silence the following error:
-            //
-            //     error: expected expression, found `;`
-            //      --> file.rs:2:13
-            //       |
-            //     2 |     foo(bar(;
-            //       |             ^ expected expression
-            self.bump();
-            Ok(self.mk_expr_err(self.token.span))
         } else if self.token.uninterpolated_span().rust_2018() {
             // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
             if self.check_keyword(kw::Async) {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 9d9ae154ad4..85cc8ca02a9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -125,16 +125,13 @@ impl<'a> Parser<'a> {
             return Ok(Some(item.into_inner()));
         };
 
-        let mut unclosed_delims = vec![];
         let item =
             self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
                 let item =
                     this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode);
-                unclosed_delims.append(&mut this.unclosed_delims);
                 Ok((item?, TrailingToken::None))
             })?;
 
-        self.unclosed_delims.append(&mut unclosed_delims);
         Ok(item)
     }
 
@@ -1960,21 +1957,12 @@ impl<'a> Parser<'a> {
         // FIXME: This will make us not emit the help even for declarative
         // macros within the same crate (that we can fix), which is sad.
         if !span.from_expansion() {
-            if self.unclosed_delims.is_empty() {
-                let DelimSpan { open, close } = args.dspan;
-                err.multipart_suggestion(
-                    "change the delimiters to curly braces",
-                    vec![(open, "{".to_string()), (close, '}'.to_string())],
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                err.span_suggestion(
-                    span,
-                    "change the delimiters to curly braces",
-                    " { /* items */ }",
-                    Applicability::HasPlaceholders,
-                );
-            }
+            let DelimSpan { open, close } = args.dspan;
+            err.multipart_suggestion(
+                "change the delimiters to curly braces",
+                vec![(open, "{".to_string()), (close, '}'.to_string())],
+                Applicability::MaybeIncorrect,
+            );
             err.span_suggestion(
                 span.shrink_to_hi(),
                 "add a semicolon",
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index da82e4724d1..6e9b447fa61 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -146,10 +146,7 @@ pub struct Parser<'a> {
     /// See the comments in the `parse_path_segment` function for more details.
     unmatched_angle_bracket_count: u32,
     max_angle_bracket_count: u32,
-    /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery
-    /// it gets removed from here. Every entry left at the end gets emitted as an independent
-    /// error.
-    pub(super) unclosed_delims: Vec<UnmatchedDelim>,
+
     last_unexpected_token_span: Option<Span>,
     /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it
     /// looked like it could have been a mistyped path or literal `Option:Some(42)`).
@@ -168,7 +165,7 @@ pub struct Parser<'a> {
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 312);
+rustc_data_structures::static_assert_size!(Parser<'_>, 288);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -215,12 +212,6 @@ struct CaptureState {
     inner_attr_ranges: FxHashMap<AttrId, ReplaceRange>,
 }
 
-impl<'a> Drop for Parser<'a> {
-    fn drop(&mut self) {
-        emit_unclosed_delims(&mut self.unclosed_delims, &self.sess);
-    }
-}
-
 /// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that
 /// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b)
 /// use this type to emit them as a linear sequence. But a linear sequence is
@@ -478,7 +469,6 @@ impl<'a> Parser<'a> {
             desugar_doc_comments,
             unmatched_angle_bracket_count: 0,
             max_angle_bracket_count: 0,
-            unclosed_delims: Vec::new(),
             last_unexpected_token_span: None,
             last_type_ascription: None,
             subparser_name,
@@ -859,7 +849,6 @@ impl<'a> Parser<'a> {
         let mut recovered = false;
         let mut trailing = false;
         let mut v = ThinVec::new();
-        let unclosed_delims = !self.unclosed_delims.is_empty();
 
         while !self.expect_any_with_type(kets, expect) {
             if let token::CloseDelim(..) | token::Eof = self.token.kind {
@@ -901,7 +890,7 @@ impl<'a> Parser<'a> {
                                 _ => {
                                     // Attempt to keep parsing if it was a similar separator.
                                     if let Some(tokens) = t.similar_tokens() {
-                                        if tokens.contains(&self.token.kind) && !unclosed_delims {
+                                        if tokens.contains(&self.token.kind) {
                                             self.bump();
                                         }
                                     }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index e2f858a34b6..28e06e5bb3e 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -13,7 +13,7 @@ use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{sym, Symbol};
 use std::mem;
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index b327ba63330..b7e6a11998b 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{sigpipe, CrateType, EntryFnType};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index de0e50a65de..9418f3cd322 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -5,7 +5,7 @@ use rustc_hir::intravisit;
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     tcx.dep_graph.assert_ignored();
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index df5c8f53ec1..db9d0dcc300 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -95,7 +95,7 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt};
+use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{BytePos, Span};
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 051100c56f8..d6cb68a9c20 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -14,7 +14,7 @@ use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::middle::privacy::{self, Level};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::CrateType;
 use rustc_target::spec::abi::Abi;
 
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 16194a6f196..d5cc64a5402 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -265,6 +265,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 self.index.implications.insert(implied_by, feature);
             }
 
+            if let Some(ConstStability {
+                level: Unstable { implied_by: Some(implied_by), .. },
+                feature,
+                ..
+            }) = const_stab
+            {
+                self.index.implications.insert(implied_by, feature);
+            }
+
             self.index.stab_map.insert(def_id, stab);
             stab
         });
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 50176c80232..99a44b0ca4d 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -29,7 +29,7 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind};
+use rustc_middle::ty::{self, Const, GenericParamDefKind};
 use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index b1e023f2caa..9526bca3df2 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -25,9 +25,8 @@ use rustc_expand::expand::AstFragment;
 use rustc_hir::def::{self, *};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_metadata::creader::LoadedMacro;
-use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::{bug, ty};
 use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
 use rustc_span::source_map::respan;
@@ -99,7 +98,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         loop {
             match self.get_module(def_id) {
                 Some(module) => return module,
-                None => def_id = self.parent(def_id),
+                None => def_id = self.tcx.parent(def_id),
             }
         }
     }
@@ -775,7 +774,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                         let field_vis = self
                             .try_resolve_visibility(&field.vis, false)
                             .unwrap_or(ty::Visibility::Public);
-                        if ctor_vis.is_at_least(field_vis, &*self.r) {
+                        if ctor_vis.is_at_least(field_vis, self.r.tcx) {
                             ctor_vis = field_vis;
                         }
                         ret_fields.push(field_vis.to_def_id());
@@ -1414,10 +1413,7 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
 
         if !(ctxt == AssocCtxt::Impl
             && matches!(item.vis.kind, ast::VisibilityKind::Inherited)
-            && self
-                .r
-                .trait_impl_items
-                .contains(&ty::DefIdTree::local_parent(&*self.r, local_def_id)))
+            && self.r.trait_impl_items.contains(&self.r.tcx.local_parent(local_def_id)))
         {
             // Trait impl item visibility is inherited from its trait when not specified
             // explicitly. In that case we cannot determine it here in early resolve,
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7add59ac627..adec7973671 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -15,7 +15,7 @@ use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
 use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         segms.push(ast::PathSegment::from_ident(ident));
                         let path = Path { span: name_binding.span, segments: segms, tokens: None };
                         let did = match res {
-                            Res::Def(DefKind::Ctor(..), did) => this.opt_parent(did),
+                            Res::Def(DefKind::Ctor(..), did) => this.tcx.opt_parent(did),
                             _ => res.opt_def_id(),
                         };
 
@@ -1591,7 +1591,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             ctor_def_id,
         )) = binding.kind
         {
-            let def_id = self.parent(ctor_def_id);
+            let def_id = self.tcx.parent(ctor_def_id);
             let fields = self.field_names.get(&def_id)?;
             return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
         }
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 7bd90d7e345..4bb252bfb29 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
-use rustc_middle::ty::{DefIdTree, Visibility};
+use rustc_middle::ty::Visibility;
 use std::mem;
 
 type ImportId<'a> = Interned<'a, NameBinding<'a>>;
@@ -60,7 +60,7 @@ impl Resolver<'_, '_> {
         // For mod items `nearest_normal_mod` returns its argument, but we actually need its parent.
         let normal_mod_id = self.nearest_normal_mod(def_id);
         if normal_mod_id == def_id {
-            self.opt_local_parent(def_id).map_or(Visibility::Public, Visibility::Restricted)
+            self.tcx.opt_local_parent(def_id).map_or(Visibility::Public, Visibility::Restricted)
         } else {
             Visibility::Restricted(normal_mod_id)
         }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 4dab0836d28..5d40c6e4e48 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -245,7 +245,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         import: &'a Import<'a>,
     ) -> &'a NameBinding<'a> {
         let import_vis = import.expect_vis().to_def_id();
-        let vis = if binding.vis.is_at_least(import_vis, self)
+        let vis = if binding.vis.is_at_least(import_vis, self.tcx)
             || pub_use_of_private_extern_crate_hack(import, binding)
         {
             import_vis
@@ -255,7 +255,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         if let ImportKind::Glob { ref max_vis, .. } = import.kind {
             if vis == import_vis
-                || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
+                || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx))
             {
                 max_vis.set(Some(vis.expect_local()))
             }
@@ -294,7 +294,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 old_binding,
                                 binding,
                             ));
-                        } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
+                        } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
                             // We are glob-importing the same item but with greater visibility.
                             resolution.binding = Some(binding);
                         }
@@ -786,7 +786,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     if !is_prelude
                     && let Some(max_vis) = max_vis.get()
-                    && !max_vis.is_at_least(import.expect_vis(), &*self)
+                    && !max_vis.is_at_least(import.expect_vis(), self.tcx)
                 {
                     let msg = "glob import doesn't reexport anything because no candidate is public enough";
                     self.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
@@ -977,7 +977,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let mut crate_private_reexport = false;
         self.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
-                if !binding.vis.is_at_least(import.expect_vis(), &*this) {
+                if !binding.vis.is_at_least(import.expect_vis(), this.tcx) {
                     reexport_error = Some((ns, binding));
                     if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
                         if binding_def_id.is_top_level_module() {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 7df17376b3e..cc3e142a5fd 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -22,7 +22,6 @@ use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
 use rustc_middle::middle::resolve_bound_vars::Set1;
-use rustc_middle::ty::DefIdTree;
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
 use rustc_session::lint;
@@ -1671,8 +1670,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             // Figure out if this is a type/trait segment,
             // which may need lifetime elision performed.
             let type_def_id = match partial_res.base_res() {
-                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => self.r.parent(def_id),
-                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => self.r.parent(def_id),
+                Res::Def(DefKind::AssocTy, def_id) if i + 2 == proj_start => {
+                    self.r.tcx.parent(def_id)
+                }
+                Res::Def(DefKind::Variant, def_id) if i + 1 == proj_start => {
+                    self.r.tcx.parent(def_id)
+                }
                 Res::Def(DefKind::Struct, def_id)
                 | Res::Def(DefKind::Union, def_id)
                 | Res::Def(DefKind::Enum, def_id)
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index b8ddc455257..206c43f6902 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -21,7 +21,6 @@ use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::PrimTy;
-use rustc_middle::ty::DefIdTree;
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
@@ -1508,7 +1507,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
                 }
             }
             (Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => {
-                let def_id = self.r.parent(ctor_def_id);
+                let def_id = self.r.tcx.parent(ctor_def_id);
                 if let Some(span) = self.def_span(def_id) {
                     err.span_label(span, &format!("`{}` defined here", path_str));
                 }
@@ -1999,7 +1998,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             }
         } else {
             let needs_placeholder = |ctor_def_id: DefId, kind: CtorKind| {
-                let def_id = self.r.parent(ctor_def_id);
+                let def_id = self.r.tcx.parent(ctor_def_id);
                 let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
                 match kind {
                     CtorKind::Const => false,
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 1fdfb1a53d4..5eba208e3ed 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -44,7 +44,7 @@ use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, TyCtxt};
+use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt};
 use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::CrateStore;
@@ -1117,13 +1117,6 @@ impl<'a, 'tcx> AsMut<Resolver<'a, 'tcx>> for Resolver<'a, 'tcx> {
     }
 }
 
-impl<'a, 'b, 'tcx> DefIdTree for &'a Resolver<'b, 'tcx> {
-    #[inline]
-    fn opt_parent(self, id: DefId) -> Option<DefId> {
-        self.tcx.opt_parent(id)
-    }
-}
-
 impl<'tcx> Resolver<'_, 'tcx> {
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
         self.node_id_to_def_id.get(&node).copied()
@@ -1789,7 +1782,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         vis: ty::Visibility<impl Into<DefId>>,
         module: Module<'a>,
     ) -> bool {
-        vis.is_accessible_from(module.nearest_parent_mod(), self)
+        vis.is_accessible_from(module.nearest_parent_mod(), self.tcx)
     }
 
     fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index dee823eefde..9f22e9776d4 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1151,6 +1151,7 @@ pub enum DesugaringKind {
     Await,
     ForLoop,
     WhileLoop,
+    Replace,
 }
 
 impl DesugaringKind {
@@ -1166,6 +1167,7 @@ impl DesugaringKind {
             DesugaringKind::OpaqueTy => "`impl Trait`",
             DesugaringKind::ForLoop => "`for` loop",
             DesugaringKind::WhileLoop => "`while` loop",
+            DesugaringKind::Replace => "drop and replace",
         }
     }
 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6272bf7f25e..4e626fd9f30 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1197,6 +1197,8 @@ symbols! {
         rlib,
         rotate_left,
         rotate_right,
+        roundevenf32,
+        roundevenf64,
         roundf32,
         roundf64,
         rt,
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index a55b984fd63..38120b9760f 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -149,6 +149,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
         &mut self,
         _: &InferCtxt<'tcx>,
     ) -> Vec<PredicateObligation<'tcx>> {
-        unimplemented!()
+        std::mem::take(&mut self.obligations)
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index b20636174ee..62d5e50dbc5 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -158,7 +158,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
         self.infcx
             .at(cause, param_env)
             .define_opaque_types(true)
-            .sup(expected, actual)
+            .sub(expected, actual)
             .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
     }
 
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 66d74fd05a6..9ab753c5a48 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -30,7 +30,7 @@ use rustc_middle::hir::map;
 use rustc_middle::ty::error::TypeError::{self, Sorts};
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::{
-    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
     GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
     IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
     TypeSuperFoldable, TypeVisitableExt, TypeckResults,
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index b2317f55d25..0e047977caa 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -28,7 +28,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use rustc_span::def_id::{DefId, CRATE_DEF_ID};
 use rustc_span::Span;
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 870ecc2a970..f7559a3f10a 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -32,7 +32,6 @@ use rustc_infer::traits::ImplSourceBuiltinData;
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
@@ -2200,7 +2199,8 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
         Err(guar) => return Progress::error(tcx, guar),
     };
     // We don't support specialization for RPITITs anyways... yet.
-    if !leaf_def.is_final() {
+    // Also don't try to project to an RPITIT that has no value
+    if !leaf_def.is_final() || !leaf_def.item.defaultness(tcx).has_value() {
         return Progress { term: tcx.ty_error_misc().into(), obligations };
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4377de15829..cd3f3c114ba 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2149,7 +2149,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => None,
             ty::Infer(ty::TyVar(_)) => Ambiguous,
 
-            // We can make this an ICE if/once we actually instantiate the trait obligation.
+            // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
             ty::Bound(..) => None,
 
             ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
@@ -2257,7 +2257,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
             }
 
-            ty::Adt(..) | ty::Alias(..) | ty::Param(..) => {
+            ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
                 None
             }
@@ -2269,9 +2269,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ambiguous
             }
 
-            ty::Placeholder(..)
-            | ty::Bound(..)
-            | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            // We can make this an ICE if/once we actually instantiate the trait obligation eagerly.
+            ty::Bound(..) => None,
+
+            ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
             }
         }
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
index e4f3e7928da..0cae0377ee8 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -58,9 +58,7 @@ mod rustc {
             use rustc_middle::ty;
 
             let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
-                use rustc_middle::ty::DefIdTree;
-                let parent = self.parent(adt_def.did());
-                parent
+                self.parent(adt_def.did())
             } else {
                 // Is this always how we want to handle a non-ADT scope?
                 return false;
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 0648784b265..2fc55a2527d 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -4,7 +4,7 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_middle::ty::{self, DefIdTree, ImplTraitInTraitData, InternalSubsts, TyCtxt};
+use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt};
 use rustc_span::symbol::kw;
 
 pub fn provide(providers: &mut ty::query::Providers) {
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 7fecee2a38b..56d6cc28bc8 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,4 +1,3 @@
-use crate::rustc_middle::ty::DefIdTree;
 use rustc_hir::{def::DefKind, def_id::DefId};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 18159778a8e..70c9de91fbf 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -142,12 +142,14 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         && tcx.associated_item(def_id).container == ty::AssocItemContainer::TraitContainer
     {
         let sig = tcx.fn_sig(def_id).subst_identity();
-        sig.visit_with(&mut ImplTraitInTraitFinder {
+        // We accounted for the binder of the fn sig, so skip the binder.
+        sig.skip_binder().visit_with(&mut ImplTraitInTraitFinder {
             tcx,
             fn_def_id: def_id,
             bound_vars: sig.bound_vars(),
             predicates: &mut predicates,
             seen: FxHashSet::default(),
+            depth: ty::INNERMOST,
         });
     }
 
@@ -244,15 +246,36 @@ struct ImplTraitInTraitFinder<'a, 'tcx> {
     fn_def_id: DefId,
     bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
     seen: FxHashSet<DefId>,
+    depth: ty::DebruijnIndex,
 }
 
 impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+        &mut self,
+        binder: &ty::Binder<'tcx, T>,
+    ) -> std::ops::ControlFlow<Self::BreakTy> {
+        self.depth.shift_in(1);
+        let binder = binder.super_visit_with(self);
+        self.depth.shift_out(1);
+        binder
+    }
+
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> std::ops::ControlFlow<Self::BreakTy> {
         if let ty::Alias(ty::Projection, alias_ty) = *ty.kind()
             && self.tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
             && self.tcx.impl_trait_in_trait_parent(alias_ty.def_id) == self.fn_def_id
             && self.seen.insert(alias_ty.def_id)
         {
+            // We have entered some binders as we've walked into the
+            // bounds of the RPITIT. Shift these binders back out when
+            // constructing the top-level projection predicate.
+            let alias_ty = self.tcx.fold_regions(alias_ty, |re, _| {
+                if let ty::ReLateBound(index, bv) = re.kind() {
+                    self.tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
+                } else {
+                    re
+                }
+            });
             self.predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
diff --git a/config.toml.example b/config.toml.example
index 69eb228a2d5..dee0d8f254b 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -46,12 +46,6 @@ changelog-seen = 2
 # Defaults to "if-available" when `channel = "dev"` and "false" otherwise.
 #download-ci-llvm = "if-available"
 
-# Indicates whether LLVM rebuild should be skipped when running bootstrap. If
-# this is `false` then the compiler's LLVM will be rebuilt whenever the built
-# version doesn't have the correct hash. If it is `true` then LLVM will never
-# be rebuilt. The default value is `false`.
-#skip-rebuild = false
-
 # Indicates whether the LLVM build is a Release or Debug build
 #optimize = true
 
@@ -81,11 +75,6 @@ changelog-seen = 2
 # or alternatively ...
 #ccache = "/path/to/ccache"
 
-# If an external LLVM root is specified, we automatically check the version by
-# default to make sure it's within the range that we're expecting, but setting
-# this flag will indicate that this version check should not be done.
-#version-check = true
-
 # When true, link libstdc++ statically into the rustc_llvm.
 # This is useful if you don't want to use the dynamic version of that
 # library provided by LLVM.
@@ -164,6 +153,7 @@ changelog-seen = 2
 # General build configuration options
 # =============================================================================
 [build]
+
 # The default stage to use for the `check` subcommand
 #check-stage = 0
 
@@ -669,6 +659,10 @@ changelog-seen = 2
 # Build compiler with the optimization enabled and -Zvalidate-mir, currently only for `std`
 #validate-mir-opts = 3
 
+# Copy the linker, DLLs, and various libraries from MinGW into the rustc toolchain.
+# Only applies when the host or target is pc-windows-gnu.
+#include-mingw-linker = true
+
 # =============================================================================
 # Options for specific targets
 #
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index e4100120d82..74ef0949b8a 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -20,6 +20,7 @@ mod ops;
 mod pattern;
 mod slice;
 mod str;
+mod tuple;
 
 /// Returns a `rand::Rng` seeded with a consistent seed.
 ///
diff --git a/library/core/benches/tuple.rs b/library/core/benches/tuple.rs
new file mode 100644
index 00000000000..d9ff9d0dd93
--- /dev/null
+++ b/library/core/benches/tuple.rs
@@ -0,0 +1,22 @@
+use rand::prelude::*;
+use test::{black_box, Bencher};
+
+#[bench]
+fn bench_tuple_comparison(b: &mut Bencher) {
+    let mut rng = black_box(super::bench_rng());
+
+    let data = black_box([
+        ("core::iter::adapters::Chain", 123_usize),
+        ("core::iter::adapters::Clone", 456_usize),
+        ("core::iter::adapters::Copie", 789_usize),
+        ("core::iter::adapters::Cycle", 123_usize),
+        ("core::iter::adapters::Flatt", 456_usize),
+        ("core::iter::adapters::TakeN", 789_usize),
+    ]);
+
+    b.iter(|| {
+        let x = data.choose(&mut rng).unwrap();
+        let y = data.choose(&mut rng).unwrap();
+        [x < y, x <= y, x > y, x >= y]
+    });
+}
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 18a90599c4d..c6321587adc 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1585,9 +1585,15 @@ extern "rust-intrinsic" {
 
     /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception
     /// if the argument is not an integer.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
     pub fn rintf32(x: f32) -> f32;
     /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception
     /// if the argument is not an integer.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
     pub fn rintf64(x: f64) -> f64;
 
     /// Returns the nearest integer to an `f32`.
@@ -1610,6 +1616,19 @@ extern "rust-intrinsic" {
     /// [`f64::round`](../../std/primitive.f64.html#method.round)
     pub fn roundf64(x: f64) -> f64;
 
+    /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[cfg(not(bootstrap))]
+    pub fn roundevenf32(x: f32) -> f32;
+    /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[cfg(not(bootstrap))]
+    pub fn roundevenf64(x: f64) -> f64;
+
     /// Float addition that allows optimizations based on algebraic rules.
     /// May assume inputs are finite.
     ///
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index c295a0e0645..3539353240a 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -2,6 +2,7 @@
 
 use crate::intrinsics::assert_unsafe_precondition;
 use crate::intrinsics::const_eval_select;
+use crate::intrinsics::unchecked_sub;
 use crate::ops;
 use crate::ptr;
 
@@ -371,25 +372,25 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
 
     #[inline]
     unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
-        let this = ops::Range { start: self.start, end: self.end };
+        let this = ops::Range { ..self };
         // SAFETY: the caller guarantees that `slice` is not dangling, so it
         // cannot be longer than `isize::MAX`. They also guarantee that
         // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
-        // so the call to `add` is safe.
-
+        // so the call to `add` is safe and the length calculation cannot overflow.
         unsafe {
             assert_unsafe_precondition!(
                 "slice::get_unchecked requires that the range is within the slice",
                 [T](this: ops::Range<usize>, slice: *const [T]) =>
                 this.end >= this.start && this.end <= slice.len()
             );
-            ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
         }
     }
 
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
-        let this = ops::Range { start: self.start, end: self.end };
+        let this = ops::Range { ..self };
         // SAFETY: see comments for `get_unchecked` above.
         unsafe {
             assert_unsafe_precondition!(
@@ -397,7 +398,8 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
                 [T](this: ops::Range<usize>, slice: *mut [T]) =>
                 this.end >= this.start && this.end <= slice.len()
             );
-            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
+            let new_len = unchecked_sub(self.end, self.start);
+            ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
         }
     }
 
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 1cd86b445b0..d319b2bc37f 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1695,7 +1695,13 @@ impl<T> [T] {
         let ptr = self.as_ptr();
 
         // SAFETY: Caller has to check that `0 <= mid <= self.len()`
-        unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) }
+        unsafe {
+            assert_unsafe_precondition!(
+                "slice::split_at_unchecked requires the index to be within the slice",
+                (mid: usize, len: usize) => mid <= len
+            );
+            (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid))
+        }
     }
 
     /// Divides one mutable slice into two at an index, without doing bounds checking.
diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs
index 68f62ce8be5..41c097b55ee 100644
--- a/library/core/src/str/traits.rs
+++ b/library/core/src/str/traits.rs
@@ -1,6 +1,7 @@
 //! Trait implementations for `str`.
 
 use crate::cmp::Ordering;
+use crate::intrinsics::assert_unsafe_precondition;
 use crate::ops;
 use crate::ptr;
 use crate::slice::SliceIndex;
@@ -194,7 +195,21 @@ unsafe impl const SliceIndex<str> for ops::Range<usize> {
         let slice = slice as *const [u8];
         // SAFETY: the caller guarantees that `self` is in bounds of `slice`
         // which satisfies all the conditions for `add`.
-        let ptr = unsafe { slice.as_ptr().add(self.start) };
+        let ptr = unsafe {
+            let this = ops::Range { ..self };
+            assert_unsafe_precondition!(
+                "str::get_unchecked requires that the range is within the string slice",
+                (this: ops::Range<usize>, slice: *const [u8]) =>
+                // We'd like to check that the bounds are on char boundaries,
+                // but there's not really a way to do so without reading
+                // behind the pointer, which has aliasing implications.
+                // It's also not possible to move this check up to
+                // `str::get_unchecked` without adding a special function
+                // to `SliceIndex` just for this.
+                this.end >= this.start && this.end <= slice.len()
+            );
+            slice.as_ptr().add(self.start)
+        };
         let len = self.end - self.start;
         ptr::slice_from_raw_parts(ptr, len) as *const str
     }
@@ -202,7 +217,15 @@ unsafe impl const SliceIndex<str> for ops::Range<usize> {
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
         let slice = slice as *mut [u8];
         // SAFETY: see comments for `get_unchecked`.
-        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
+        let ptr = unsafe {
+            let this = ops::Range { ..self };
+            assert_unsafe_precondition!(
+                "str::get_unchecked_mut requires that the range is within the string slice",
+                (this: ops::Range<usize>, slice: *mut [u8]) =>
+                this.end >= this.start && this.end <= slice.len()
+            );
+            slice.as_mut_ptr().add(self.start)
+        };
         let len = self.end - self.start;
         ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
     }
@@ -272,15 +295,13 @@ unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
     }
     #[inline]
     unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-        let slice = slice as *const [u8];
-        let ptr = slice.as_ptr();
-        ptr::slice_from_raw_parts(ptr, self.end) as *const str
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (0..self.end).get_unchecked(slice) }
     }
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-        let slice = slice as *mut [u8];
-        let ptr = slice.as_mut_ptr();
-        ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (0..self.end).get_unchecked_mut(slice) }
     }
     #[inline]
     fn index(self, slice: &str) -> &Self::Output {
@@ -343,20 +364,15 @@ unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
     }
     #[inline]
     unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
-        let slice = slice as *const [u8];
-        // SAFETY: the caller guarantees that `self` is in bounds of `slice`
-        // which satisfies all the conditions for `add`.
-        let ptr = unsafe { slice.as_ptr().add(self.start) };
-        let len = slice.len() - self.start;
-        ptr::slice_from_raw_parts(ptr, len) as *const str
+        let len = (slice as *const [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+        unsafe { (self.start..len).get_unchecked(slice) }
     }
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
-        let slice = slice as *mut [u8];
-        // SAFETY: identical to `get_unchecked`.
-        let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
-        let len = slice.len() - self.start;
-        ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
+        let len = (slice as *mut [u8]).len();
+        // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+        unsafe { (self.start..len).get_unchecked_mut(slice) }
     }
     #[inline]
     fn index(self, slice: &str) -> &Self::Output {
@@ -452,35 +468,29 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
     type Output = str;
     #[inline]
     fn get(self, slice: &str) -> Option<&Self::Output> {
-        if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) }
+        (0..=self.end).get(slice)
     }
     #[inline]
     fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
-        if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
+        (0..=self.end).get_mut(slice)
     }
     #[inline]
     unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked`.
-        unsafe { (..self.end + 1).get_unchecked(slice) }
+        unsafe { (0..=self.end).get_unchecked(slice) }
     }
     #[inline]
     unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
         // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
-        unsafe { (..self.end + 1).get_unchecked_mut(slice) }
+        unsafe { (0..=self.end).get_unchecked_mut(slice) }
     }
     #[inline]
     fn index(self, slice: &str) -> &Self::Output {
-        if self.end == usize::MAX {
-            str_index_overflow_fail();
-        }
-        (..self.end + 1).index(slice)
+        (0..=self.end).index(slice)
     }
     #[inline]
     fn index_mut(self, slice: &mut str) -> &mut Self::Output {
-        if self.end == usize::MAX {
-            str_index_overflow_fail();
-        }
-        (..self.end + 1).index_mut(slice)
+        (0..=self.end).index_mut(slice)
     }
 }
 
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 28275798f75..0620e7173bc 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,7 @@
 // See src/libstd/primitive_docs.rs for documentation.
 
-use crate::cmp::Ordering::*;
-use crate::cmp::*;
+use crate::cmp::Ordering::{self, *};
+use crate::mem::transmute;
 
 // Recursive macro for implementing n-ary tuple functions and operations
 //
@@ -61,19 +61,19 @@ macro_rules! tuple_impls {
                 }
                 #[inline]
                 fn lt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(lt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+                    lexical_ord!(lt, Less, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
                 }
                 #[inline]
                 fn le(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(le, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+                    lexical_ord!(le, Less, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
                 }
                 #[inline]
                 fn ge(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(ge, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+                    lexical_ord!(ge, Greater, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
                 }
                 #[inline]
                 fn gt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(gt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+                    lexical_ord!(gt, Greater, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
                 }
             }
         }
@@ -123,16 +123,38 @@ macro_rules! maybe_tuple_doc {
     };
 }
 
-// Constructs an expression that performs a lexical ordering using method $rel.
+#[inline]
+const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
+    // FIXME: Just use `==` once that's const-stable on `Option`s.
+    // This isn't using `match` because that optimizes worse due to
+    // making a two-step check (`Some` *then* the inner value).
+
+    // SAFETY: There's no public guarantee for `Option<Ordering>`,
+    // but we're core so we know that it's definitely a byte.
+    unsafe {
+        let c: i8 = transmute(c);
+        let x: i8 = transmute(Some(x));
+        c == x
+    }
+}
+
+// Constructs an expression that performs a lexical ordering using method `$rel`.
 // The values are interleaved, so the macro invocation for
-// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
-// a3, b3)` (and similarly for `lexical_cmp`)
+// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
+// a2, b2, a3, b3)` (and similarly for `lexical_cmp`)
+//
+// `$ne_rel` is only used to determine the result after checking that they're
+// not equal, so `lt` and `le` can both just use `Less`.
 macro_rules! lexical_ord {
-    ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
-        if $a != $b { lexical_ord!($rel, $a, $b) }
-        else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
+    ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
+        let c = PartialOrd::partial_cmp(&$a, &$b);
+        if !ordering_is_some(c, Equal) { ordering_is_some(c, $ne_rel) }
+        else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) }
+    }};
+    ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => {
+        // Use the specific method for the last element
+        PartialOrd::$rel(&$a, &$b)
     };
-    ($rel: ident, $a:expr, $b:expr) => { ($a) . $rel (& $b) };
 }
 
 macro_rules! lexical_partial_cmp {
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 6b1f0cba82d..c7c33678fd3 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -78,10 +78,14 @@ impl f32 {
     /// let f = 3.3_f32;
     /// let g = -3.3_f32;
     /// let h = -3.7_f32;
+    /// let i = 3.5_f32;
+    /// let j = 4.5_f32;
     ///
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -91,6 +95,32 @@ impl f32 {
         unsafe { intrinsics::roundf32(self) }
     }
 
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_ties_even)]
+    ///
+    /// let f = 3.3_f32;
+    /// let g = -3.3_f32;
+    /// let h = 3.5_f32;
+    /// let i = 4.5_f32;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// ```
+    #[rustc_allow_incoherent_impl]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[inline]
+    pub fn round_ties_even(self) -> f32 {
+        unsafe { intrinsics::rintf32(self) }
+    }
+
     /// Returns the integer part of `self`.
     /// This means that non-integer numbers are always truncated towards zero.
     ///
diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
index 6ee295de616..e949def00bb 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/src/f32/tests.rs
@@ -209,6 +209,7 @@ fn test_ceil() {
 
 #[test]
 fn test_round() {
+    assert_approx_eq!(2.5f32.round(), 3.0f32);
     assert_approx_eq!(1.0f32.round(), 1.0f32);
     assert_approx_eq!(1.3f32.round(), 1.0f32);
     assert_approx_eq!(1.5f32.round(), 2.0f32);
@@ -222,6 +223,21 @@ fn test_round() {
 }
 
 #[test]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32);
+    assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32);
+    assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32);
+    assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32);
+    assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32);
+    assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32);
+    assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32);
+    assert_approx_eq!((-1.7f32).round_ties_even(), -2.0f32);
+}
+
+#[test]
 fn test_trunc() {
     assert_approx_eq!(1.0f32.trunc(), 1.0f32);
     assert_approx_eq!(1.3f32.trunc(), 1.0f32);
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 16359766b51..b1faa670307 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -78,10 +78,14 @@ impl f64 {
     /// let f = 3.3_f64;
     /// let g = -3.3_f64;
     /// let h = -3.7_f64;
+    /// let i = 3.5_f64;
+    /// let j = 4.5_f64;
     ///
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -91,6 +95,32 @@ impl f64 {
         unsafe { intrinsics::roundf64(self) }
     }
 
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_ties_even)]
+    ///
+    /// let f = 3.3_f64;
+    /// let g = -3.3_f64;
+    /// let h = 3.5_f64;
+    /// let i = 4.5_f64;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// ```
+    #[rustc_allow_incoherent_impl]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[inline]
+    pub fn round_ties_even(self) -> f64 {
+        unsafe { intrinsics::rintf64(self) }
+    }
+
     /// Returns the integer part of `self`.
     /// This means that non-integer numbers are always truncated towards zero.
     ///
diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs
index 5b039d445ce..53d351cceef 100644
--- a/library/std/src/f64/tests.rs
+++ b/library/std/src/f64/tests.rs
@@ -199,6 +199,7 @@ fn test_ceil() {
 
 #[test]
 fn test_round() {
+    assert_approx_eq!(2.5f64.round(), 3.0f64);
     assert_approx_eq!(1.0f64.round(), 1.0f64);
     assert_approx_eq!(1.3f64.round(), 1.0f64);
     assert_approx_eq!(1.5f64.round(), 2.0f64);
@@ -212,6 +213,21 @@ fn test_round() {
 }
 
 #[test]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64);
+    assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64);
+    assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64);
+    assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64);
+    assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64);
+    assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64);
+    assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64);
+    assert_approx_eq!((-1.7f64).round_ties_even(), -2.0f64);
+}
+
+#[test]
 fn test_trunc() {
     assert_approx_eq!(1.0f64.trunc(), 1.0f64);
     assert_approx_eq!(1.3f64.trunc(), 1.0f64);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b62f3ad29d3..7837dd276d2 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -304,6 +304,7 @@
 #![feature(provide_any)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
+#![feature(round_ties_even)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(std_internals)]
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 4105fa5ec96..648eb553c78 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - `remote-test-server`'s `verbose` argument has been removed in favor of the `--verbose` flag
 - `remote-test-server`'s `remote` argument has been removed in favor of the `--bind` flag. Use `--bind 0.0.0.0:12345` to replicate the behavior of the `remote` argument.
 - `x.py fmt` now formats only files modified between the merge-base of HEAD and the last commit in the master branch of the rust-lang repository and the current working directory. To restore old behaviour, use `x.py fmt .`. The check mode is not affected by this change. [#105702](https://github.com/rust-lang/rust/pull/105702)
+- The `llvm.version-check` config option has been removed. Older versions were never supported. If you still need to support older versions (e.g. you are applying custom patches), patch `check_llvm_version` in bootstrap to change the minimum version. [#108619](https://github.com/rust-lang/rust/pull/108619)
 
 ### Non-breaking changes
 
diff --git a/src/bootstrap/bolt.rs b/src/bootstrap/bolt.rs
index ea37cd47049..973dc4f602b 100644
--- a/src/bootstrap/bolt.rs
+++ b/src/bootstrap/bolt.rs
@@ -1,46 +1,40 @@
 use std::path::Path;
 use std::process::Command;
 
-/// Uses the `llvm-bolt` binary to instrument the binary/library at the given `path` with BOLT.
+/// Uses the `llvm-bolt` binary to instrument the artifact at the given `path` with BOLT.
 /// When the instrumented artifact is executed, it will generate BOLT profiles into
 /// `/tmp/prof.fdata.<pid>.fdata`.
-pub fn instrument_with_bolt_inplace(path: &Path) {
-    let dir = std::env::temp_dir();
-    let instrumented_path = dir.join("instrumented.so");
-
+/// Creates the instrumented artifact at `output_path`.
+pub fn instrument_with_bolt(path: &Path, output_path: &Path) {
     let status = Command::new("llvm-bolt")
         .arg("-instrument")
         .arg(&path)
         // Make sure that each process will write its profiles into a separate file
         .arg("--instrumentation-file-append-pid")
         .arg("-o")
-        .arg(&instrumented_path)
+        .arg(output_path)
         .status()
         .expect("Could not instrument artifact using BOLT");
 
     if !status.success() {
         panic!("Could not instrument {} with BOLT, exit code {:?}", path.display(), status.code());
     }
-
-    std::fs::copy(&instrumented_path, path).expect("Cannot copy instrumented artifact");
-    std::fs::remove_file(instrumented_path).expect("Cannot delete instrumented artifact");
 }
 
-/// Uses the `llvm-bolt` binary to optimize the binary/library at the given `path` with BOLT,
+/// Uses the `llvm-bolt` binary to optimize the artifact at the given `path` with BOLT,
 /// using merged profiles from `profile_path`.
 ///
 /// The recorded profiles have to be merged using the `merge-fdata` tool from LLVM and the merged
 /// profile path should be then passed to this function.
-pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
-    let dir = std::env::temp_dir();
-    let optimized_path = dir.join("optimized.so");
-
+///
+/// Creates the optimized artifact at `output_path`.
+pub fn optimize_with_bolt(path: &Path, profile_path: &Path, output_path: &Path) {
     let status = Command::new("llvm-bolt")
         .arg(&path)
         .arg("-data")
         .arg(&profile_path)
         .arg("-o")
-        .arg(&optimized_path)
+        .arg(output_path)
         // Reorder basic blocks within functions
         .arg("-reorder-blocks=ext-tsp")
         // Reorder functions within the binary
@@ -65,7 +59,4 @@ pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
     if !status.success() {
         panic!("Could not optimize {} with BOLT, exit code {:?}", path.display(), status.code());
     }
-
-    std::fs::copy(&optimized_path, path).expect("Cannot copy optimized artifact");
-    std::fs::remove_file(optimized_path).expect("Cannot delete optimized artifact");
 }
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 05e74254949..4f417d36511 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -112,14 +112,12 @@ pub struct Config {
     pub backtrace_on_ice: bool,
 
     // llvm codegen options
-    pub llvm_skip_rebuild: bool,
     pub llvm_assertions: bool,
     pub llvm_tests: bool,
     pub llvm_plugins: bool,
     pub llvm_optimize: bool,
     pub llvm_thin_lto: bool,
     pub llvm_release_debuginfo: bool,
-    pub llvm_version_check: bool,
     pub llvm_static_stdcpp: bool,
     /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm.
     #[cfg(not(test))]
@@ -192,6 +190,7 @@ pub struct Config {
     pub dist_sign_folder: Option<PathBuf>,
     pub dist_upload_addr: Option<String>,
     pub dist_compression_formats: Option<Vec<String>>,
+    pub dist_include_mingw_linker: bool,
 
     // libstd features
     pub backtrace: bool, // support for RUST_BACKTRACE
@@ -666,7 +665,6 @@ define_config! {
 define_config! {
     /// TOML representation of how the LLVM build is configured.
     struct Llvm {
-        skip_rebuild: Option<bool> = "skip-rebuild",
         optimize: Option<bool> = "optimize",
         thin_lto: Option<bool> = "thin-lto",
         release_debuginfo: Option<bool> = "release-debuginfo",
@@ -674,7 +672,6 @@ define_config! {
         tests: Option<bool> = "tests",
         plugins: Option<bool> = "plugins",
         ccache: Option<StringOrBool> = "ccache",
-        version_check: Option<bool> = "version-check",
         static_libstdcpp: Option<bool> = "static-libstdcpp",
         ninja: Option<bool> = "ninja",
         targets: Option<String> = "targets",
@@ -704,6 +701,7 @@ define_config! {
         src_tarball: Option<bool> = "src-tarball",
         missing_tools: Option<bool> = "missing-tools",
         compression_formats: Option<Vec<String>> = "compression-formats",
+        include_mingw_linker: Option<bool> = "include-mingw-linker",
     }
 }
 
@@ -806,7 +804,6 @@ impl Config {
         let mut config = Config::default();
         config.llvm_optimize = true;
         config.ninja_in_file = true;
-        config.llvm_version_check = true;
         config.llvm_static_stdcpp = false;
         config.backtrace = true;
         config.rust_optimize = true;
@@ -821,6 +818,7 @@ impl Config {
         config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")];
         config.deny_warnings = true;
         config.bindir = "bin".into();
+        config.dist_include_mingw_linker = true;
 
         // set by build.rs
         config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
@@ -1060,11 +1058,6 @@ impl Config {
             config.mandir = install.mandir.map(PathBuf::from);
         }
 
-        // We want the llvm-skip-rebuild flag to take precedence over the
-        // skip-rebuild config.toml option so we store it separately
-        // so that we can infer the right value
-        let mut llvm_skip_rebuild = flags.llvm_skip_rebuild;
-
         // Store off these values as options because if they're not provided
         // we'll infer default values for them later
         let mut llvm_assertions = None;
@@ -1170,11 +1163,9 @@ impl Config {
             llvm_assertions = llvm.assertions;
             llvm_tests = llvm.tests;
             llvm_plugins = llvm.plugins;
-            llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild);
             set(&mut config.llvm_optimize, llvm.optimize);
             set(&mut config.llvm_thin_lto, llvm.thin_lto);
             set(&mut config.llvm_release_debuginfo, llvm.release_debuginfo);
-            set(&mut config.llvm_version_check, llvm.version_check);
             set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
             if let Some(v) = llvm.link_shared {
                 config.llvm_link_shared.set(Some(v));
@@ -1311,6 +1302,7 @@ impl Config {
             config.dist_compression_formats = t.compression_formats;
             set(&mut config.rust_dist_src, t.src_tarball);
             set(&mut config.missing_tools, t.missing_tools);
+            set(&mut config.dist_include_mingw_linker, t.include_mingw_linker)
         }
 
         if let Some(r) = build.rustfmt {
@@ -1324,7 +1316,6 @@ impl Config {
         // Now that we've reached the end of our configuration, infer the
         // default values for all options that we haven't otherwise stored yet.
 
-        config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false);
         config.llvm_assertions = llvm_assertions.unwrap_or(false);
         config.llvm_tests = llvm_tests.unwrap_or(false);
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index ab3d0829296..5278f0c10b3 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -44,7 +44,6 @@ o("local-rebuild", "build.local-rebuild", "assume local-rust matches the current
 o("llvm-static-stdcpp", "llvm.static-libstdcpp", "statically link to libstdc++ for LLVM")
 o("llvm-link-shared", "llvm.link-shared", "prefer shared linking to LLVM (llvm-config --link-shared)")
 o("rpath", "rust.rpath", "build rpaths into rustc itself")
-o("llvm-version-check", "llvm.version-check", "check if the LLVM version is supported, build anyway")
 o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
 o("option-checking", None, "complain about unrecognized options in this configure script")
 o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
@@ -488,6 +487,22 @@ for section_key, section_config in config.items():
     else:
         configure_section(sections[section_key], section_config)
 
+def write_uncommented(target, f):
+    block = []
+    is_comment = True
+
+    for line in target:
+        block.append(line)
+        if len(line) == 0:
+            if not is_comment:
+                for l in block:
+                    f.write(l + "\n")
+            block = []
+            is_comment = True
+            continue
+        is_comment = is_comment and line.startswith('#')
+    return f
+
 # Now that we've built up our `config.toml`, write it all out in the same
 # order that we read it in.
 p("")
@@ -496,11 +511,9 @@ with bootstrap.output('config.toml') as f:
     for section in section_order:
         if section == 'target':
             for target in targets:
-                for line in targets[target]:
-                    f.write(line + "\n")
+                f = write_uncommented(targets[target], f)
         else:
-            for line in sections[section]:
-                f.write(line + "\n")
+            f = write_uncommented(sections[section], f)
 
 with bootstrap.output('Makefile') as f:
     contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
diff --git a/src/bootstrap/defaults/config.codegen.toml b/src/bootstrap/defaults/config.codegen.toml
index 088cbd1057e..eb2afa555f1 100644
--- a/src/bootstrap/defaults/config.codegen.toml
+++ b/src/bootstrap/defaults/config.codegen.toml
@@ -17,3 +17,5 @@ debug-logging = true
 incremental = true
 # Print backtrace on internal compiler errors during bootstrap
 backtrace-on-ice = true
+# Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
+lto = "off"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 9b2b549612d..c9384004100 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -18,7 +18,9 @@ use std::process::Command;
 
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
+use sha2::Digest;
 
+use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::channel;
@@ -322,7 +324,7 @@ impl Step for Mingw {
     /// without any extra installed software (e.g., we bundle gcc, libraries, etc).
     fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
         let host = self.host;
-        if !host.ends_with("pc-windows-gnu") {
+        if !host.ends_with("pc-windows-gnu") || !builder.config.dist_include_mingw_linker {
             return None;
         }
 
@@ -378,7 +380,7 @@ impl Step for Rustc {
         // anything requiring us to distribute a license, but it's likely the
         // install will *also* include the rust-mingw package, which also needs
         // licenses, so to be safe we just include it here in all MinGW packages.
-        if host.ends_with("pc-windows-gnu") {
+        if host.ends_with("pc-windows-gnu") && builder.config.dist_include_mingw_linker {
             make_win_dist(tarball.image_dir(), &tmpdir(builder), host, builder);
             tarball.add_dir(builder.src.join("src/etc/third-party"), "share/doc");
         }
@@ -1904,6 +1906,26 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
     }
 }
 
+fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
+    if builder.config.dry_run() {
+        return;
+    }
+
+    // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
+    // This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
+    // We perform the instrumentation/optimization here, on the fly, just before they are being
+    // packaged into some destination directory.
+    let postprocessed = if builder.config.llvm_bolt_profile_generate {
+        builder.ensure(BoltInstrument::new(source.to_path_buf()))
+    } else if let Some(path) = &builder.config.llvm_bolt_profile_use {
+        builder.ensure(BoltOptimize::new(source.to_path_buf(), path.into()))
+    } else {
+        source.to_path_buf()
+    };
+
+    builder.install(&postprocessed, destination, 0o644);
+}
+
 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
 ///
 /// Returns whether the files were actually copied.
@@ -1955,7 +1977,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
             } else {
                 PathBuf::from(file)
             };
-            builder.install(&file, dst_libdir, 0o644);
+            install_llvm_file(builder, &file, dst_libdir);
         }
         !builder.config.dry_run()
     } else {
@@ -1986,6 +2008,117 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
     }
 }
 
+/// Creates an output path to a BOLT-manipulated artifact for the given `file`.
+/// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
+/// files with the same name.
+///
+/// We need to keep the file-name the same though, to make sure that copying the manipulated file
+/// to a directory will not change the final file path.
+fn create_bolt_output_path(builder: &Builder<'_>, file: &Path, hash: &str) -> PathBuf {
+    let directory = builder.out.join("bolt").join(hash);
+    t!(fs::create_dir_all(&directory));
+    directory.join(file.file_name().unwrap())
+}
+
+/// Instrument the provided file with BOLT.
+/// Returns a path to the instrumented artifact.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct BoltInstrument {
+    file: PathBuf,
+    hash: String,
+}
+
+impl BoltInstrument {
+    fn new(file: PathBuf) -> Self {
+        let mut hasher = sha2::Sha256::new();
+        hasher.update(t!(fs::read(&file)));
+        let hash = hex::encode(hasher.finalize().as_slice());
+
+        Self { file, hash }
+    }
+}
+
+impl Step for BoltInstrument {
+    type Output = PathBuf;
+
+    const ONLY_HOSTS: bool = false;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        if builder.build.config.dry_run() {
+            return self.file.clone();
+        }
+
+        if builder.build.config.llvm_from_ci {
+            println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
+        }
+
+        println!("Instrumenting {} with BOLT", self.file.display());
+
+        let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
+        if !output_path.is_file() {
+            instrument_with_bolt(&self.file, &output_path);
+        }
+        output_path
+    }
+}
+
+/// Optimize the provided file with BOLT.
+/// Returns a path to the optimized artifact.
+///
+/// The hash is stored in the step to make sure that we don't optimize the same file
+/// twice (even under  different file paths).
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct BoltOptimize {
+    file: PathBuf,
+    profile: PathBuf,
+    hash: String,
+}
+
+impl BoltOptimize {
+    fn new(file: PathBuf, profile: PathBuf) -> Self {
+        let mut hasher = sha2::Sha256::new();
+        hasher.update(t!(fs::read(&file)));
+        hasher.update(t!(fs::read(&profile)));
+        let hash = hex::encode(hasher.finalize().as_slice());
+
+        Self { file, profile, hash }
+    }
+}
+
+impl Step for BoltOptimize {
+    type Output = PathBuf;
+
+    const ONLY_HOSTS: bool = false;
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.never()
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        if builder.build.config.dry_run() {
+            return self.file.clone();
+        }
+
+        if builder.build.config.llvm_from_ci {
+            println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
+        }
+
+        println!("Optimizing {} with BOLT", self.file.display());
+
+        let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
+        if !output_path.is_file() {
+            optimize_with_bolt(&self.file, &self.profile, &output_path);
+        }
+        output_path
+    }
+}
+
 #[derive(Clone, Debug, Eq, Hash, PartialEq)]
 pub struct LlvmTools {
     pub target: TargetSelection,
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 9d1504c34e8..2b0b772a618 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -67,8 +67,6 @@ pub struct Flags {
     // true => deny, false => warn
     pub deny_warnings: Option<bool>,
 
-    pub llvm_skip_rebuild: Option<bool>,
-
     pub rust_profile_use: Option<String>,
     pub rust_profile_generate: Option<String>,
 
@@ -251,14 +249,6 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
         opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
         opts.optopt(
             "",
-            "llvm-skip-rebuild",
-            "whether rebuilding llvm should be skipped \
-             a VALUE of TRUE indicates that llvm will not be rebuilt \
-             VALUE overrides the skip-rebuild option in config.toml.",
-            "VALUE",
-        );
-        opts.optopt(
-            "",
             "rust-profile-generate",
             "generate PGO profile with rustc build",
             "PROFILE",
@@ -714,9 +704,6 @@ Arguments:
                 .collect::<Vec<_>>(),
             include_default_paths: matches.opt_present("include-default-paths"),
             deny_warnings: parse_deny_warnings(&matches),
-            llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
-                |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
-            ),
             color: matches
                 .opt_get_default("color", Color::Auto)
                 .expect("`color` should be `always`, `never`, or `auto`"),
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index 6d5753e8a6d..5cb94c2f1d6 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -2,6 +2,7 @@
 
 use crate::builder::Builder;
 use crate::util::{output, program_out_of_date, t};
+use build_helper::ci::CiEnv;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 use std::collections::VecDeque;
@@ -144,8 +145,10 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
             let untracked_paths = untracked_paths_output
                 .lines()
                 .filter(|entry| entry.starts_with("??"))
-                .map(|entry| {
-                    entry.split(' ').nth(1).expect("every git status entry should list a path")
+                .filter_map(|entry| {
+                    let path =
+                        entry.split(' ').nth(1).expect("every git status entry should list a path");
+                    path.ends_with(".rs").then_some(path)
                 });
             for untracked_path in untracked_paths {
                 println!("skip untracked path {} during rustfmt invocations", untracked_path);
@@ -156,7 +159,10 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
                 // preventing the latter from being formatted.
                 ignore_fmt.add(&format!("!/{}", untracked_path)).expect(&untracked_path);
             }
-            if !check && paths.is_empty() {
+            // Only check modified files locally to speed up runtime.
+            // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through;
+            // we also care about CI time less since this is still very fast compared to building the compiler.
+            if !CiEnv::is_ci() && paths.is_empty() {
                 match get_modified_rs_files(build) {
                     Ok(Some(files)) => {
                         for file in files {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 5987b641b39..909e7d83a15 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -16,7 +16,6 @@ use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use crate::bolt::{instrument_with_bolt_inplace, optimize_library_with_bolt_inplace};
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::channel;
 use crate::config::{Config, TargetSelection};
@@ -109,15 +108,6 @@ pub fn prebuilt_llvm_config(
     let stamp = out_dir.join("llvm-finished-building");
     let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
 
-    if builder.config.llvm_skip_rebuild && stamp.path.exists() {
-        builder.info(
-            "Warning: \
-                Using a potentially stale build of LLVM; \
-                This may not behave well.",
-        );
-        return Ok(res);
-    }
-
     if stamp.is_done() {
         if stamp.hash.is_none() {
             builder.info(
@@ -523,39 +513,13 @@ impl Step for Llvm {
             }
         }
 
-        // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file
-        // in place. This is fine, because currently we do not support incrementally rebuilding
-        // LLVM after a configuration change, so to rebuild it the build files have to be removed,
-        // which will also remove these modified files.
-        if builder.config.llvm_bolt_profile_generate {
-            instrument_with_bolt_inplace(&get_built_llvm_lib_path(&res.llvm_config));
-        }
-        if let Some(path) = &builder.config.llvm_bolt_profile_use {
-            optimize_library_with_bolt_inplace(
-                &get_built_llvm_lib_path(&res.llvm_config),
-                &Path::new(path),
-            );
-        }
-
         t!(stamp.write());
 
         res
     }
 }
 
-/// Returns path to a built LLVM library (libLLVM.so).
-/// Assumes that we have built LLVM into a single library file.
-fn get_built_llvm_lib_path(llvm_config_path: &Path) -> PathBuf {
-    let mut cmd = Command::new(llvm_config_path);
-    cmd.arg("--libfiles");
-    PathBuf::from(output(&mut cmd).trim())
-}
-
 fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
-    if !builder.config.llvm_version_check {
-        return;
-    }
-
     if builder.config.dry_run() {
         return;
     }
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index 4480bce99d7..09f26862b4a 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -24,7 +24,7 @@ pub enum Profile {
     None,
 }
 
-/// A list of historical hashes of `src/etc/vscode_settings.json`.
+/// A list of historical hashes of `src/etc/rust_analyzer_settings.json`.
 /// New entries should be appended whenever this is updated so we can detect
 /// outdated vs. user-modified settings files.
 static SETTINGS_HASHES: &[&str] = &[
@@ -32,7 +32,7 @@ static SETTINGS_HASHES: &[&str] = &[
     "56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
     "af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
 ];
-static VSCODE_SETTINGS: &str = include_str!("../etc/vscode_settings.json");
+static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
 
 impl Profile {
     fn include_path(&self, src_path: &Path) -> PathBuf {
@@ -489,7 +489,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks."
     Ok(())
 }
 
-/// Sets up or displays `src/etc/vscode_settings.json`
+/// Sets up or displays `src/etc/rust_analyzer_settings.json`
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 pub struct Vscode;
 
@@ -580,10 +580,10 @@ fn create_vscode_settings_maybe(config: &Config) -> io::Result<()> {
             }
             _ => "Created",
         };
-        fs::write(&vscode_settings, &VSCODE_SETTINGS)?;
+        fs::write(&vscode_settings, &RUST_ANALYZER_SETTINGS)?;
         println!("{verb} `.vscode/settings.json`");
     } else {
-        println!("\n{VSCODE_SETTINGS}");
+        println!("\n{RUST_ANALYZER_SETTINGS}");
     }
     Ok(())
 }
diff --git a/src/bootstrap/setup/tests.rs b/src/bootstrap/setup/tests.rs
index dcf9d18e632..0fe6e4a4644 100644
--- a/src/bootstrap/setup/tests.rs
+++ b/src/bootstrap/setup/tests.rs
@@ -1,14 +1,14 @@
-use super::{SETTINGS_HASHES, VSCODE_SETTINGS};
+use super::{RUST_ANALYZER_SETTINGS, SETTINGS_HASHES};
 use sha2::Digest;
 
 #[test]
 fn check_matching_settings_hash() {
     let mut hasher = sha2::Sha256::new();
-    hasher.update(&VSCODE_SETTINGS);
+    hasher.update(&RUST_ANALYZER_SETTINGS);
     let hash = hex::encode(hasher.finalize().as_slice());
     assert_eq!(
         &hash,
         SETTINGS_HASHES.last().unwrap(),
-        "Update `SETTINGS_HASHES` with the new hash of `src/etc/vscode_settings.json`"
+        "Update `SETTINGS_HASHES` with the new hash of `src/etc/rust_analyzer_settings.json`"
     );
 }
diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py
index bd8fd524a26..fe3083dc31e 100644
--- a/src/ci/stage-build.py
+++ b/src/ci/stage-build.py
@@ -798,14 +798,16 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
                     "--llvm-profile-use",
                     pipeline.llvm_profile_merged_file(),
                     "--llvm-bolt-profile-generate",
+                    "--rust-profile-use",
+                    pipeline.rustc_profile_merged_file()
                 ])
                 record_metrics(pipeline, rustc_build)
 
             with stage3.section("Gather profiles"):
                 gather_llvm_bolt_profiles(pipeline)
 
+        # LLVM is not being cleared here, we want to reuse the previous build
         print_free_disk_space(pipeline)
-        clear_llvm_files(pipeline)
         final_build_args += [
             "--llvm-bolt-profile-use",
             pipeline.llvm_bolt_profile_merged_file()
diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
index 432e0cfc960..32d3440f1dc 100644
--- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
@@ -26,7 +26,6 @@ Therefore, you can build Rust with support for the target by adding it to the ta
 ```toml
 [llvm]
 download-ci-llvm = false
-skip-rebuild = true
 optimize = true
 ninja = true
 targets = "ARM;X86"
diff --git a/src/doc/unstable-book/src/compiler-flags/cf-protection.md b/src/doc/unstable-book/src/compiler-flags/cf-protection.md
index ab698c82ba9..efe5f5642b8 100644
--- a/src/doc/unstable-book/src/compiler-flags/cf-protection.md
+++ b/src/doc/unstable-book/src/compiler-flags/cf-protection.md
@@ -1,5 +1,9 @@
 # `cf-protection`
 
+The tracking issue for this feature is: [#93754](https://github.com/rust-lang/rust/issues/93754).
+
+------------------------
+
 This option enables control-flow enforcement technology (CET) on x86; a more detailed description of
 CET is available [here]. Similar to `clang`, this flag takes one of the following values:
 
diff --git a/src/etc/vscode_settings.json b/src/etc/rust_analyzer_settings.json
index dd01bfaa725..dd01bfaa725 100644
--- a/src/etc/vscode_settings.json
+++ b/src/etc/rust_analyzer_settings.json
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index c48f7998c5a..6ca6edfd3c9 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -8,7 +8,7 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
-askama = { version = "0.11", default-features = false, features = ["config"] }
+askama = { version = "0.12", default-features = false, features = ["config"] }
 itertools = "0.10.1"
 minifier = "0.2.2"
 once_cell = "1.10.0"
diff --git a/src/librustdoc/askama.toml b/src/librustdoc/askama.toml
index 0c984f637ba..2732c4bc61e 100644
--- a/src/librustdoc/askama.toml
+++ b/src/librustdoc/askama.toml
@@ -1,2 +1,3 @@
 [general]
 dirs = ["html/templates"]
+whitespace = "suppress"
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0e8f0cfc518..bbd9f18973a 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::InternalSubsts;
 use rustc_middle::ty::TypeVisitableExt;
-use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::hygiene::{AstPass, MacroKind};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 27d18aad7a3..6d8380c5fcc 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -22,7 +22,7 @@ use rustc_hir::{BodyId, Mutability};
 use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility};
+use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c9c1c2c458a..cafb00df51e 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -17,7 +17,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 0e4c5ed6836..f9ea829e388 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -19,7 +19,6 @@ use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty;
-use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::kw;
 use rustc_span::{sym, Symbol};
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 2869a39613f..08796f10d92 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1839,6 +1839,12 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
         } else {
             let size = layout.size.bytes() - tag_size;
             write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" },);
+            if layout.abi.is_uninhabited() {
+                write!(
+                    w,
+                    " (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)"
+                );
+            }
         }
     }
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 090ea2cb157..e22ac6ec19b 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -7,9 +7,7 @@ use rustc_span::symbol::Symbol;
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
-use crate::clean::types::{
-    FnRetTy, Function, GenericBound, Generics, ItemId, Type, WherePredicate,
-};
+use crate::clean::types::{FnRetTy, Function, Generics, ItemId, Type, WherePredicate};
 use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
 use crate::html::format::join_with_double_colon;
@@ -482,29 +480,23 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>(
     if let Type::Generic(arg_s) = *arg {
         // First we check if the bounds are in a `where` predicate...
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
-            WherePredicate::BoundPredicate { ty, .. } => ty.def_id(cache) == arg.def_id(cache),
+            WherePredicate::BoundPredicate { ty: Type::Generic(ty_s), .. } => *ty_s == arg_s,
             _ => false,
         }) {
             let mut ty_generics = Vec::new();
             let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
             for bound in bounds.iter() {
-                if let GenericBound::TraitBound(poly_trait, _) = bound {
-                    for param_def in poly_trait.generic_params.iter() {
-                        match &param_def.kind {
-                            clean::GenericParamDefKind::Type { default: Some(ty), .. } => {
-                                add_generics_and_bounds_as_types(
-                                    self_,
-                                    generics,
-                                    ty,
-                                    tcx,
-                                    recurse + 1,
-                                    &mut ty_generics,
-                                    cache,
-                                )
-                            }
-                            _ => {}
-                        }
-                    }
+                if let Some(path) = bound.get_trait_path() {
+                    let ty = Type::Path { path };
+                    add_generics_and_bounds_as_types(
+                        self_,
+                        generics,
+                        &ty,
+                        tcx,
+                        recurse + 1,
+                        &mut ty_generics,
+                        cache,
+                    );
                 }
             }
             insert_ty(res, arg.clone(), ty_generics);
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
index fff65e3b5ff..72c516c93eb 100644
--- a/src/librustdoc/html/templates/STYLE.md
+++ b/src/librustdoc/html/templates/STYLE.md
@@ -10,28 +10,29 @@ similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [As
 
 We want our rendered output to have as little unnecessary whitespace as
 possible, so that pages load quickly. To achieve that we use Tera's
-[whitespace control] features. At the end of most lines, we put an empty comment
-tag with the whitespace control characters: `{#- -#}`. This causes all
-whitespace between the end of the line and the beginning of the next, including
-indentation, to be omitted on render. Sometimes we want to preserve a single
-space. In those cases we put the space at the end of the line, followed by
-`{# -#}`, which is a directive to remove following whitespace but not preceding.
-We also use the whitespace control characters in most instances of tags with
-control flow, for example `{%- if foo -%}`.
+[whitespace control] features. By default, whitespace characters are removed
+around jinja tags (`{% %}` for example). At the end of most lines, we put an
+empty comment tag: `{# #}`. This causes all whitespace between the end of the
+line and the beginning of the next, including indentation, to be omitted on
+render. Sometimes we want to preserve a single space. In those cases we put the
+space at the end of the line, followed by `{#+ #}`, which is a directive to
+remove following whitespace but not preceding. We also use the whitespace
+control characters in most instances of tags with control flow, for example
+`{% if foo %}`.
 
 [whitespace control]: https://tera.netlify.app/docs/#whitespace-control
 
 We want our templates to be readable, so we use indentation and newlines
-liberally. We indent by four spaces after opening an HTML tag _or_ a Tera
+liberally. We indent by four spaces after opening an HTML tag _or_ a Jinja
 tag. In most cases an HTML tag should be followed by a newline, but if the
 tag has simple contents and fits with its close tag on a single line, the
 contents don't necessarily need a new line.
 
-Tera templates support quite sophisticated control flow. To keep our templates
+Askama templates support quite sophisticated control flow. To keep our templates
 simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic](assignments) and [Tera
+we avoid [assignments in the template logic](assignments) and [Askama
 macros](macros). This also may make things easier if we switch to a different
 Jinja-style template system, like Askama, in the future.
 
-[assignments]: https://tera.netlify.app/docs/#assignments
-[macros]: https://tera.netlify.app/docs/#macros
+[assignments]: https://djc.github.io/askama/template_syntax.html#assignments
+[macros]: https://djc.github.io/askama/template_syntax.html#macros
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 7690d8f251f..e896850fab6 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -1,148 +1,148 @@
-<!DOCTYPE html> {#- -#}
-<html lang="en"> {#- -#}
-<head> {#- -#}
-    <meta charset="utf-8"> {#- -#}
-    <meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
-    <meta name="generator" content="rustdoc"> {#- -#}
-    <meta name="description" content="{{page.description}}"> {#- -#}
-    <title>{{page.title}}</title> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_medium}}"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_regular}}"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_bold}}"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_semibold}}"> {#- -#}
-    <link rel="stylesheet" {# -#}
-          href="{{static_root_path|safe}}{{files.normalize_css}}"> {#- -#}
-    <link rel="stylesheet" {# -#}
-          href="{{static_root_path|safe}}{{files.rustdoc_css}}" {# -#}
-          id="mainThemeStyle"> {#- -#}
-    <link rel="stylesheet" id="themeStyle" href="{{static_root_path|safe}}{{files.theme_light_css}}"> {#- -#}
-    <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {#- -#}
-    <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_ayu_css}}"> {#- -#}
-    {%- for theme in themes -%}
-        <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
-    {%- endfor -%}
-    {%- if !layout.default_settings.is_empty() -%}
-    <script id="default-settings" {# -#}
-      {% for (k, v) in layout.default_settings %}
+<!DOCTYPE html> {# #}
+<html lang="en"> {# #}
+<head> {# #}
+    <meta charset="utf-8"> {# #}
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"> {# #}
+    <meta name="generator" content="rustdoc"> {# #}
+    <meta name="description" content="{{page.description}}"> {# #}
+    <title>{{page.title}}</title> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_medium}}"> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_regular}}"> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_bold}}"> {# #}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_semibold}}"> {# #}
+    <link rel="stylesheet" {#+ #}
+          href="{{static_root_path|safe}}{{files.normalize_css}}"> {# #}
+    <link rel="stylesheet" {#+ #}
+          href="{{static_root_path|safe}}{{files.rustdoc_css}}" {#+ #}
+          id="mainThemeStyle"> {# #}
+    <link rel="stylesheet" id="themeStyle" href="{{static_root_path|safe}}{{files.theme_light_css}}"> {# #}
+    <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {# #}
+    <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_ayu_css}}"> {# #}
+    {% for theme in themes %}
+        <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {# #}
+    {% endfor %}
+    {% if !layout.default_settings.is_empty() %}
+    <script id="default-settings" {#+ #}
+      {%~ for (k, v) in layout.default_settings ~%}
         data-{{k}}="{{v}}"
-      {%- endfor -%}
-    ></script> {#- -#}
-    {%- endif -%}
-    <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
-    {%- if page.css_class.contains("crate") -%}
-    <script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
-    {%- else if page.css_class == "source" -%}
-    <script defer src="{{static_root_path|safe}}{{files.source_script_js}}"></script> {#- -#}
-    <script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {#- -#}
-    {%- else if !page.css_class.contains("mod") -%}
-    <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {#- -#}
-    {%- endif -%}
-    <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {#- -#}
-    {%- if layout.scrape_examples_extension -%}
-    <script defer src="{{static_root_path|safe}}{{files.scrape_examples_js}}"></script> {#- -#}
-    {%- endif -%}
-    <noscript> {#- -#}
-        <link rel="stylesheet" {# -#}
-           href="{{static_root_path|safe}}{{files.noscript_css}}"> {#- -#}
-    </noscript> {#- -#}
-    {%- if layout.css_file_extension.is_some() -%}
-        <link rel="stylesheet" {# -#}
-            href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
-    {%- endif -%}
-    {%- if !layout.favicon.is_empty() -%}
-        <link rel="icon" href="{{layout.favicon}}"> {#- -#}
-    {%- else -%}
-        <link rel="alternate icon" type="image/png" {# -#}
-            href="{{static_root_path|safe}}{{files.rust_favicon_png_16}}"> {#- -#}
-        <link rel="alternate icon" type="image/png" {# -#}
-            href="{{static_root_path|safe}}{{files.rust_favicon_png_32}}"> {#- -#}
-        <link rel="icon" type="image/svg+xml" {# -#}
-            href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {#- -#}
-    {%- endif -%}
-    {{- layout.external_html.in_header|safe -}}
-</head> {#- -#}
-<body class="rustdoc {{page.css_class}}"> {#- -#}
-    <!--[if lte IE 11]> {#- -#}
-    <div class="warning"> {#- -#}
-        This old browser is unsupported and will most likely display funky things. {#- -#}
-    </div> {#- -#}
-    <![endif]--> {#- -#}
-    {{- layout.external_html.before_content|safe -}}
-    {%- if page.css_class != "source" -%}
-    <nav class="mobile-topbar"> {#- -#}
-        <button class="sidebar-menu-toggle">&#9776;</button> {#- -#}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
-        {%- if !layout.logo.is_empty() -%}
-            <img src="{{layout.logo}}" alt="logo"> {#- -#}
-        {%- else -%}
-            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
-        {%- endif -%}
-        </a> {#- -#}
-        <h2></h2> {#- -#}
-    </nav> {#- -#}
-    {%- endif -%}
-    <nav class="sidebar"> {#- -#}
-        {%- if page.css_class != "source" -%}
-        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
-            {%- if !layout.logo.is_empty()  %}
-                <img src="{{layout.logo}}" alt="logo"> {#- -#}
-            {%- else -%}
-                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
-            {%- endif -%}
-        </a> {#- -#}
-        {%- endif -%}
-        {{- sidebar|safe -}}
-    </nav> {#- -#}
-    <main> {#- -#}
-        {%- if page.css_class != "source" -%}<div class="width-limiter">{%- endif -%}
-            <nav class="sub"> {#- -#}
-                {%- if page.css_class == "source" -%}
-                <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
-                    {%- if !layout.logo.is_empty()  %}
-                        <img src="{{layout.logo}}" alt="logo"> {#- -#}
-                    {%- else -%}
-                        <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
-                    {%- endif -%}
-                </a> {#- -#}
-                {%- endif -%}
-                <form class="search-form"> {#- -#}
-                    <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
-                    <input {# -#}
-                        class="search-input" {# -#}
-                        name="search" {# -#}
-                        aria-label="Run search in the documentation" {# -#}
-                        autocomplete="off" {# -#}
-                        spellcheck="false" {# -#}
-                        placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
-                        type="search"> {#- -#}
-                    <div id="help-button" title="help" tabindex="-1"> {#- -#}
-                        <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
-                    </div> {#- -#}
-                    <div id="settings-menu" tabindex="-1"> {#- -#}
-                        <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
-                            <img width="22" height="22" alt="Change settings" {# -#}
-                            src="{{static_root_path|safe}}{{files.wheel_svg}}"> {#- -#}
-                        </a> {#- -#}
-                    </div> {#- -#}
-                </form> {#- -#}
-            </nav> {#- -#}
-            <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
-        {%- if page.css_class != "source" -%}</div>{%- endif -%}
-    </main> {#- -#}
-    {{- layout.external_html.after_content|safe -}}
-    <div id="rustdoc-vars" {# -#}
-         data-root-path="{{page.root_path|safe}}" {# -#}
-         data-static-root-path="{{static_root_path|safe}}" {# -#}
-         data-current-crate="{{layout.krate}}" {# -#}
-         data-themes="{{themes|join(",") }}" {# -#}
-         data-resource-suffix="{{page.resource_suffix}}" {# -#}
-         data-rustdoc-version="{{rustdoc_version}}" {# -#}
-         data-search-js="{{files.search_js}}" {# -#}
-         data-settings-js="{{files.settings_js}}" {# -#}
-         data-settings-css="{{files.settings_css}}" {# -#}
-    > {#- -#}
-    </div> {#- -#}
-</body> {#- -#}
-</html> {#- -#}
+      {% endfor %}
+    ></script> {# #}
+    {% endif %}
+    <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {# #}
+    {% if page.css_class.contains("crate") %}
+    <script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {# #}
+    {% else if page.css_class == "source" %}
+    <script defer src="{{static_root_path|safe}}{{files.source_script_js}}"></script> {# #}
+    <script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {# #}
+    {% else if !page.css_class.contains("mod") %}
+    <script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {# #}
+    {% endif %}
+    <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {# #}
+    {% if layout.scrape_examples_extension %}
+    <script defer src="{{static_root_path|safe}}{{files.scrape_examples_js}}"></script> {# #}
+    {% endif %}
+    <noscript> {# #}
+        <link rel="stylesheet" {#+ #}
+           href="{{static_root_path|safe}}{{files.noscript_css}}"> {# #}
+    </noscript> {# #}
+    {% if layout.css_file_extension.is_some() %}
+        <link rel="stylesheet" {#+ #}
+            href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {# #}
+    {% endif %}
+    {% if !layout.favicon.is_empty() %}
+        <link rel="icon" href="{{layout.favicon}}"> {# #}
+    {% else %}
+        <link rel="alternate icon" type="image/png" {#+ #}
+            href="{{static_root_path|safe}}{{files.rust_favicon_png_16}}"> {# #}
+        <link rel="alternate icon" type="image/png" {#+ #}
+            href="{{static_root_path|safe}}{{files.rust_favicon_png_32}}"> {# #}
+        <link rel="icon" type="image/svg+xml" {#+ #}
+            href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {# #}
+    {% endif %}
+    {{ layout.external_html.in_header|safe }}
+</head> {# #}
+<body class="rustdoc {{+page.css_class}}"> {# #}
+    <!--[if lte IE 11]> {# #}
+    <div class="warning"> {# #}
+        This old browser is unsupported and will most likely display funky things. {# #}
+    </div> {# #}
+    <![endif]--> {# #}
+    {{ layout.external_html.before_content|safe }}
+    {% if page.css_class != "source" %}
+    <nav class="mobile-topbar"> {# #}
+        <button class="sidebar-menu-toggle">&#9776;</button> {# #}
+        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
+        {% if !layout.logo.is_empty() %}
+            <img src="{{layout.logo}}" alt="logo"> {# #}
+        {% else %}
+            <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+        {% endif %}
+        </a> {# #}
+        <h2></h2> {# #}
+    </nav> {# #}
+    {% endif %}
+    <nav class="sidebar"> {# #}
+        {% if page.css_class != "source" %}
+        <a class="logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
+            {% if !layout.logo.is_empty() %}
+                <img src="{{layout.logo}}" alt="logo"> {# #}
+            {% else %}
+                <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+            {% endif %}
+        </a> {# #}
+        {% endif %}
+        {{ sidebar|safe }}
+    </nav> {# #}
+    <main> {# #}
+        {% if page.css_class != "source" %}<div class="width-limiter">{% endif %}
+            <nav class="sub"> {# #}
+                {% if page.css_class == "source" %}
+                <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {# #}
+                    {% if !layout.logo.is_empty() %}
+                        <img src="{{layout.logo}}" alt="logo"> {# #}
+                    {% else %}
+                        <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {# #}
+                    {% endif %}
+                </a> {# #}
+                {% endif %}
+                <form class="search-form"> {# #}
+                    <span></span> {# This empty span is a hacky fix for Safari - See #93184 #}
+                    <input {#+ #}
+                        class="search-input" {#+ #}
+                        name="search" {#+ #}
+                        aria-label="Run search in the documentation" {#+ #}
+                        autocomplete="off" {#+ #}
+                        spellcheck="false" {#+ #}
+                        placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {#+ #}
+                        type="search"> {# #}
+                    <div id="help-button" title="help" tabindex="-1"> {# #}
+                        <a href="{{page.root_path|safe}}help.html">?</a> {# #}
+                    </div> {# #}
+                    <div id="settings-menu" tabindex="-1"> {# #}
+                        <a href="{{page.root_path|safe}}settings.html" title="settings"> {# #}
+                            <img width="22" height="22" alt="Change settings" {#+ #}
+                            src="{{static_root_path|safe}}{{files.wheel_svg}}"> {# #}
+                        </a> {# #}
+                    </div> {# #}
+                </form> {# #}
+            </nav> {# #}
+            <section id="main-content" class="content">{{ content|safe }}</section> {# #}
+        {% if page.css_class != "source" %}</div>{% endif %}
+    </main> {# #}
+    {{ layout.external_html.after_content|safe }}
+    <div id="rustdoc-vars" {#+ #}
+         data-root-path="{{page.root_path|safe}}" {#+ #}
+         data-static-root-path="{{static_root_path|safe}}" {#+ #}
+         data-current-crate="{{layout.krate}}" {#+ #}
+         data-themes="{{themes|join(",") }}" {#+ #}
+         data-resource-suffix="{{page.resource_suffix}}" {#+ #}
+         data-rustdoc-version="{{rustdoc_version}}" {#+ #}
+         data-search-js="{{files.search_js}}" {#+ #}
+         data-settings-js="{{files.settings_js}}" {#+ #}
+         data-settings-css="{{files.settings_css}}" {#+ #}
+    > {# #}
+    </div> {# #}
+</body> {# #}
+</html> {# #}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 3a1867b7feb..edabac9a082 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -1,28 +1,28 @@
-<div class="main-heading"> {#- -#}
-    <h1> {#- -#}
-        {{-typ-}}
-        {#- The breadcrumbs of the item path, like std::string -#}
-        {%- for component in path_components -%}
-        <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
-        {%- endfor -%}
-        <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
-        <button id="copy-path" title="Copy item path to clipboard"> {#- -#}
-        <img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#}
-                width="19" height="18" {# -#}
-                alt="Copy item path"> {#- -#}
-        </button> {#- -#}
-    </h1> {#- -#}
-    <span class="out-of-band"> {#- -#}
+<div class="main-heading"> {# #}
+    <h1> {# #}
+        {{typ}}
+        {# The breadcrumbs of the item path, like std::string #}
+        {% for component in path_components %}
+            <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
+        {% endfor %}
+        <a class="{{item_type}}" href="#">{{name}}</a> {# #}
+        <button id="copy-path" title="Copy item path to clipboard"> {# #}
+        <img src="{{static_root_path|safe}}{{clipboard_svg}}" {#+ #}
+                width="19" height="18" {#+ #}
+                alt="Copy item path"> {# #}
+        </button> {# #}
+    </h1> {# #}
+    <span class="out-of-band"> {# #}
         {% if !stability_since_raw.is_empty() %}
-        {{- stability_since_raw|safe }} · {# -#}
+        {{ stability_since_raw|safe +}} · {#+ #}
         {% endif %}
-        {%- match src_href -%}
-            {%- when Some with (href) -%}
-                <a class="srclink" href="{{href|safe}}">source</a> · {# -#}
-            {%- else -%}
-        {%- endmatch -%}
-        <button id="toggle-all-docs" title="collapse all docs"> {#- -#}
-            [<span>&#x2212;</span>] {#- -#}
-        </button> {#- -#}
-    </span> {#- -#}
-</div> {#- -#}
+        {% match src_href %}
+            {% when Some with (href) %}
+                <a class="srclink" href="{{href|safe}}">source</a> · {#+ #}
+            {% else %}
+        {% endmatch %}
+        <button id="toggle-all-docs" title="collapse all docs"> {# #}
+            [<span>&#x2212;</span>] {# #}
+        </button> {# #}
+    </span> {# #}
+</div> {# #}
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 0b22f943dab..be5286b24d7 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -8,7 +8,6 @@ use crate::visit::DocVisitor;
 use rustc_hir as hir;
 use rustc_lint::builtin::MISSING_DOCS;
 use rustc_middle::lint::LintLevelSource;
-use rustc_middle::ty::DefIdTree;
 use rustc_session::lint;
 use rustc_span::FileName;
 use serde::Serialize;
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index a39d57d42b7..6b13e6c9581 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -14,7 +14,6 @@ use crate::visit::DocVisitor;
 use crate::visit_ast::inherits_doc_hidden;
 use rustc_hir as hir;
 use rustc_middle::lint::LintLevelSource;
-use rustc_middle::ty::DefIdTree;
 use rustc_session::lint;
 
 pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index cbfc581389c..bcb69d1a4ca 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -13,7 +13,7 @@ use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{DefKind, Namespace, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
 use rustc_hir::Mutability;
-use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{bug, ty};
 use rustc_resolve::rustdoc::MalformedGenerics;
 use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, strip_generics_from_path};
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 01ed4a60b3b..d32e8185d3f 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -9,7 +9,7 @@ use crate::visit::DocVisitor;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty;
 use rustc_span::symbol::sym;
 
 pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs
index a4bc486900b..f35643af637 100644
--- a/src/librustdoc/passes/propagate_doc_cfg.rs
+++ b/src/librustdoc/passes/propagate_doc_cfg.rs
@@ -9,7 +9,6 @@ use crate::fold::DocFolder;
 use crate::passes::Pass;
 
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::DefIdTree;
 
 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 277201e4de9..5bbbff175cf 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -8,7 +8,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
 use rustc_hir::intravisit::{walk_item, Visitor};
 use rustc_hir::{Node, CRATE_HIR_ID};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{DefIdTree, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
diff --git a/src/rustdoc-json-types/Cargo.toml b/src/rustdoc-json-types/Cargo.toml
index d60699efd36..d63caa7ad70 100644
--- a/src/rustdoc-json-types/Cargo.toml
+++ b/src/rustdoc-json-types/Cargo.toml
@@ -8,6 +8,7 @@ path = "lib.rs"
 
 [dependencies]
 serde = { version = "1.0", features = ["derive"] }
+rustc-hash = "1.1.0"
 
 [dev-dependencies]
 serde_json = "1.0"
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 387d5787dfc..4c210291b11 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -3,10 +3,9 @@
 //! These types are the public API exposed through the `--output-format json` flag. The [`Crate`]
 //! struct is the root of the JSON blob and all other items are contained within.
 
-use std::collections::HashMap;
-use std::path::PathBuf;
-
+use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
+use std::path::PathBuf;
 
 /// rustdoc format-version.
 pub const FORMAT_VERSION: u32 = 24;
@@ -24,11 +23,11 @@ pub struct Crate {
     pub includes_private: bool,
     /// A collection of all items in the local crate as well as some external traits and their
     /// items that are referenced locally.
-    pub index: HashMap<Id, Item>,
+    pub index: FxHashMap<Id, Item>,
     /// Maps IDs to fully qualified paths and other info helpful for generating links.
-    pub paths: HashMap<Id, ItemSummary>,
+    pub paths: FxHashMap<Id, ItemSummary>,
     /// Maps `crate_id` of items to a crate name and html_root_url if it exists.
-    pub external_crates: HashMap<u32, ExternalCrate>,
+    pub external_crates: FxHashMap<u32, ExternalCrate>,
     /// A single version number to be used in the future when making backwards incompatible changes
     /// to the JSON output.
     pub format_version: u32,
@@ -54,8 +53,8 @@ pub struct ItemSummary {
     ///
     /// Note that items can appear in multiple paths, and the one chosen is implementation
     /// defined. Currently, this is the full path to where the item was defined. Eg
-    /// [`String`] is currently `["alloc", "string", "String"]` and [`HashMap`] is
-    /// `["std", "collections", "hash", "map", "HashMap"]`, but this is subject to change.
+    /// [`String`] is currently `["alloc", "string", "String"]` and [`HashMap`][`std::collections::HashMap`]
+    /// is `["std", "collections", "hash", "map", "HashMap"]`, but this is subject to change.
     pub path: Vec<String>,
     /// Whether this item is a struct, trait, macro, etc.
     pub kind: ItemKind,
@@ -80,7 +79,7 @@ pub struct Item {
     /// Some("") if there is some documentation but it is empty (EG `#[doc = ""]`).
     pub docs: Option<String>,
     /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
-    pub links: HashMap<String, Id>,
+    pub links: FxHashMap<String, Id>,
     /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
     pub attrs: Vec<String>,
     pub deprecation: Option<Deprecation>,
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index f95b8ccf067..c5f4e943f4f 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -8,7 +8,7 @@ use rustc_hir::{
     Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{AdtDef, DefIdTree};
+use rustc_middle::ty::AdtDef;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 8c27c09404b..1e02a30e35f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -9,7 +9,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, Pat, PatKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty;
 use rustc_span::source_map::Span;
 
 /// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 9a84068d448..0e22485db2c 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -8,7 +8,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::{self as hir, Expr, ExprKind, QPath};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::DefIdTree;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::{sym, Span};
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 587c926dc01..6447899f2b9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -10,7 +10,6 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{OptionNone, ResultErr};
 use rustc_hir::{Arm, Expr, PatKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::DefIdTree;
 use rustc_span::sym;
 
 use super::MANUAL_UNWRAP_OR;
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 81bebff34c8..df0ea7f5b86 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -12,7 +12,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
+use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
 use rustc_span::{sym, Symbol};
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 4720a6e6888..8e1130cf8df 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -8,7 +8,6 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::{LangItem, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::ty::DefIdTree;
 use rustc_span::Span;
 
 pub(crate) struct OptionAndThenSome;
diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
index 56b7fbb9d4b..079df2226d1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_lint::Lint;
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty;
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 pub(super) fn check(
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
index 3a23ecc50dc..41ceef19e3a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_or_none.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
-use rustc_middle::ty::DefIdTree;
 use rustc_span::symbol::sym;
 
 use super::OPTION_MAP_OR_NONE;
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 9659ca8ced2..5b1f03fc16c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -13,7 +13,7 @@ use if_chain::if_chain;
 use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{DefIdTree, Visibility};
+use rustc_middle::ty::Visibility;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 97c8cfbd3eb..e2a7ba02a04 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::DefIdTree;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index d6b336bef94..a13bc7a5188 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -2,7 +2,6 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{def::Res, HirId, Path, PathSegment};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::DefIdTree;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, symbol::kw, Span};
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 688a8b865f3..f8978e30a8e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::interpret::ConstValue;
-use rustc_middle::ty::{self};
+use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Symbol;
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index b59ef4086cd..14ed1368e03 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index f02f8ecb43d..bcfedd07ed1 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -104,7 +104,7 @@ use rustc_middle::ty::fast_reject::SimplifiedType::{
     PtrSimplifiedType, SliceSimplifiedType, StrSimplifiedType, UintSimplifiedType,
 };
 use rustc_middle::ty::{
-    layout::IntegerExt, BorrowKind, ClosureKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture,
+    layout::IntegerExt, BorrowKind, ClosureKind, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, UpvarCapture,
 };
 use rustc_middle::ty::{FloatTy, IntTy, UintTy};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 25654e6957b..41e34eba0ad 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -16,7 +16,7 @@ use rustc_infer::infer::{
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, DefIdTree, FnSig, IntTy, List, ParamEnv, Predicate,
+    self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate,
     PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
     TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
diff --git a/src/tools/jsondoclint/Cargo.toml b/src/tools/jsondoclint/Cargo.toml
index 8990310a4f4..1318a1f4476 100644
--- a/src/tools/jsondoclint/Cargo.toml
+++ b/src/tools/jsondoclint/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2021"
 anyhow = "1.0.62"
 clap = { version = "4.0.15", features = ["derive"] }
 fs-err = "2.8.1"
+rustc-hash = "1.1.0"
 rustdoc-json-types = { version = "0.1.0", path = "../../rustdoc-json-types" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.85"
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index 1ef41ff123a..95a56a9dfac 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -1,5 +1,4 @@
-use std::collections::HashMap;
-
+use rustc_hash::FxHashMap;
 use rustdoc_json_types::{Crate, Item, ItemKind, ItemSummary, Visibility, FORMAT_VERSION};
 
 use crate::json_find::SelectorPart;
@@ -27,7 +26,7 @@ fn errors_on_missing_links() {
         root: id("0"),
         crate_version: None,
         includes_private: false,
-        index: HashMap::from_iter([(
+        index: FxHashMap::from_iter([(
             id("0"),
             Item {
                 name: Some("root".to_owned()),
@@ -36,7 +35,7 @@ fn errors_on_missing_links() {
                 span: None,
                 visibility: Visibility::Public,
                 docs: None,
-                links: HashMap::from_iter([("Not Found".to_owned(), id("1"))]),
+                links: FxHashMap::from_iter([("Not Found".to_owned(), id("1"))]),
                 attrs: vec![],
                 deprecation: None,
                 inner: ItemEnum::Module(Module {
@@ -46,8 +45,8 @@ fn errors_on_missing_links() {
                 }),
             },
         )]),
-        paths: HashMap::new(),
-        external_crates: HashMap::new(),
+        paths: FxHashMap::default(),
+        external_crates: FxHashMap::default(),
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
@@ -73,7 +72,7 @@ fn errors_on_local_in_paths_and_not_index() {
         root: id("0:0:1572"),
         crate_version: None,
         includes_private: false,
-        index: HashMap::from_iter([
+        index: FxHashMap::from_iter([
             (
                 id("0:0:1572"),
                 Item {
@@ -83,7 +82,7 @@ fn errors_on_local_in_paths_and_not_index() {
                     span: None,
                     visibility: Visibility::Public,
                     docs: None,
-                    links: HashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]),
+                    links: FxHashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]),
                     attrs: Vec::new(),
                     deprecation: None,
                     inner: ItemEnum::Module(Module {
@@ -102,14 +101,14 @@ fn errors_on_local_in_paths_and_not_index() {
                     span: None,
                     visibility: Visibility::Public,
                     docs: None,
-                    links: HashMap::default(),
+                    links: FxHashMap::default(),
                     attrs: Vec::new(),
                     deprecation: None,
                     inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
                 },
             ),
         ]),
-        paths: HashMap::from_iter([(
+        paths: FxHashMap::from_iter([(
             id("0:1:1571"),
             ItemSummary {
                 crate_id: 0,
@@ -117,7 +116,7 @@ fn errors_on_local_in_paths_and_not_index() {
                 kind: ItemKind::Primitive,
             },
         )]),
-        external_crates: HashMap::default(),
+        external_crates: FxHashMap::default(),
         format_version: rustdoc_json_types::FORMAT_VERSION,
     };
 
@@ -137,7 +136,7 @@ fn checks_local_crate_id_is_correct() {
         root: id("root"),
         crate_version: None,
         includes_private: false,
-        index: HashMap::from_iter([(
+        index: FxHashMap::from_iter([(
             id("root"),
             Item {
                 id: id("root"),
@@ -146,7 +145,7 @@ fn checks_local_crate_id_is_correct() {
                 span: None,
                 visibility: Visibility::Public,
                 docs: None,
-                links: HashMap::default(),
+                links: FxHashMap::default(),
                 attrs: Vec::new(),
                 deprecation: None,
                 inner: ItemEnum::Module(Module {
@@ -156,8 +155,8 @@ fn checks_local_crate_id_is_correct() {
                 }),
             },
         )]),
-        paths: HashMap::default(),
-        external_crates: HashMap::default(),
+        paths: FxHashMap::default(),
+        external_crates: FxHashMap::default(),
         format_version: FORMAT_VERSION,
     };
     check(&krate, &[]);
diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs
index 33b35d05415..864e68de55d 100644
--- a/src/tools/replace-version-placeholder/src/main.rs
+++ b/src/tools/replace-version-placeholder/src/main.rs
@@ -10,7 +10,7 @@ fn main() {
     let version_str = version_str.trim();
     walk::walk(
         &root_path,
-        &mut |path| {
+        |path| {
             walk::filter_dirs(path)
                 // We exempt these as they require the placeholder
                 // for their operation
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index ea5780f66d7..e617ceba3b9 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -2,8 +2,8 @@ const fs = require('fs');
 const path = require('path');
 
 function loadContent(content) {
-    var Module = module.constructor;
-    var m = new Module();
+    const Module = module.constructor;
+    const m = new Module();
     m._compile(content, "tmp.js");
     m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
         content.startsWith("// ignore-order\n");
@@ -26,8 +26,8 @@ function contentToDiffLine(key, value) {
 // the diff between the two items.
 function betterLookingDiff(entry, data) {
     let output = ' {\n';
-    let spaces = '     ';
-    for (let key in entry) {
+    const spaces = '     ';
+    for (const key in entry) {
         if (!entry.hasOwnProperty(key)) {
             continue;
         }
@@ -35,7 +35,7 @@ function betterLookingDiff(entry, data) {
             output += '-' + spaces + contentToDiffLine(key, entry[key]) + '\n';
             continue;
         }
-        let value = data[key];
+        const value = data[key];
         if (value !== entry[key]) {
             output += '-' + spaces + contentToDiffLine(key, entry[key]) + '\n';
             output += '+' + spaces + contentToDiffLine(key, value) + '\n';
@@ -47,19 +47,19 @@ function betterLookingDiff(entry, data) {
 }
 
 function lookForEntry(entry, data) {
-    for (var i = 0; i < data.length; ++i) {
-        var allGood = true;
-        for (var key in entry) {
+    return data.findIndex(data_entry => {
+        let allGood = true;
+        for (const key in entry) {
             if (!entry.hasOwnProperty(key)) {
                 continue;
             }
-            var value = data[i][key];
+            let value = data_entry[key];
             // To make our life easier, if there is a "parent" type, we add it to the path.
-            if (key === 'path' && data[i]['parent'] !== undefined) {
+            if (key === 'path' && data_entry['parent'] !== undefined) {
                 if (value.length > 0) {
-                    value += '::' + data[i]['parent']['name'];
+                    value += '::' + data_entry['parent']['name'];
                 } else {
-                    value = data[i]['parent']['name'];
+                    value = data_entry['parent']['name'];
                 }
             }
             if (value !== entry[key]) {
@@ -67,11 +67,8 @@ function lookForEntry(entry, data) {
                 break;
             }
         }
-        if (allGood === true) {
-            return i;
-        }
-    }
-    return null;
+        return allGood === true;
+    });
 }
 
 // This function checks if `expected` has all the required fields needed for the checks.
@@ -97,13 +94,12 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position)
     } else {
         fieldsToCheck = [];
     }
-    for (var i = 0; i < fieldsToCheck.length; ++i) {
-        const field = fieldsToCheck[i];
+    for (const field of fieldsToCheck) {
         if (!expected.hasOwnProperty(field)) {
             let text = `${queryName}==> Mandatory key \`${field}\` is not present`;
             if (fullPath.length > 0) {
                 text += ` in field \`${fullPath}\``;
-                if (position != null) {
+                if (position !== null) {
                     text += ` (position ${position})`;
                 }
             }
@@ -114,7 +110,8 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position)
 
 function valueCheck(fullPath, expected, result, error_text, queryName) {
     if (Array.isArray(expected)) {
-        for (var i = 0; i < expected.length; ++i) {
+        let i;
+        for (i = 0; i < expected.length; ++i) {
             checkNeededFields(fullPath, expected[i], error_text, queryName, i);
             if (i >= result.length) {
                 error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +
@@ -154,8 +151,8 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
             valueCheck(obj_path, expected[key], result_v, error_text, queryName);
         }
     } else {
-        expectedValue = JSON.stringify(expected);
-        resultValue = JSON.stringify(result);
+        const expectedValue = JSON.stringify(expected);
+        const resultValue = JSON.stringify(result);
         if (expectedValue != resultValue) {
             error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +
                 `EXPECTED: \`${expectedValue}\`\nRESULT:   \`${resultValue}\``);
@@ -164,7 +161,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
 }
 
 function runParser(query, expected, parseQuery, queryName) {
-    var error_text = [];
+    const error_text = [];
     checkNeededFields("", expected, error_text, queryName, null);
     if (error_text.length === 0) {
         valueCheck('', expected, parseQuery(query), error_text, queryName);
@@ -176,10 +173,10 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
     const ignore_order = loadedFile.ignore_order;
     const exact_check = loadedFile.exact_check;
 
-    var results = doSearch(query, loadedFile.FILTER_CRATE);
-    var error_text = [];
+    const results = doSearch(query, loadedFile.FILTER_CRATE);
+    const error_text = [];
 
-    for (var key in expected) {
+    for (const key in expected) {
         if (!expected.hasOwnProperty(key)) {
             continue;
         }
@@ -187,37 +184,37 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) {
             error_text.push('==> Unknown key "' + key + '"');
             break;
         }
-        var entry = expected[key];
+        const entry = expected[key];
 
         if (exact_check == true && entry.length !== results[key].length) {
             error_text.push(queryName + "==> Expected exactly " + entry.length +
                             " results but found " + results[key].length + " in '" + key + "'");
         }
 
-        var prev_pos = -1;
-        for (var i = 0; i < entry.length; ++i) {
-            var entry_pos = lookForEntry(entry[i], results[key]);
-            if (entry_pos === null) {
+        let prev_pos = -1;
+        entry.forEach((elem, index) => {
+            const entry_pos = lookForEntry(elem, results[key]);
+            if (entry_pos === -1) {
                 error_text.push(queryName + "==> Result not found in '" + key + "': '" +
-                                JSON.stringify(entry[i]) + "'");
+                                JSON.stringify(elem) + "'");
                 // By default, we just compare the two first items.
                 let item_to_diff = 0;
-                if ((ignore_order === false || exact_check === true) && i < results[key].length) {
-                    item_to_diff = i;
+                if ((!ignore_order || exact_check) && index < results[key].length) {
+                    item_to_diff = index;
                 }
                 error_text.push("Diff of first error:\n" +
-                    betterLookingDiff(entry[i], results[key][item_to_diff]));
+                    betterLookingDiff(elem, results[key][item_to_diff]));
             } else if (exact_check === true && prev_pos + 1 !== entry_pos) {
                 error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) +
-                                ": expected '" + JSON.stringify(entry[i]) + "' but found '" +
-                                JSON.stringify(results[key][i]) + "'");
+                                ": expected '" + JSON.stringify(elem) + "' but found '" +
+                                JSON.stringify(results[key][index]) + "'");
             } else if (ignore_order === false && entry_pos < prev_pos) {
-                error_text.push(queryName + "==> '" + JSON.stringify(entry[i]) + "' was supposed " +
+                error_text.push(queryName + "==> '" + JSON.stringify(elem) + "' was supposed " +
                                 "to be before '" + JSON.stringify(results[key][entry_pos]) + "'");
             } else {
                 prev_pos = entry_pos;
             }
-        }
+        });
     }
     return error_text;
 }
@@ -252,15 +249,15 @@ function runCheck(loadedFile, key, callback) {
             console.log(`==> QUERY variable should have the same length as ${key}`);
             return 1;
         }
-        for (var i = 0; i < query.length; ++i) {
-            var error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
+        for (let i = 0; i < query.length; ++i) {
+            const error_text = callback(query[i], expected[i], "[ query `" + query[i] + "`]");
             if (checkResult(error_text, loadedFile, false) !== 0) {
                 return 1;
             }
         }
         console.log("OK");
     } else {
-        var error_text = callback(query, expected, "");
+        const error_text = callback(query, expected, "");
         if (checkResult(error_text, loadedFile, true) !== 0) {
             return 1;
         }
@@ -269,9 +266,9 @@ function runCheck(loadedFile, key, callback) {
 }
 
 function runChecks(testFile, doSearch, parseQuery) {
-    var checkExpected = false;
-    var checkParsed = false;
-    var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
+    let checkExpected = false;
+    let checkParsed = false;
+    let testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;';
 
     if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
         testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
@@ -294,7 +291,7 @@ function runChecks(testFile, doSearch, parseQuery) {
     }
 
     const loadedFile = loadContent(testFileContent);
-    var res = 0;
+    let res = 0;
 
     if (checkExpected) {
         res += runCheck(loadedFile, "EXPECTED", (query, expected, text) => {
@@ -323,8 +320,7 @@ function loadSearchJS(doc_folder, resource_suffix) {
     const searchIndex = require(searchIndexJs);
 
     const staticFiles = path.join(doc_folder, "static.files");
-    const searchJs = fs.readdirSync(staticFiles).find(
-        f => f.match(/search.*\.js$/));
+    const searchJs = fs.readdirSync(staticFiles).find(f => f.match(/search.*\.js$/));
     const searchModule = require(path.join(staticFiles, searchJs));
     const searchWords = searchModule.initSearch(searchIndex.searchIndex);
 
@@ -334,7 +330,7 @@ function loadSearchJS(doc_folder, resource_suffix) {
                 filterCrate, currentCrate);
         },
         parseQuery: searchModule.parseQuery,
-    }
+    };
 }
 
 function showHelp() {
@@ -349,14 +345,14 @@ function showHelp() {
 }
 
 function parseOptions(args) {
-    var opts = {
+    const opts = {
         "crate_name": "",
         "resource_suffix": "",
         "doc_folder": "",
         "test_folder": "",
         "test_file": [],
     };
-    var correspondences = {
+    const correspondences = {
         "--resource-suffix": "resource_suffix",
         "--doc-folder": "doc_folder",
         "--test-folder": "test_folder",
@@ -364,7 +360,7 @@ function parseOptions(args) {
         "--crate-name": "crate_name",
     };
 
-    for (var i = 0; i < args.length; ++i) {
+    for (let i = 0; i < args.length; ++i) {
         if (correspondences.hasOwnProperty(args[i])) {
             i += 1;
             if (i >= args.length) {
@@ -398,17 +394,18 @@ function parseOptions(args) {
 }
 
 function main(argv) {
-    var opts = parseOptions(argv.slice(2));
+    const opts = parseOptions(argv.slice(2));
     if (opts === null) {
         return 1;
     }
 
-    let parseAndSearch = loadSearchJS(
+    const parseAndSearch = loadSearchJS(
         opts["doc_folder"],
-        opts["resource_suffix"]);
-    var errors = 0;
+        opts["resource_suffix"]
+    );
+    let errors = 0;
 
-    let doSearch = function (queryStr, filterCrate) {
+    const doSearch = function (queryStr, filterCrate) {
         return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]);
     };
 
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index f913f6cde38..9bfee1efc0b 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -95,7 +95,7 @@ fn check_section<'a>(
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
-    walk(path, &mut filter_dirs, &mut |entry, contents| {
+    walk(path, filter_dirs, &mut |entry, contents| {
         let file = &entry.path().display();
 
         let mut lines = contents.lines().enumerate().peekable();
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index b898f20a5d0..2d6abe59343 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -101,54 +101,38 @@ mod os_impl {
 
         const ALLOWED: &[&str] = &["configure", "x"];
 
-        walk_no_read(
-            path,
-            &mut |path| {
-                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 extension = file.extension();
-                let scripts = ["py", "sh", "ps1"];
-                if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
-                    return;
-                }
+        // FIXME: we don't need to look at all binaries, only files that have been modified in this branch
+        // (e.g. using `git ls-files`).
+        walk_no_read(path, |path| filter_dirs(path) || path.ends_with("src/etc"), &mut |entry| {
+            let file = entry.path();
+            let extension = file.extension();
+            let scripts = ["py", "sh", "ps1"];
+            if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
+                return;
+            }
 
-                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 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;
-                    }
+                if ALLOWED.contains(&git_friendly_path.as_str()) {
+                    return;
+                }
 
-                    let output = Command::new("git")
-                        .arg("ls-files")
-                        .arg(&git_friendly_path)
-                        .current_dir(path)
-                        .stderr(Stdio::null())
-                        .output()
-                        .unwrap_or_else(|e| {
-                            panic!("could not run git ls-files: {e}");
-                        });
-                    let path_bytes = rel_path.as_os_str().as_bytes();
-                    if output.status.success() && output.stdout.starts_with(path_bytes) {
-                        tidy_error!(bad, "binary checked into source: {}", file.display());
-                    }
+                let output = Command::new("git")
+                    .arg("ls-files")
+                    .arg(&git_friendly_path)
+                    .current_dir(path)
+                    .stderr(Stdio::null())
+                    .output()
+                    .unwrap_or_else(|e| {
+                        panic!("could not run git ls-files: {e}");
+                    });
+                let path_bytes = rel_path.as_os_str().as_bytes();
+                if output.status.success() && output.stdout.starts_with(path_bytes) {
+                    tidy_error!(bad, "binary checked into source: {}", file.display());
                 }
-            },
-        )
+            }
+        })
     }
 }
diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs
index 0dd9c1e160c..2241375eaae 100644
--- a/src/tools/tidy/src/debug_artifacts.rs
+++ b/src/tools/tidy/src/debug_artifacts.rs
@@ -6,7 +6,7 @@ use std::path::Path;
 const GRAPHVIZ_POSTFLOW_MSG: &str = "`borrowck_graphviz_postflow` attribute in test";
 
 pub fn check(test_dir: &Path, bad: &mut bool) {
-    walk(test_dir, &mut filter_dirs, &mut |entry, contents| {
+    walk(test_dir, filter_dirs, &mut |entry, contents| {
         let filename = entry.path();
         let is_rust = filename.extension().map_or(false, |ext| ext == "rs");
         if !is_rust {
diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs
index 8172e3d292b..67d9c30a04f 100644
--- a/src/tools/tidy/src/edition.rs
+++ b/src/tools/tidy/src/edition.rs
@@ -9,27 +9,20 @@ fn is_edition_2021(mut line: &str) -> bool {
 }
 
 pub fn check(path: &Path, bad: &mut bool) {
-    walk(
-        path,
-        &mut |path| {
-            filter_dirs(path)
-                || (path.ends_with("tests") && path.join("COMPILER_TESTS.md").exists())
-        },
-        &mut |entry, contents| {
-            let file = entry.path();
-            let filename = file.file_name().unwrap();
-            if filename != "Cargo.toml" {
-                return;
-            }
+    walk(path, |path| filter_dirs(path), &mut |entry, contents| {
+        let file = entry.path();
+        let filename = file.file_name().unwrap();
+        if filename != "Cargo.toml" {
+            return;
+        }
 
-            let is_2021 = contents.lines().any(is_edition_2021);
-            if !is_2021 {
-                tidy_error!(
-                    bad,
-                    "{} doesn't have `edition = \"2021\"` on a separate line",
-                    file.display()
-                );
-            }
-        },
-    );
+        let is_2021 = contents.lines().any(is_edition_2021);
+        if !is_2021 {
+            tidy_error!(
+                bad,
+                "{} doesn't have `edition = \"2021\"` on a separate line",
+                file.display()
+            );
+        }
+    });
 }
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index c60caa0d49c..a8375050614 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -46,8 +46,10 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
 
     // Stage 1: create list
     let error_codes = extract_error_codes(root_path, &mut errors);
-    println!("Found {} error codes", error_codes.len());
-    println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
+    if verbose {
+        println!("Found {} error codes", error_codes.len());
+        println!("Highest error code: `{}`", error_codes.iter().max().unwrap());
+    }
 
     // Stage 2: check list has docs
     let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut errors, verbose);
@@ -127,7 +129,7 @@ fn check_error_codes_docs(
 
     let mut no_longer_emitted_codes = Vec::new();
 
-    walk(&docs_path, &mut |_| false, &mut |entry, contents| {
+    walk(&docs_path, |_| false, &mut |entry, contents| {
         let path = entry.path();
 
         // Error if the file isn't markdown.
@@ -319,7 +321,7 @@ fn check_error_codes_used(
 
     let mut found_codes = Vec::new();
 
-    walk_many(search_paths, &mut filter_dirs, &mut |entry, contents| {
+    walk_many(search_paths, filter_dirs, &mut |entry, contents| {
         let path = entry.path();
 
         // Return early if we aren't looking at a source file.
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index af92e6eb863..6d94417a10f 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -101,7 +101,7 @@ pub fn check(
             &tests_path.join("rustdoc-ui"),
             &tests_path.join("rustdoc"),
         ],
-        &mut filter_dirs,
+        filter_dirs,
         &mut |entry, contents| {
             let file = entry.path();
             let filename = file.file_name().unwrap().to_string_lossy();
@@ -219,8 +219,6 @@ pub fn check(
         for line in lines {
             println!("* {line}");
         }
-    } else {
-        println!("* {} features", features.len());
     }
 
     CollectedFeatures { lib: lib_features, lang: features }
@@ -477,11 +475,11 @@ fn get_and_check_lib_features(
 
 fn map_lib_features(
     base_src_path: &Path,
-    mf: &mut dyn FnMut(Result<(&str, Feature), &str>, &Path, usize),
+    mf: &mut (dyn Send + Sync + FnMut(Result<(&str, Feature), &str>, &Path, usize)),
 ) {
     walk(
         base_src_path,
-        &mut |path| filter_dirs(path) || path.ends_with("tests"),
+        |path| filter_dirs(path) || path.ends_with("tests"),
         &mut |entry, contents| {
             let file = entry.path();
             let filename = file.file_name().unwrap().to_string_lossy();
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 505f9d724c8..d98758ace4f 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -91,7 +91,6 @@ fn main() {
 
         // Checks that need to be done for both the compiler and std libraries.
         check!(unit_tests, &src_path);
-        check!(unit_tests, &tests_path);
         check!(unit_tests, &compiler_path);
         check!(unit_tests, &library_path);
 
@@ -107,7 +106,6 @@ fn main() {
         check!(edition, &src_path);
         check!(edition, &compiler_path);
         check!(edition, &library_path);
-        check!(edition, &tests_path);
 
         check!(alphabetical, &src_path);
         check!(alphabetical, &tests_path);
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index f4592fdcff9..33938ac9a0a 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -68,7 +68,7 @@ pub fn check(path: &Path, bad: &mut bool) {
     // Sanity check that the complex parsing here works.
     let mut saw_target_arch = false;
     let mut saw_cfg_bang = false;
-    walk(path, &mut filter_dirs, &mut |entry, contents| {
+    walk(path, filter_dirs, &mut |entry, contents| {
         let file = entry.path();
         let filestr = file.to_string_lossy().replace("\\", "/");
         if !filestr.ends_with(".rs") {
diff --git a/src/tools/tidy/src/rustdoc_gui_tests.rs b/src/tools/tidy/src/rustdoc_gui_tests.rs
index feb513df34b..d7db5c02297 100644
--- a/src/tools/tidy/src/rustdoc_gui_tests.rs
+++ b/src/tools/tidy/src/rustdoc_gui_tests.rs
@@ -5,7 +5,7 @@ use std::path::Path;
 pub fn check(path: &Path, bad: &mut bool) {
     crate::walk::walk(
         &path.join("rustdoc-gui"),
-        &mut |p| {
+        |p| {
             // If there is no extension, it's very likely a folder and we want to go into it.
             p.extension().map(|e| e != "goml").unwrap_or(false)
         },
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 6a0855405ec..9ecb30529cc 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -235,7 +235,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         .chain(PROBLEMATIC_CONSTS.iter().map(|v| format!("{:X}", v)))
         .collect();
     let problematic_regex = RegexSet::new(problematic_consts_strings.as_slice()).unwrap();
-    walk(path, &mut skip, &mut |entry, contents| {
+    walk(path, skip, &mut |entry, contents| {
         let file = entry.path();
         let filename = file.file_name().unwrap().to_string_lossy();
         let extensions =
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index d7a157672cf..f41fa4fcce1 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -37,7 +37,7 @@ struct RevisionInfo<'a> {
 pub fn check(path: &Path, bad: &mut bool) {
     crate::walk::walk(
         path,
-        &mut |path| path.extension().map(|p| p == "rs") == Some(false),
+        |path| path.extension().map(|p| p == "rs") == Some(false),
         &mut |entry, content| {
             let file = entry.path().display();
             let mut header_map = BTreeMap::new();
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 409f7563184..15c36923e88 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -54,7 +54,7 @@ fn check_entries(path: &Path, bad: &mut bool) {
 pub fn check(path: &Path, bad: &mut bool) {
     check_entries(&path, bad);
     for path in &[&path.join("ui"), &path.join("ui-fulldeps")] {
-        crate::walk::walk_no_read(path, &mut |_| false, &mut |entry| {
+        crate::walk::walk_no_read(path, |_| false, &mut |entry| {
             let file_path = entry.path();
             if let Some(ext) = file_path.extension() {
                 if ext == "stderr" || ext == "stdout" {
diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs
index 27f36c85561..3da200a8a93 100644
--- a/src/tools/tidy/src/unit_tests.rs
+++ b/src/tools/tidy/src/unit_tests.rs
@@ -11,18 +11,19 @@ use crate::walk::{filter_dirs, walk};
 use std::path::Path;
 
 pub fn check(root_path: &Path, bad: &mut bool) {
-    let core = &root_path.join("core");
-    let core_tests = &core.join("tests");
-    let core_benches = &core.join("benches");
-    let is_core = |path: &Path| {
-        path.starts_with(core) && !(path.starts_with(core_tests) || path.starts_with(core_benches))
+    let core = root_path.join("core");
+    let core_copy = core.clone();
+    let core_tests = core.join("tests");
+    let core_benches = core.join("benches");
+    let is_core = move |path: &Path| {
+        path.starts_with(&core)
+            && !(path.starts_with(&core_tests) || path.starts_with(&core_benches))
     };
 
-    let mut skip = |path: &Path| {
+    let skip = move |path: &Path| {
         let file_name = path.file_name().unwrap_or_default();
         if path.is_dir() {
             filter_dirs(path)
-                || path.ends_with("tests")
                 || path.ends_with("src/doc")
                 || (file_name == "tests" || file_name == "benches") && !is_core(path)
         } else {
@@ -35,9 +36,9 @@ pub fn check(root_path: &Path, bad: &mut bool) {
         }
     };
 
-    walk(root_path, &mut skip, &mut |entry, contents| {
+    walk(root_path, skip, &mut |entry, contents| {
         let path = entry.path();
-        let is_core = path.starts_with(core);
+        let is_core = path.starts_with(&core_copy);
         for (i, line) in contents.lines().enumerate() {
             let line = line.trim();
             let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 4cfb70fa31c..94152e75168 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -1,9 +1,8 @@
-use std::fs::File;
-use std::io::Read;
-use walkdir::{DirEntry, WalkDir};
+use ignore::DirEntry;
 
-use std::path::Path;
+use std::{fs::File, io::Read, path::Path};
 
+/// The default directory filter.
 pub fn filter_dirs(path: &Path) -> bool {
     let skip = [
         "tidy-test-file",
@@ -36,34 +35,42 @@ pub fn filter_dirs(path: &Path) -> bool {
 
 pub fn walk_many(
     paths: &[&Path],
-    skip: &mut dyn FnMut(&Path) -> bool,
+    skip: impl Clone + Send + Sync + 'static + Fn(&Path) -> bool,
     f: &mut dyn FnMut(&DirEntry, &str),
 ) {
     for path in paths {
-        walk(path, skip, f);
+        walk(path, skip.clone(), f);
     }
 }
 
-pub fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
-    let mut contents = String::new();
+pub fn walk(
+    path: &Path,
+    skip: impl Send + Sync + 'static + Fn(&Path) -> bool,
+    f: &mut dyn FnMut(&DirEntry, &str),
+) {
+    let mut contents = Vec::new();
     walk_no_read(path, skip, &mut |entry| {
         contents.clear();
-        if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
-            contents.clear();
-        }
-        f(&entry, &contents);
+        let mut file = t!(File::open(entry.path()), entry.path());
+        t!(file.read_to_end(&mut contents), entry.path());
+        let contents_str = match std::str::from_utf8(&contents) {
+            Ok(s) => s,
+            Err(_) => return, // skip this file
+        };
+        f(&entry, &contents_str);
     });
 }
 
 pub(crate) fn walk_no_read(
     path: &Path,
-    skip: &mut dyn FnMut(&Path) -> bool,
+    skip: impl Send + Sync + 'static + Fn(&Path) -> bool,
     f: &mut dyn FnMut(&DirEntry),
 ) {
-    let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path()));
-    for entry in walker {
+    let mut walker = ignore::WalkBuilder::new(path);
+    let walker = walker.filter_entry(move |e| !skip(e.path()));
+    for entry in walker.build() {
         if let Ok(entry) = entry {
-            if entry.file_type().is_dir() {
+            if entry.file_type().map_or(true, |kind| kind.is_dir() || kind.is_symlink()) {
                 continue;
             }
             f(&entry);
diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs
new file mode 100644
index 00000000000..a9d25e3b53c
--- /dev/null
+++ b/tests/codegen/comparison-operators-2-tuple.rs
@@ -0,0 +1,121 @@
+// compile-flags: -C opt-level=1 -Z merge-functions=disabled
+// min-llvm-version: 15.0
+// only-x86_64
+
+#![crate_type = "lib"]
+
+use std::cmp::Ordering;
+
+type TwoTuple = (i16, u16);
+
+//
+// The operators are all overridden directly, so should optimize easily.
+//
+// Yes, the `s[lg]t` is correct for the `[lg]e` version because it's only used
+// in the side of the select where we know the values are *not* equal.
+//
+
+// CHECK-LABEL: @check_lt_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a < b
+}
+
+// CHECK-LABEL: @check_le_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a <= b
+}
+
+// CHECK-LABEL: @check_gt_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a > b
+}
+
+// CHECK-LABEL: @check_ge_direct
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    a >= b
+}
+
+//
+// These ones are harder, since there are more intermediate values to remove.
+//
+// `<` seems to be getting lucky right now, so test that doesn't regress.
+//
+// The others, however, aren't managing to optimize away the extra `select`s yet.
+// See <https://github.com/rust-lang/rust/issues/106107> for more about this.
+//
+
+// CHECK-LABEL: @check_lt_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_lt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]]
+    // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_lt()
+}
+
+// CHECK-LABEL: @check_le_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_le_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sle i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
+    // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // FIXME-CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_le()
+}
+
+// CHECK-LABEL: @check_gt_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_gt_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
+    // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // FIXME-CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_gt()
+}
+
+// CHECK-LABEL: @check_ge_via_cmp
+// CHECK-SAME: (i16 noundef %[[A0:.+]], i16 noundef %[[A1:.+]], i16 noundef %[[B0:.+]], i16 noundef %[[B1:.+]])
+#[no_mangle]
+pub fn check_ge_via_cmp(a: TwoTuple, b: TwoTuple) -> bool {
+    // FIXME-CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP0:.+]] = icmp sge i16 %[[A0]], %[[B0]]
+    // FIXME-CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
+    // FIXME-CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
+    // FIXME-CHECK: ret i1 %[[R]]
+    Ord::cmp(&a, &b).is_ge()
+}
diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs
new file mode 100644
index 00000000000..c40d59fb0cf
--- /dev/null
+++ b/tests/codegen/slice-indexing.rs
@@ -0,0 +1,35 @@
+// compile-flags: -O
+// only-64bit (because the LLVM type of i64 for usize shows up)
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::ops::Range;
+
+// CHECK-LABEL: @index_by_range(
+#[no_mangle]
+pub fn index_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
+    // CHECK: sub nuw i64
+    &x[r]
+}
+
+// CHECK-LABEL: @get_unchecked_by_range(
+#[no_mangle]
+pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
+    // CHECK: sub nuw i64
+    x.get_unchecked(r)
+}
+
+// CHECK-LABEL: @index_mut_by_range(
+#[no_mangle]
+pub fn index_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
+    // CHECK: sub nuw i64
+    &mut x[r]
+}
+
+// CHECK-LABEL: @get_unchecked_mut_by_range(
+#[no_mangle]
+pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
+    // CHECK: sub nuw i64
+    x.get_unchecked_mut(r)
+}
diff --git a/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
new file mode 100644
index 00000000000..61a934685cd
--- /dev/null
+++ b/tests/mir-opt/basic_assignment.main.ElaborateDrops.diff
@@ -0,0 +1,85 @@
+- // MIR for `main` before ElaborateDrops
++ // MIR for `main` after ElaborateDrops
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/basic_assignment.rs:+0:11: +0:11
+      let _1: bool;                        // in scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17
+      let mut _3: bool;                    // in scope 0 at $DIR/basic_assignment.rs:+6:16: +6:24
+      let mut _6: std::option::Option<std::boxed::Box<u32>>; // in scope 0 at $DIR/basic_assignment.rs:+13:14: +13:20
+      scope 1 {
+          debug nodrop_x => _1;            // in scope 1 at $DIR/basic_assignment.rs:+1:9: +1:17
+          let _2: bool;                    // in scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17
+          scope 2 {
+              debug nodrop_y => _2;        // in scope 2 at $DIR/basic_assignment.rs:+2:9: +2:17
+              let _4: std::option::Option<std::boxed::Box<u32>>; // in scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15
+              scope 3 {
+                  debug drop_x => _4;      // in scope 3 at $DIR/basic_assignment.rs:+8:9: +8:15
+                  let _5: std::option::Option<std::boxed::Box<u32>>; // in scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15
+                  scope 4 {
+                      debug drop_y => _5;  // in scope 4 at $DIR/basic_assignment.rs:+9:9: +9:15
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/basic_assignment.rs:+1:9: +1:17
+          _1 = const false;                // scope 0 at $DIR/basic_assignment.rs:+1:20: +1:25
+          StorageLive(_2);                 // scope 1 at $DIR/basic_assignment.rs:+2:9: +2:17
+          StorageLive(_3);                 // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24
+          _3 = _1;                         // scope 2 at $DIR/basic_assignment.rs:+6:16: +6:24
+          _2 = move _3;                    // scope 2 at $DIR/basic_assignment.rs:+6:5: +6:24
+          StorageDead(_3);                 // scope 2 at $DIR/basic_assignment.rs:+6:23: +6:24
+          StorageLive(_4);                 // scope 2 at $DIR/basic_assignment.rs:+8:9: +8:15
+          _4 = Option::<Box<u32>>::None;   // scope 2 at $DIR/basic_assignment.rs:+8:36: +8:40
+          StorageLive(_5);                 // scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15
+          StorageLive(_6);                 // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20
+          _6 = move _4;                    // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20
+-         drop(_5) -> [return: bb1, unwind: bb2]; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
++         goto -> bb1;                     // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+      }
+  
+      bb1: {
+          _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+-         drop(_6) -> [return: bb3, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
++         goto -> bb3;                     // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+      }
+  
+      bb2 (cleanup): {
+          _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+          drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+      }
+  
+      bb3: {
+          StorageDead(_6);                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+          _0 = const ();                   // scope 0 at $DIR/basic_assignment.rs:+0:11: +14:2
+          drop(_5) -> [return: bb4, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+      }
+  
+      bb4: {
+          StorageDead(_5);                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+-         drop(_4) -> bb5;                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
++         goto -> bb5;                     // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+      }
+  
+      bb5: {
+          StorageDead(_4);                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+          StorageDead(_2);                 // scope 1 at $DIR/basic_assignment.rs:+14:1: +14:2
+          StorageDead(_1);                 // scope 0 at $DIR/basic_assignment.rs:+14:1: +14:2
+          return;                          // scope 0 at $DIR/basic_assignment.rs:+14:2: +14:2
+      }
+  
+      bb6 (cleanup): {
+          drop(_5) -> bb7;                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+      }
+  
+      bb7 (cleanup): {
+-         drop(_4) -> bb8;                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
++         goto -> bb8;                     // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+      }
+  
+      bb8 (cleanup): {
+          resume;                          // scope 0 at $DIR/basic_assignment.rs:+0:1: +14:2
+      }
+  }
+  
diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
index 1f099cd5e83..f20b534259a 100644
--- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir
@@ -1,8 +1,8 @@
 // MIR for `main` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<std::boxed::Box<u32>>) }, span: $DIR/basic_assignment.rs:18:17: 18:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<std::boxed::Box<u32>>) }, span: $DIR/basic_assignment.rs:18:17: 18:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<std::boxed::Box<u32>>) }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<std::boxed::Box<u32>>) }, span: $DIR/basic_assignment.rs:20:17: 20:33, inferred_ty: std::option::Option<std::boxed::Box<u32>>
 |
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/basic_assignment.rs:+0:11: +0:11
@@ -41,35 +41,37 @@ fn main() -> () {
         StorageLive(_5);                 // scope 3 at $DIR/basic_assignment.rs:+9:9: +9:15
         StorageLive(_6);                 // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20
         _6 = move _4;                    // scope 4 at $DIR/basic_assignment.rs:+13:14: +13:20
-        replace(_5 <- move _6) -> [return: bb1, unwind: bb5]; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+        drop(_5) -> [return: bb1, unwind: bb2]; // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
     }
 
     bb1: {
-        drop(_6) -> [return: bb2, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+        _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+        drop(_6) -> [return: bb3, unwind: bb6]; // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
     }
 
-    bb2: {
+    bb2 (cleanup): {
+        _5 = move _6;                    // scope 4 at $DIR/basic_assignment.rs:+13:5: +13:11
+        drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
+    }
+
+    bb3: {
         StorageDead(_6);                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
         _0 = const ();                   // scope 0 at $DIR/basic_assignment.rs:+0:11: +14:2
-        drop(_5) -> [return: bb3, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
+        drop(_5) -> [return: bb4, unwind: bb7]; // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
     }
 
-    bb3: {
+    bb4: {
         StorageDead(_5);                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
-        drop(_4) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
+        drop(_4) -> [return: bb5, unwind: bb8]; // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
     }
 
-    bb4: {
+    bb5: {
         StorageDead(_4);                 // scope 2 at $DIR/basic_assignment.rs:+14:1: +14:2
         StorageDead(_2);                 // scope 1 at $DIR/basic_assignment.rs:+14:1: +14:2
         StorageDead(_1);                 // scope 0 at $DIR/basic_assignment.rs:+14:1: +14:2
         return;                          // scope 0 at $DIR/basic_assignment.rs:+14:2: +14:2
     }
 
-    bb5 (cleanup): {
-        drop(_6) -> bb6;                 // scope 4 at $DIR/basic_assignment.rs:+13:19: +13:20
-    }
-
     bb6 (cleanup): {
         drop(_5) -> bb7;                 // scope 3 at $DIR/basic_assignment.rs:+14:1: +14:2
     }
diff --git a/tests/mir-opt/basic_assignment.rs b/tests/mir-opt/basic_assignment.rs
index ac350271e9f..92434e44aa9 100644
--- a/tests/mir-opt/basic_assignment.rs
+++ b/tests/mir-opt/basic_assignment.rs
@@ -1,5 +1,7 @@
+// needs-unwind
 // this tests move up progration, which is not yet implemented
 
+// EMIT_MIR basic_assignment.main.ElaborateDrops.diff
 // EMIT_MIR basic_assignment.main.SimplifyCfg-initial.after.mir
 
 // Check codegen for assignments (`a = b`) where the left-hand-side is
diff --git a/tests/mir-opt/building/custom/as_cast.float_to_int.built.after.mir b/tests/mir-opt/building/custom/as_cast.float_to_int.built.after.mir
new file mode 100644
index 00000000000..d0b770783c1
--- /dev/null
+++ b/tests/mir-opt/building/custom/as_cast.float_to_int.built.after.mir
@@ -0,0 +1,10 @@
+// MIR for `float_to_int` after built
+
+fn float_to_int(_1: f32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/as_cast.rs:+0:28: +0:31
+
+    bb0: {
+        _0 = _1 as i32 (FloatToInt);     // scope 0 at $DIR/as_cast.rs:+3:13: +3:27
+        return;                          // scope 0 at $DIR/as_cast.rs:+4:13: +4:21
+    }
+}
diff --git a/tests/mir-opt/building/custom/as_cast.int_to_int.built.after.mir b/tests/mir-opt/building/custom/as_cast.int_to_int.built.after.mir
new file mode 100644
index 00000000000..aaebff0d767
--- /dev/null
+++ b/tests/mir-opt/building/custom/as_cast.int_to_int.built.after.mir
@@ -0,0 +1,10 @@
+// MIR for `int_to_int` after built
+
+fn int_to_int(_1: u32) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/as_cast.rs:+0:26: +0:29
+
+    bb0: {
+        _0 = _1 as i32 (IntToInt);       // scope 0 at $DIR/as_cast.rs:+3:13: +3:27
+        return;                          // scope 0 at $DIR/as_cast.rs:+4:13: +4:21
+    }
+}
diff --git a/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
new file mode 100644
index 00000000000..f040cf53df4
--- /dev/null
+++ b/tests/mir-opt/building/custom/as_cast.int_to_ptr.built.after.mir
@@ -0,0 +1,10 @@
+// MIR for `int_to_ptr` after built
+
+fn int_to_ptr(_1: usize) -> *const i32 {
+    let mut _0: *const i32;              // return place in scope 0 at $DIR/as_cast.rs:+0:28: +0:38
+
+    bb0: {
+        _0 = _1 as *const i32 (PointerFromExposedAddress); // scope 0 at $DIR/as_cast.rs:+3:13: +3:34
+        return;                          // scope 0 at $DIR/as_cast.rs:+4:13: +4:21
+    }
+}
diff --git a/tests/mir-opt/building/custom/as_cast.rs b/tests/mir-opt/building/custom/as_cast.rs
new file mode 100644
index 00000000000..b4b5ac6aa3b
--- /dev/null
+++ b/tests/mir-opt/building/custom/as_cast.rs
@@ -0,0 +1,43 @@
+#![feature(custom_mir, core_intrinsics)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR as_cast.int_to_int.built.after.mir
+#[custom_mir(dialect = "built")]
+fn int_to_int(x: u32) -> i32 {
+    mir!(
+        {
+            RET = x as i32;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR as_cast.float_to_int.built.after.mir
+#[custom_mir(dialect = "built")]
+fn float_to_int(x: f32) -> i32 {
+    mir!(
+        {
+            RET = x as i32;
+            Return()
+        }
+    )
+}
+
+// EMIT_MIR as_cast.int_to_ptr.built.after.mir
+#[custom_mir(dialect = "built")]
+fn int_to_ptr(x: usize) -> *const i32 {
+    mir!(
+        {
+            RET = x as *const i32;
+            Return()
+        }
+    )
+}
+
+fn main() {
+    assert_eq!(int_to_int(5), 5);
+    assert_eq!(float_to_int(5.), 5);
+    assert_eq!(int_to_ptr(0), std::ptr::null());
+}
diff --git a/tests/mir-opt/issue_41110.test.ElaborateDrops.diff b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
index 79e3d073be5..3dd1a9bbab5 100644
--- a/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41110.test.ElaborateDrops.diff
@@ -38,37 +38,39 @@
           StorageLive(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
 +         _6 = const false;                // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
           _5 = move _1;                    // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
--         replace(_2 <- move _5) -> [return: bb2, unwind: bb6]; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-+         goto -> bb12;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+-         drop(_2) -> [return: bb2, unwind: bb3]; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
++         goto -> bb2;                     // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
       }
   
       bb2: {
--         drop(_5) -> [return: bb3, unwind: bb8]; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-+         goto -> bb3;                     // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+          _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+-         drop(_5) -> [return: bb4, unwind: bb8]; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
++         goto -> bb4;                     // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+      }
+  
+      bb3 (cleanup): {
+          _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+          drop(_5) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
       }
   
-      bb3: {
+      bb4: {
           StorageDead(_5);                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
           _0 = const ();                   // scope 0 at $DIR/issue_41110.rs:+0:15: +5:2
-          drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+          drop(_2) -> [return: bb5, unwind: bb9]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   
-      bb4: {
+      bb5: {
           StorageDead(_2);                 // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
--         drop(_1) -> bb5;                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-+         goto -> bb5;                     // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+-         drop(_1) -> bb6;                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb6;                     // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   
-      bb5: {
+      bb6: {
 +         _6 = const false;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
           StorageDead(_1);                 // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/issue_41110.rs:+5:2: +5:2
       }
   
-      bb6 (cleanup): {
-          drop(_5) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
-      }
-  
       bb7 (cleanup): {
 -         drop(_4) -> bb8;                 // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
 +         goto -> bb8;                     // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
@@ -81,7 +83,7 @@
   
       bb9 (cleanup): {
 -         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
-+         goto -> bb14;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++         goto -> bb12;                    // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   
       bb10 (cleanup): {
@@ -89,21 +91,11 @@
 +     }
 + 
 +     bb11 (cleanup): {
-+         _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-+         goto -> bb10;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-+     }
-+ 
-+     bb12: {
-+         _2 = move _5;                    // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-+         goto -> bb2;                     // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
-+     }
-+ 
-+     bb13 (cleanup): {
 +         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
 +     }
 + 
-+     bb14 (cleanup): {
-+         switchInt(_6) -> [0: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
++     bb12 (cleanup): {
++         switchInt(_6) -> [0: bb10, otherwise: bb11]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
       }
   }
   
diff --git a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
index 257f0b1e6e8..4e38659a90b 100644
--- a/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
+++ b/tests/mir-opt/issue_41888.main.ElaborateDrops.diff
@@ -34,7 +34,7 @@
       }
   
       bb1: {
-          switchInt(move _2) -> [0: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+          switchInt(move _2) -> [0: bb8, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
       }
   
       bb2: {
@@ -43,47 +43,56 @@
           _4 = K;                          // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
           _3 = E::F(move _4);              // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
           StorageDead(_4);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
--         replace(_1 <- move _3) -> [return: bb3, unwind: bb10]; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         goto -> bb14;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+-         drop(_1) -> [return: bb3, unwind: bb4]; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         goto -> bb3;                     // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
       }
   
       bb3: {
--         drop(_3) -> [return: bb4, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-+         goto -> bb4;                     // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
++         _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
++         _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+          _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+-         drop(_3) -> [return: bb5, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
++         goto -> bb5;                     // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+      }
+  
+      bb4 (cleanup): {
+          _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+          drop(_3) -> bb11;                // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
       }
   
-      bb4: {
+      bb5: {
           StorageDead(_3);                 // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
           _5 = discriminant(_1);           // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
-          switchInt(move _5) -> [0: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
+          switchInt(move _5) -> [0: bb6, otherwise: bb7]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
       }
   
-      bb5: {
+      bb6: {
           StorageLive(_6);                 // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
 +         _9 = const false;                // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
           _6 = move ((_1 as F).0: K);      // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
           _0 = const ();                   // scope 2 at $DIR/issue_41888.rs:+4:29: +7:10
           StorageDead(_6);                 // scope 1 at $DIR/issue_41888.rs:+7:9: +7:10
-          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
+          goto -> bb9;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
       }
   
-      bb6: {
+      bb7: {
           _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+7:10: +7:10
-          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
+          goto -> bb9;                     // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
       }
   
-      bb7: {
+      bb8: {
           _0 = const ();                   // scope 1 at $DIR/issue_41888.rs:+8:6: +8:6
-          goto -> bb8;                     // scope 1 at $DIR/issue_41888.rs:+2:5: +8:6
+          goto -> bb9;                     // scope 1 at $DIR/issue_41888.rs:+2:5: +8:6
       }
   
-      bb8: {
+      bb9: {
           StorageDead(_2);                 // scope 1 at $DIR/issue_41888.rs:+8:5: +8:6
--         drop(_1) -> bb9;                 // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         goto -> bb20;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+-         drop(_1) -> bb10;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb18;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
       }
   
-      bb9: {
+      bb10: {
 +         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +         _8 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +         _9 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
@@ -91,10 +100,6 @@
           return;                          // scope 0 at $DIR/issue_41888.rs:+9:2: +9:2
       }
   
-      bb10 (cleanup): {
-          drop(_3) -> bb11;                // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
-      }
-  
       bb11 (cleanup): {
 -         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
@@ -104,55 +109,39 @@
           resume;                          // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
 +     }
 + 
-+     bb13 (cleanup): {
-+         _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         goto -> bb12;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+     }
-+ 
-+     bb14: {
-+         _7 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _8 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _9 = const true;                 // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         _1 = move _3;                    // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+         goto -> bb3;                     // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
-+     }
-+ 
-+     bb15: {
++     bb13: {
 +         _7 = const false;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         goto -> bb9;                     // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         goto -> bb10;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb16 (cleanup): {
++     bb14 (cleanup): {
 +         goto -> bb12;                    // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb17: {
-+         drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb15: {
++         drop(_1) -> [return: bb13, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb18 (cleanup): {
++     bb16 (cleanup): {
 +         drop(_1) -> bb12;                // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb19: {
++     bb17: {
 +         _10 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         switchInt(move _10) -> [0: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _10) -> [0: bb13, otherwise: bb15]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb20: {
-+         switchInt(_7) -> [0: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb18: {
++         switchInt(_7) -> [0: bb13, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb21 (cleanup): {
++     bb19 (cleanup): {
 +         _11 = discriminant(_1);          // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
-+         switchInt(move _11) -> [0: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++         switchInt(move _11) -> [0: bb14, otherwise: bb16]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
 +     }
 + 
-+     bb22 (cleanup): {
-+         switchInt(_7) -> [0: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
++     bb20 (cleanup): {
++         switchInt(_7) -> [0: bb12, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
       }
   }
   
diff --git a/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir b/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
index 210f178a0a9..56cb9166c37 100644
--- a/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/tests/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
@@ -28,21 +28,21 @@ fn main() -> () {
         StorageDead(_5);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:28: +2:29
         StorageLive(_6);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
         _6 = move (_1.0: Aligned);       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
-        drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+        drop(_6) -> [return: bb4, unwind: bb1]; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
     }
 
-    bb1: {
-        StorageDead(_1);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
-        return;                          // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:2: +3:2
+    bb1 (cleanup): {
+        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+        drop(_1) -> bb3;                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
     }
 
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:1: +3:2
+    bb2: {
+        StorageDead(_1);                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
+        return;                          // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:2: +3:2
     }
 
     bb3 (cleanup): {
-        (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
-        drop(_1) -> bb2;                 // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
+        resume;                          // scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:1: +3:2
     }
 
     bb4: {
@@ -50,6 +50,6 @@ fn main() -> () {
         (_1.0: Aligned) = move _4;       // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
         StorageDead(_4);                 // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:28: +2:29
         _0 = const ();                   // scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:11: +3:2
-        drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
+        drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
     }
 }
diff --git a/tests/mir-opt/sroa.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.constant.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 9e33215f2b5..00000000000
--- a/tests/mir-opt/sroa.constant.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,46 +0,0 @@
-- // MIR for `constant` before ScalarReplacementOfAggregates
-+ // MIR for `constant` after ScalarReplacementOfAggregates
-  
-  fn constant() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:15: +0:15
-      let _1: (usize, u8);                 // in scope 0 at $DIR/sroa.rs:+2:9: +2:10
-+     let _4: usize;                       // in scope 0 at $DIR/sroa.rs:+2:9: +2:10
-+     let _5: u8;                          // in scope 0 at $DIR/sroa.rs:+2:9: +2:10
-      scope 1 {
--         debug y => _1;                   // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
-+         debug y => (usize, u8){ .0 => _4, .1 => _5, }; // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
-          let _2: usize;                   // in scope 1 at $DIR/sroa.rs:+3:9: +3:10
-          scope 2 {
-              debug t => _2;               // in scope 2 at $DIR/sroa.rs:+3:9: +3:10
-              let _3: u8;                  // in scope 2 at $DIR/sroa.rs:+4:9: +4:10
-              scope 3 {
-                  debug u => _3;           // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-              }
-          }
-      }
-  
-      bb0: {
--         StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+2:9: +2:10
-+         StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+2:9: +2:10
-+         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+2:9: +2:10
-+         nop;                             // scope 0 at $DIR/sroa.rs:+2:9: +2:10
-          _1 = const _;                    // scope 0 at $DIR/sroa.rs:+2:13: +2:14
-+         _4 = move (_1.0: usize);         // scope 1 at $DIR/sroa.rs:+3:9: +3:10
-+         _5 = move (_1.1: u8);            // scope 1 at $DIR/sroa.rs:+3:9: +3:10
-          StorageLive(_2);                 // scope 1 at $DIR/sroa.rs:+3:9: +3:10
--         _2 = (_1.0: usize);              // scope 1 at $DIR/sroa.rs:+3:13: +3:16
-+         _2 = _4;                         // scope 1 at $DIR/sroa.rs:+3:13: +3:16
-          StorageLive(_3);                 // scope 2 at $DIR/sroa.rs:+4:9: +4:10
--         _3 = (_1.1: u8);                 // scope 2 at $DIR/sroa.rs:+4:13: +4:16
-+         _3 = _5;                         // scope 2 at $DIR/sroa.rs:+4:13: +4:16
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:15: +5:2
-          StorageDead(_3);                 // scope 2 at $DIR/sroa.rs:+5:1: +5:2
-          StorageDead(_2);                 // scope 1 at $DIR/sroa.rs:+5:1: +5:2
--         StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+5:1: +5:2
-+         StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+5:1: +5:2
-+         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+5:1: +5:2
-+         nop;                             // scope 0 at $DIR/sroa.rs:+5:1: +5:2
-          return;                          // scope 0 at $DIR/sroa.rs:+5:2: +5:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 976f6d44b75..00000000000
--- a/tests/mir-opt/sroa.copies.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,91 +0,0 @@
-- // MIR for `copies` before ScalarReplacementOfAggregates
-+ // MIR for `copies` after ScalarReplacementOfAggregates
-  
-  fn copies(_1: Foo) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/sroa.rs:+0:11: +0:12
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
-      let _2: Foo;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _11: u8;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _12: ();                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _13: &str;                       // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _14: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-      scope 1 {
--         debug y => _2;                   // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
-+         debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
-          let _3: u8;                      // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
-          scope 2 {
-              debug t => _3;               // in scope 2 at $DIR/sroa.rs:+2:9: +2:10
-              let _4: &str;                // in scope 2 at $DIR/sroa.rs:+3:9: +3:10
-              scope 3 {
-                  debug u => _4;           // in scope 3 at $DIR/sroa.rs:+3:9: +3:10
-                  let _5: Foo;             // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+                 let _7: u8;              // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+                 let _8: ();              // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+                 let _9: &str;            // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+                 let _10: std::option::Option<isize>; // in scope 3 at $DIR/sroa.rs:+4:9: +4:10
-                  scope 4 {
--                     debug z => _5;       // in scope 4 at $DIR/sroa.rs:+4:9: +4:10
-+                     debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; // in scope 4 at $DIR/sroa.rs:+4:9: +4:10
-                      let _6: ();          // in scope 4 at $DIR/sroa.rs:+5:9: +5:10
-                      scope 5 {
-                          debug a => _6;   // in scope 5 at $DIR/sroa.rs:+5:9: +5:10
-                      }
-                  }
-              }
-          }
-      }
-  
-      bb0: {
--         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
--         _2 = _1;                         // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-+         StorageLive(_11);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_12);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_13);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_14);                // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         _11 = (_1.0: u8);                // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-+         _12 = (_1.1: ());                // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-+         _13 = (_1.2: &str);              // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-+         _14 = (_1.3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:13: +1:14
-          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+2:9: +2:10
--         _3 = (_2.0: u8);                 // scope 1 at $DIR/sroa.rs:+2:13: +2:16
-+         _3 = _11;                        // scope 1 at $DIR/sroa.rs:+2:13: +2:16
-          StorageLive(_4);                 // scope 2 at $DIR/sroa.rs:+3:9: +3:10
--         _4 = (_2.2: &str);               // scope 2 at $DIR/sroa.rs:+3:13: +3:16
--         StorageLive(_5);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
--         _5 = _2;                         // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-+         _4 = _13;                        // scope 2 at $DIR/sroa.rs:+3:13: +3:16
-+         StorageLive(_7);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+         StorageLive(_8);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+         StorageLive(_9);                 // scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+         StorageLive(_10);                // scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+         nop;                             // scope 3 at $DIR/sroa.rs:+4:9: +4:10
-+         _7 = _11;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-+         _8 = _12;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-+         _9 = _13;                        // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-+         _10 = _14;                       // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-+         nop;                             // scope 3 at $DIR/sroa.rs:+4:13: +4:14
-          StorageLive(_6);                 // scope 4 at $DIR/sroa.rs:+5:9: +5:10
--         _6 = (_5.1: ());                 // scope 4 at $DIR/sroa.rs:+5:13: +5:16
-+         _6 = _8;                         // scope 4 at $DIR/sroa.rs:+5:13: +5:16
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +6:2
-          StorageDead(_6);                 // scope 4 at $DIR/sroa.rs:+6:1: +6:2
--         StorageDead(_5);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_7);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_8);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_9);                 // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_10);                // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-+         nop;                             // scope 3 at $DIR/sroa.rs:+6:1: +6:2
-          StorageDead(_4);                 // scope 2 at $DIR/sroa.rs:+6:1: +6:2
-          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+6:1: +6:2
--         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_11);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_12);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_13);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-+         StorageDead(_14);                // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-+         nop;                             // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/sroa.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 17a89e7d8eb..00000000000
--- a/tests/mir-opt/sroa.dropping.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,44 +0,0 @@
-- // MIR for `dropping` before ScalarReplacementOfAggregates
-+ // MIR for `dropping` after ScalarReplacementOfAggregates
-  
-  fn dropping() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
-      let _1: Tag;                         // in scope 0 at $DIR/sroa.rs:+1:5: +1:32
-      let mut _2: S;                       // in scope 0 at $DIR/sroa.rs:+1:5: +1:30
-      let mut _3: Tag;                     // in scope 0 at $DIR/sroa.rs:+1:7: +1:13
-      let mut _4: Tag;                     // in scope 0 at $DIR/sroa.rs:+1:15: +1:21
-      let mut _5: Tag;                     // in scope 0 at $DIR/sroa.rs:+1:23: +1:29
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:32
-          StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:30
-          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:13
-          _3 = Tag(const 0_usize);         // scope 0 at $DIR/sroa.rs:+1:7: +1:13
-          StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+1:15: +1:21
-          _4 = Tag(const 1_usize);         // scope 0 at $DIR/sroa.rs:+1:15: +1:21
-          StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:23: +1:29
-          _5 = Tag(const 2_usize);         // scope 0 at $DIR/sroa.rs:+1:23: +1:29
-          _2 = S(move _3, move _4, move _5); // scope 0 at $DIR/sroa.rs:+1:5: +1:30
-          StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
-          StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
-          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+1:29: +1:30
-          _1 = move (_2.1: Tag);           // scope 0 at $DIR/sroa.rs:+1:5: +1:32
-          drop(_1) -> bb1;                 // scope 0 at $DIR/sroa.rs:+1:32: +1:33
-      }
-  
-      bb1: {
-          drop((_2.0: Tag)) -> bb3;        // scope 0 at $DIR/sroa.rs:+1:32: +1:33
-      }
-  
-      bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+1:32: +1:33
-          StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+1:32: +1:33
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +2:2
-          return;                          // scope 0 at $DIR/sroa.rs:+2:2: +2:2
-      }
-  
-      bb3: {
-          drop((_2.2: Tag)) -> bb2;        // scope 0 at $DIR/sroa.rs:+1:32: +1:33
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 04d26162aad..00000000000
--- a/tests/mir-opt/sroa.enums.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,43 +0,0 @@
-- // MIR for `enums` before ScalarReplacementOfAggregates
-+ // MIR for `enums` after ScalarReplacementOfAggregates
-  
-  fn enums(_1: usize) -> usize {
-      debug a => _1;                       // in scope 0 at $DIR/sroa.rs:+0:14: +0:15
-      let mut _0: usize;                   // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:32
-      let mut _2: std::option::Option<usize>; // in scope 0 at $DIR/sroa.rs:+1:22: +1:29
-      let mut _3: usize;                   // in scope 0 at $DIR/sroa.rs:+1:27: +1:28
-      let mut _4: isize;                   // in scope 0 at $DIR/sroa.rs:+1:12: +1:19
-      scope 1 {
-          debug a => _5;                   // in scope 1 at $DIR/sroa.rs:+1:17: +1:18
-          let _5: usize;                   // in scope 1 at $DIR/sroa.rs:+1:17: +1:18
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 1 at $DIR/sroa.rs:+1:22: +1:29
-          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+1:27: +1:28
-          _3 = _1;                         // scope 1 at $DIR/sroa.rs:+1:27: +1:28
-          _2 = Option::<usize>::Some(move _3); // scope 1 at $DIR/sroa.rs:+1:22: +1:29
-          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+1:28: +1:29
-          _4 = discriminant(_2);           // scope 1 at $DIR/sroa.rs:+1:12: +1:19
-          switchInt(move _4) -> [1: bb1, otherwise: bb2]; // scope 1 at $DIR/sroa.rs:+1:12: +1:19
-      }
-  
-      bb1: {
-          StorageLive(_5);                 // scope 1 at $DIR/sroa.rs:+1:17: +1:18
-          _5 = ((_2 as Some).0: usize);    // scope 1 at $DIR/sroa.rs:+1:17: +1:18
-          _0 = _5;                         // scope 1 at $DIR/sroa.rs:+1:32: +1:33
-          StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:34: +1:35
-          goto -> bb3;                     // scope 0 at $DIR/sroa.rs:+1:5: +1:46
-      }
-  
-      bb2: {
-          _0 = const 0_usize;              // scope 0 at $DIR/sroa.rs:+1:43: +1:44
-          goto -> bb3;                     // scope 0 at $DIR/sroa.rs:+1:5: +1:46
-      }
-  
-      bb3: {
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+2:1: +2:2
-          return;                          // scope 0 at $DIR/sroa.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index fd691fdd153..00000000000
--- a/tests/mir-opt/sroa.escaping.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,44 +0,0 @@
-- // MIR for `escaping` before ScalarReplacementOfAggregates
-+ // MIR for `escaping` after ScalarReplacementOfAggregates
-  
-  fn escaping() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:19: +0:19
-      let _1: ();                          // in scope 0 at $DIR/sroa.rs:+1:5: +1:42
-      let mut _2: *const u32;              // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
-      let _3: &u32;                        // in scope 0 at $DIR/sroa.rs:+1:7: +1:41
-      let _4: Escaping;                    // in scope 0 at $DIR/sroa.rs:+1:8: +1:39
-      let mut _5: u32;                     // in scope 0 at $DIR/sroa.rs:+1:34: +1:37
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:5: +1:42
-          StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:41
-          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+1:7: +1:41
-          StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+1:8: +1:39
-          StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:34: +1:37
-          _5 = g() -> bb1;                 // scope 0 at $DIR/sroa.rs:+1:34: +1:37
-                                           // mir::Constant
-                                           // + span: $DIR/sroa.rs:78:34: 78:35
-                                           // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
-      }
-  
-      bb1: {
-          _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/sroa.rs:+1:8: +1:39
-          StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:38: +1:39
-          _3 = &(_4.0: u32);               // scope 0 at $DIR/sroa.rs:+1:7: +1:41
-          _2 = &raw const (*_3);           // scope 0 at $DIR/sroa.rs:+1:7: +1:41
-          _1 = f(move _2) -> bb2;          // scope 0 at $DIR/sroa.rs:+1:5: +1:42
-                                           // mir::Constant
-                                           // + span: $DIR/sroa.rs:78:5: 78:6
-                                           // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
-      }
-  
-      bb2: {
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+1:41: +1:42
-          StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
-          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
-          StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+1:42: +1:43
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:19: +2:2
-          return;                          // scope 0 at $DIR/sroa.rs:+2:2: +2:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 69631fc0213..00000000000
--- a/tests/mir-opt/sroa.flat.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,80 +0,0 @@
-- // MIR for `flat` before ScalarReplacementOfAggregates
-+ // MIR for `flat` after ScalarReplacementOfAggregates
-  
-  fn flat() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:15: +0:15
-      let _1: u8;                          // in scope 0 at $DIR/sroa.rs:+1:15: +1:16
-      let _2: ();                          // in scope 0 at $DIR/sroa.rs:+1:18: +1:19
-      let _3: &str;                        // in scope 0 at $DIR/sroa.rs:+1:21: +1:22
-      let _4: std::option::Option<isize>;  // in scope 0 at $DIR/sroa.rs:+1:24: +1:25
-      let mut _5: Foo;                     // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
-      let mut _6: ();                      // in scope 0 at $DIR/sroa.rs:+1:45: +1:47
-      let mut _7: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:60: +1:68
-+     let mut _8: u8;                      // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+     let mut _9: ();                      // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+     let mut _10: &str;                   // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+     let mut _11: std::option::Option<isize>; // in scope 0 at $DIR/sroa.rs:+1:30: +1:70
-      scope 1 {
-          debug a => _1;                   // in scope 1 at $DIR/sroa.rs:+1:15: +1:16
-          debug b => _2;                   // in scope 1 at $DIR/sroa.rs:+1:18: +1:19
-          debug c => _3;                   // in scope 1 at $DIR/sroa.rs:+1:21: +1:22
-          debug d => _4;                   // in scope 1 at $DIR/sroa.rs:+1:24: +1:25
-          scope 2 {
-              scope 3 {
-                  scope 4 {
-                      scope 5 {
-                      }
-                  }
-              }
-          }
-      }
-  
-      bb0: {
--         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         StorageLive(_8);                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         StorageLive(_9);                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         StorageLive(_10);                // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         StorageLive(_11);                // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-          StorageLive(_6);                 // scope 0 at $DIR/sroa.rs:+1:45: +1:47
-          _6 = ();                         // scope 0 at $DIR/sroa.rs:+1:45: +1:47
-          StorageLive(_7);                 // scope 0 at $DIR/sroa.rs:+1:60: +1:68
-          _7 = Option::<isize>::Some(const -4_isize); // scope 0 at $DIR/sroa.rs:+1:60: +1:68
--         _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         _8 = const 5_u8;                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         _9 = move _6;                    // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         _10 = const "a";                 // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-                                           // mir::Constant
-                                           // + span: $DIR/sroa.rs:53:52: 53:55
-                                           // + literal: Const { ty: &str, val: Value(Slice(..)) }
-+         _11 = move _7;                   // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:30: +1:70
-          StorageDead(_7);                 // scope 0 at $DIR/sroa.rs:+1:69: +1:70
-          StorageDead(_6);                 // scope 0 at $DIR/sroa.rs:+1:69: +1:70
-          StorageLive(_1);                 // scope 0 at $DIR/sroa.rs:+1:15: +1:16
--         _1 = (_5.0: u8);                 // scope 0 at $DIR/sroa.rs:+1:15: +1:16
-+         _1 = _8;                         // scope 0 at $DIR/sroa.rs:+1:15: +1:16
-          StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:18: +1:19
--         _2 = (_5.1: ());                 // scope 0 at $DIR/sroa.rs:+1:18: +1:19
-+         _2 = _9;                         // scope 0 at $DIR/sroa.rs:+1:18: +1:19
-          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+1:21: +1:22
--         _3 = (_5.2: &str);               // scope 0 at $DIR/sroa.rs:+1:21: +1:22
-+         _3 = _10;                        // scope 0 at $DIR/sroa.rs:+1:21: +1:22
-          StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+1:24: +1:25
--         _4 = (_5.3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:24: +1:25
--         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-+         _4 = _11;                        // scope 0 at $DIR/sroa.rs:+1:24: +1:25
-+         StorageDead(_8);                 // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-+         StorageDead(_9);                 // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-+         StorageDead(_10);                // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-+         StorageDead(_11);                // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:70: +1:71
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:15: +6:2
-          StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          StorageDead(_1);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/sroa.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index f0d62220dd6..00000000000
--- a/tests/mir-opt/sroa.ref_copies.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,56 +0,0 @@
-- // MIR for `ref_copies` before ScalarReplacementOfAggregates
-+ // MIR for `ref_copies` after ScalarReplacementOfAggregates
-  
-  fn ref_copies(_1: &Foo) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/sroa.rs:+0:15: +0:16
-      let mut _0: ();                      // return place in scope 0 at $DIR/sroa.rs:+0:24: +0:24
-      let _2: Foo;                         // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _5: u8;                          // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _6: ();                          // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _7: &str;                        // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+     let _8: std::option::Option<isize>;  // in scope 0 at $DIR/sroa.rs:+1:9: +1:10
-      scope 1 {
--         debug y => _2;                   // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
-+         debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; // in scope 1 at $DIR/sroa.rs:+1:9: +1:10
-          let _3: u8;                      // in scope 1 at $DIR/sroa.rs:+2:9: +2:10
-          scope 2 {
-              debug t => _3;               // in scope 2 at $DIR/sroa.rs:+2:9: +2:10
-              let _4: &str;                // in scope 2 at $DIR/sroa.rs:+3:9: +3:10
-              scope 3 {
-                  debug u => _4;           // in scope 3 at $DIR/sroa.rs:+3:9: +3:10
-              }
-          }
-      }
-  
-      bb0: {
--         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
--         _2 = (*_1);                      // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-+         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_6);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_7);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         StorageLive(_8);                 // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:9: +1:10
-+         _5 = ((*_1).0: u8);              // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-+         _6 = ((*_1).1: ());              // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-+         _7 = ((*_1).2: &str);            // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-+         _8 = ((*_1).3: std::option::Option<isize>); // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-+         nop;                             // scope 0 at $DIR/sroa.rs:+1:13: +1:15
-          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+2:9: +2:10
--         _3 = (_2.0: u8);                 // scope 1 at $DIR/sroa.rs:+2:13: +2:16
-+         _3 = _5;                         // scope 1 at $DIR/sroa.rs:+2:13: +2:16
-          StorageLive(_4);                 // scope 2 at $DIR/sroa.rs:+3:9: +3:10
--         _4 = (_2.2: &str);               // scope 2 at $DIR/sroa.rs:+3:13: +3:16
-+         _4 = _7;                         // scope 2 at $DIR/sroa.rs:+3:13: +3:16
-          _0 = const ();                   // scope 0 at $DIR/sroa.rs:+0:24: +4:2
-          StorageDead(_4);                 // scope 2 at $DIR/sroa.rs:+4:1: +4:2
-          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+4:1: +4:2
--         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-+         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-+         StorageDead(_6);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-+         StorageDead(_7);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-+         StorageDead(_8);                 // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-+         nop;                             // scope 0 at $DIR/sroa.rs:+4:1: +4:2
-          return;                          // scope 0 at $DIR/sroa.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index 2c63d8b266d..00000000000
--- a/tests/mir-opt/sroa.structs.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,33 +0,0 @@
-- // MIR for `structs` before ScalarReplacementOfAggregates
-+ // MIR for `structs` after ScalarReplacementOfAggregates
-  
-  fn structs(_1: f32) -> f32 {
-      debug a => _1;                       // in scope 0 at $DIR/sroa.rs:+0:16: +0:17
-      let mut _0: f32;                     // return place in scope 0 at $DIR/sroa.rs:+0:27: +0:30
-      let mut _2: structs::U;              // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
-      let mut _3: f32;                     // in scope 0 at $DIR/sroa.rs:+6:18: +6:19
-+     let mut _4: usize;                   // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+     let mut _5: f32;                     // in scope 0 at $DIR/sroa.rs:+6:5: +6:21
-  
-      bb0: {
--         StorageLive(_2);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         StorageLive(_4);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         StorageLive(_5);                 // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         nop;                             // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-          StorageLive(_3);                 // scope 0 at $DIR/sroa.rs:+6:18: +6:19
-          _3 = _1;                         // scope 0 at $DIR/sroa.rs:+6:18: +6:19
--         _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         _4 = const 0_usize;              // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         _5 = move _3;                    // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-+         nop;                             // scope 0 at $DIR/sroa.rs:+6:5: +6:21
-          StorageDead(_3);                 // scope 0 at $DIR/sroa.rs:+6:20: +6:21
--         _0 = (_2.1: f32);                // scope 0 at $DIR/sroa.rs:+6:5: +6:23
--         StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
-+         _0 = _5;                         // scope 0 at $DIR/sroa.rs:+6:5: +6:23
-+         StorageDead(_4);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
-+         StorageDead(_5);                 // scope 0 at $DIR/sroa.rs:+7:1: +7:2
-+         nop;                             // scope 0 at $DIR/sroa.rs:+7:1: +7:2
-          return;                          // scope 0 at $DIR/sroa.rs:+7:2: +7:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff
deleted file mode 100644
index adfb01385d4..00000000000
--- a/tests/mir-opt/sroa.unions.ScalarReplacementOfAggregates.diff
+++ /dev/null
@@ -1,23 +0,0 @@
-- // MIR for `unions` before ScalarReplacementOfAggregates
-+ // MIR for `unions` after ScalarReplacementOfAggregates
-  
-  fn unions(_1: f32) -> u32 {
-      debug a => _1;                       // in scope 0 at $DIR/sroa.rs:+0:15: +0:16
-      let mut _0: u32;                     // return place in scope 0 at $DIR/sroa.rs:+0:26: +0:29
-      let mut _2: unions::Repr;            // in scope 0 at $DIR/sroa.rs:+5:14: +5:27
-      let mut _3: f32;                     // in scope 0 at $DIR/sroa.rs:+5:24: +5:25
-      scope 1 {
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 1 at $DIR/sroa.rs:+5:14: +5:27
-          StorageLive(_3);                 // scope 1 at $DIR/sroa.rs:+5:24: +5:25
-          _3 = _1;                         // scope 1 at $DIR/sroa.rs:+5:24: +5:25
-          _2 = Repr { f: move _3 };        // scope 1 at $DIR/sroa.rs:+5:14: +5:27
-          StorageDead(_3);                 // scope 1 at $DIR/sroa.rs:+5:26: +5:27
-          _0 = (_2.1: u32);                // scope 1 at $DIR/sroa.rs:+5:14: +5:29
-          StorageDead(_2);                 // scope 0 at $DIR/sroa.rs:+6:1: +6:2
-          return;                          // scope 0 at $DIR/sroa.rs:+6:2: +6:2
-      }
-  }
-  
diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..225f80ed41b
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,214 @@
+- // MIR for `foo` before ScalarReplacementOfAggregates
++ // MIR for `foo` after ScalarReplacementOfAggregates
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/lifetimes.rs:+0:18: +0:18
+      let _1: Foo<T>;                      // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+      let mut _2: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>; // in scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+      let mut _3: std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+      let mut _4: std::boxed::Box<u32>;    // in scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+      let mut _7: isize;                   // in scope 0 at $DIR/lifetimes.rs:+9:12: +9:17
+      let _9: ();                          // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _10: ();                         // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _11: std::fmt::Arguments<'_>; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _12: &[&str];                // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let mut _13: &[&str; 3];             // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let _14: &[&str; 3];                 // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let _15: [&str; 3];                  // in scope 0 at $DIR/lifetimes.rs:+10:19: +10:28
+      let mut _16: &[core::fmt::ArgumentV1<'_>]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _17: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _18: &[core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let _19: [core::fmt::ArgumentV1<'_>; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
+      let mut _20: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let mut _21: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let _22: &std::boxed::Box<dyn std::fmt::Display>; // in scope 0 at $DIR/lifetimes.rs:+10:21: +10:22
+      let mut _23: core::fmt::ArgumentV1<'_>; // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let mut _24: &u32;                   // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let _25: &u32;                       // in scope 0 at $DIR/lifetimes.rs:+10:25: +10:26
+      let mut _27: bool;                   // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _28: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _29: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+      let mut _30: isize;                  // in scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++     let _31: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>; // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++     let _32: u32;                        // in scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+      scope 1 {
+-         debug foo => _1;                 // in scope 1 at $DIR/lifetimes.rs:+1:9: +1:12
++         debug foo => Foo<T>{ .0 => _31, .1 => _32, }; // in scope 1 at $DIR/lifetimes.rs:+1:9: +1:12
+          let _5: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>; // in scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
+          scope 2 {
+              debug x => _5;               // in scope 2 at $DIR/lifetimes.rs:+6:9: +6:10
+              let _6: u32;                 // in scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
+              scope 3 {
+                  debug y => _6;           // in scope 3 at $DIR/lifetimes.rs:+7:9: +7:10
+                  scope 4 {
+                      debug x => _8;       // in scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+                      let _8: std::boxed::Box<dyn std::fmt::Display>; // in scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+                      let mut _26: &[&str; 3]; // in scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          _27 = const false;               // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+-         StorageLive(_1);                 // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         StorageLive(_31);                // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         StorageLive(_32);                // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
++         nop;                             // scope 0 at $DIR/lifetimes.rs:+1:9: +1:12
+          StorageLive(_2);                 // scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+          StorageLive(_3);                 // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+          StorageLive(_4);                 // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+          _4 = Box::<u32>::new(const 5_u32) -> bb1; // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:19:15: 19:23
+                                           // + user_ty: UserType(1)
+                                           // + literal: Const { ty: fn(u32) -> Box<u32> {Box::<u32>::new}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _3 = move _4 as std::boxed::Box<dyn std::fmt::Display> (Pointer(Unsize)); // scope 0 at $DIR/lifetimes.rs:+2:15: +2:30
+          StorageDead(_4);                 // scope 0 at $DIR/lifetimes.rs:+2:29: +2:30
+          _2 = Result::<Box<dyn std::fmt::Display>, <T as Err>::Err>::Ok(move _3); // scope 0 at $DIR/lifetimes.rs:+2:12: +2:31
+          StorageDead(_3);                 // scope 0 at $DIR/lifetimes.rs:+2:30: +2:31
+-         _1 = Foo::<T> { x: move _2, y: const 7_u32 }; // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         _31 = move _2;                   // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         _32 = const 7_u32;               // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
++         nop;                             // scope 0 at $DIR/lifetimes.rs:+1:23: +4:6
+          StorageDead(_2);                 // scope 0 at $DIR/lifetimes.rs:+4:5: +4:6
+          StorageLive(_5);                 // scope 1 at $DIR/lifetimes.rs:+6:9: +6:10
+          _27 = const true;                // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+-         _5 = move (_1.0: std::result::Result<std::boxed::Box<dyn std::fmt::Display>, <T as Err>::Err>); // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
++         _5 = move _31;                   // scope 1 at $DIR/lifetimes.rs:+6:13: +6:18
+          StorageLive(_6);                 // scope 2 at $DIR/lifetimes.rs:+7:9: +7:10
+-         _6 = (_1.1: u32);                // scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
++         _6 = _32;                        // scope 2 at $DIR/lifetimes.rs:+7:13: +7:18
+          _7 = discriminant(_5);           // scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+          switchInt(move _7) -> [0: bb2, otherwise: bb7]; // scope 4 at $DIR/lifetimes.rs:+9:12: +9:17
+      }
+  
+      bb2: {
+          StorageLive(_8);                 // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          _27 = const false;               // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          _8 = move ((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>); // scope 4 at $DIR/lifetimes.rs:+9:15: +9:16
+          StorageLive(_9);                 // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_10);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_11);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_12);                // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageLive(_13);                // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageLive(_14);                // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _26 = const _;                   // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:19: 27:28
+                                           // + literal: Const { ty: &[&str; 3], val: Unevaluated(foo, [T], Some(promoted[0])) }
+          _14 = &(*_26);                   // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _13 = &(*_14);                   // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          _12 = move _13 as &[&str] (Pointer(Unsize)); // scope 4 at $DIR/lifetimes.rs:+10:19: +10:28
+          StorageDead(_13);                // scope 4 at $DIR/lifetimes.rs:+10:27: +10:28
+          StorageLive(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_17);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_18);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageLive(_20);                // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_21);                // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_22);                // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _22 = &_8;                       // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _21 = &(*_22);                   // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          _20 = core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>(move _21) -> bb3; // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:21: 27:22
+                                           // + user_ty: UserType(4)
+                                           // + literal: Const { ty: for<'b> fn(&'b Box<dyn std::fmt::Display>) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<Box<dyn std::fmt::Display>>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_21);                // scope 4 at $DIR/lifetimes.rs:+10:21: +10:22
+          StorageLive(_23);                // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          StorageLive(_24);                // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          StorageLive(_25);                // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _25 = &_6;                       // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _24 = &(*_25);                   // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _23 = core::fmt::ArgumentV1::<'_>::new_display::<u32>(move _24) -> bb4; // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+                                           // mir::Constant
+                                           // + span: $DIR/lifetimes.rs:27:25: 27:26
+                                           // + user_ty: UserType(5)
+                                           // + literal: Const { ty: for<'b> fn(&'b u32) -> core::fmt::ArgumentV1<'b> {core::fmt::ArgumentV1::<'_>::new_display::<u32>}, val: Value(<ZST>) }
+      }
+  
+      bb4: {
+          StorageDead(_24);                // scope 4 at $DIR/lifetimes.rs:+10:25: +10:26
+          _19 = [move _20, move _23];      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_23);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_20);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _18 = &_19;                      // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _17 = &(*_18);                   // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _16 = move _17 as &[core::fmt::ArgumentV1<'_>] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_17);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _11 = Arguments::<'_>::new_v1(move _12, move _16) -> bb5; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // + user_ty: UserType(3)
+                                           // + literal: Const { ty: fn(&[&'static str], &[core::fmt::ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1}, val: Value(<ZST>) }
+      }
+  
+      bb5: {
+          StorageDead(_16);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_12);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _10 = _eprint(move _11) -> bb6;  // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // mir::Constant
+                                           // + span: $SRC_DIR/std/src/macros.rs:LL:COL
+                                           // + literal: Const { ty: for<'a> fn(Arguments<'a>) {_eprint}, val: Value(<ZST>) }
+      }
+  
+      bb6: {
+          StorageDead(_11);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_25);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_22);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_19);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_18);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_14);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_10);                // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _9 = const ();                   // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          StorageDead(_9);                 // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
+          _0 = const ();                   // scope 4 at $DIR/lifetimes.rs:+9:22: +11:6
+          drop(_8) -> bb8;                 // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+      }
+  
+      bb7: {
+          _0 = const ();                   // scope 3 at $DIR/lifetimes.rs:+11:6: +11:6
+          goto -> bb9;                     // scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+      }
+  
+      bb8: {
+          StorageDead(_8);                 // scope 3 at $DIR/lifetimes.rs:+11:5: +11:6
+          goto -> bb9;                     // scope 3 at $DIR/lifetimes.rs:+9:5: +11:6
+      }
+  
+      bb9: {
+          StorageDead(_6);                 // scope 2 at $DIR/lifetimes.rs:+12:1: +12:2
+          _28 = discriminant(_5);          // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          switchInt(move _28) -> [0: bb11, otherwise: bb13]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb10: {
+          _27 = const false;               // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+          StorageDead(_5);                 // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+-         StorageDead(_1);                 // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         StorageDead(_31);                // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         StorageDead(_32);                // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
++         nop;                             // scope 0 at $DIR/lifetimes.rs:+12:1: +12:2
+          return;                          // scope 0 at $DIR/lifetimes.rs:+12:2: +12:2
+      }
+  
+      bb11: {
+          switchInt(_27) -> [0: bb10, otherwise: bb12]; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb12: {
+          drop(((_5 as Ok).0: std::boxed::Box<dyn std::fmt::Display>)) -> bb10; // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  
+      bb13: {
+          drop(_5) -> bb10;                // scope 1 at $DIR/lifetimes.rs:+12:1: +12:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/lifetimes.rs b/tests/mir-opt/sroa/lifetimes.rs
new file mode 100644
index 00000000000..2356d212f3f
--- /dev/null
+++ b/tests/mir-opt/sroa/lifetimes.rs
@@ -0,0 +1,37 @@
+// unit-test: ScalarReplacementOfAggregates
+// compile-flags: -Cpanic=abort
+// no-prefer-dynamic
+
+trait Err {
+    type Err;
+}
+
+struct Foo<T: Err> {
+    // Check that the `'static` lifetime is erased when creating the local for `x`,
+    // even if we fail to normalize the type.
+    x: Result<Box<dyn std::fmt::Display + 'static>, <T as Err>::Err>,
+    y: u32,
+}
+
+// EMIT_MIR lifetimes.foo.ScalarReplacementOfAggregates.diff
+fn foo<T: Err>() {
+    let foo: Foo<T> = Foo {
+        x: Ok(Box::new(5_u32)),
+        y: 7_u32,
+    };
+
+    let x = foo.x;
+    let y = foo.y;
+
+    if let Ok(x) = x {
+        eprintln!("{x} {y}");
+    }
+}
+
+impl Err for () {
+    type Err = ();
+}
+
+fn main() {
+    foo::<()>()
+}
diff --git a/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..647681f0e7a
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.constant.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,46 @@
+- // MIR for `constant` before ScalarReplacementOfAggregates
++ // MIR for `constant` after ScalarReplacementOfAggregates
+  
+  fn constant() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:15: +0:15
+      let _1: (usize, u8);                 // in scope 0 at $DIR/structs.rs:+2:9: +2:10
++     let _4: usize;                       // in scope 0 at $DIR/structs.rs:+2:9: +2:10
++     let _5: u8;                          // in scope 0 at $DIR/structs.rs:+2:9: +2:10
+      scope 1 {
+-         debug y => _1;                   // in scope 1 at $DIR/structs.rs:+2:9: +2:10
++         debug y => (usize, u8){ .0 => _4, .1 => _5, }; // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+          let _2: usize;                   // in scope 1 at $DIR/structs.rs:+3:9: +3:10
+          scope 2 {
+              debug t => _2;               // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+              let _3: u8;                  // in scope 2 at $DIR/structs.rs:+4:9: +4:10
+              scope 3 {
+                  debug u => _3;           // in scope 3 at $DIR/structs.rs:+4:9: +4:10
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);                 // scope 0 at $DIR/structs.rs:+2:9: +2:10
++         StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+2:9: +2:10
++         StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+2:9: +2:10
++         nop;                             // scope 0 at $DIR/structs.rs:+2:9: +2:10
+          _1 = const _;                    // scope 0 at $DIR/structs.rs:+2:13: +2:14
++         _4 = move (_1.0: usize);         // scope 1 at $DIR/structs.rs:+3:9: +3:10
++         _5 = move (_1.1: u8);            // scope 1 at $DIR/structs.rs:+3:9: +3:10
+          StorageLive(_2);                 // scope 1 at $DIR/structs.rs:+3:9: +3:10
+-         _2 = (_1.0: usize);              // scope 1 at $DIR/structs.rs:+3:13: +3:16
++         _2 = _4;                         // scope 1 at $DIR/structs.rs:+3:13: +3:16
+          StorageLive(_3);                 // scope 2 at $DIR/structs.rs:+4:9: +4:10
+-         _3 = (_1.1: u8);                 // scope 2 at $DIR/structs.rs:+4:13: +4:16
++         _3 = _5;                         // scope 2 at $DIR/structs.rs:+4:13: +4:16
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:15: +5:2
+          StorageDead(_3);                 // scope 2 at $DIR/structs.rs:+5:1: +5:2
+          StorageDead(_2);                 // scope 1 at $DIR/structs.rs:+5:1: +5:2
+-         StorageDead(_1);                 // scope 0 at $DIR/structs.rs:+5:1: +5:2
++         StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+5:1: +5:2
++         StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+5:1: +5:2
++         nop;                             // scope 0 at $DIR/structs.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/structs.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..b0b0da8861f
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.copies.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,91 @@
+- // MIR for `copies` before ScalarReplacementOfAggregates
++ // MIR for `copies` after ScalarReplacementOfAggregates
+  
+  fn copies(_1: Foo) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/structs.rs:+0:11: +0:12
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+      let _2: Foo;                         // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _11: u8;                         // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _12: ();                         // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _13: &str;                       // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _14: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:9: +1:10
+      scope 1 {
+-         debug y => _2;                   // in scope 1 at $DIR/structs.rs:+1:9: +1:10
++         debug y => Foo{ .0 => _11, .1 => _12, .2 => _13, .3 => _14, }; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
+          let _3: u8;                      // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+          scope 2 {
+              debug t => _3;               // in scope 2 at $DIR/structs.rs:+2:9: +2:10
+              let _4: &str;                // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+              scope 3 {
+                  debug u => _4;           // in scope 3 at $DIR/structs.rs:+3:9: +3:10
+                  let _5: Foo;             // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++                 let _7: u8;              // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++                 let _8: ();              // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++                 let _9: &str;            // in scope 3 at $DIR/structs.rs:+4:9: +4:10
++                 let _10: std::option::Option<isize>; // in scope 3 at $DIR/structs.rs:+4:9: +4:10
+                  scope 4 {
+-                     debug z => _5;       // in scope 4 at $DIR/structs.rs:+4:9: +4:10
++                     debug z => Foo{ .0 => _7, .1 => _8, .2 => _9, .3 => _10, }; // in scope 4 at $DIR/structs.rs:+4:9: +4:10
+                      let _6: ();          // in scope 4 at $DIR/structs.rs:+5:9: +5:10
+                      scope 5 {
+                          debug a => _6;   // in scope 5 at $DIR/structs.rs:+5:9: +5:10
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
+-         _2 = _1;                         // scope 0 at $DIR/structs.rs:+1:13: +1:14
++         StorageLive(_11);                // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_12);                // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_13);                // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_14);                // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         _11 = (_1.0: u8);                // scope 0 at $DIR/structs.rs:+1:13: +1:14
++         _12 = (_1.1: ());                // scope 0 at $DIR/structs.rs:+1:13: +1:14
++         _13 = (_1.2: &str);              // scope 0 at $DIR/structs.rs:+1:13: +1:14
++         _14 = (_1.3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:13: +1:14
++         nop;                             // scope 0 at $DIR/structs.rs:+1:13: +1:14
+          StorageLive(_3);                 // scope 1 at $DIR/structs.rs:+2:9: +2:10
+-         _3 = (_2.0: u8);                 // scope 1 at $DIR/structs.rs:+2:13: +2:16
++         _3 = _11;                        // scope 1 at $DIR/structs.rs:+2:13: +2:16
+          StorageLive(_4);                 // scope 2 at $DIR/structs.rs:+3:9: +3:10
+-         _4 = (_2.2: &str);               // scope 2 at $DIR/structs.rs:+3:13: +3:16
+-         StorageLive(_5);                 // scope 3 at $DIR/structs.rs:+4:9: +4:10
+-         _5 = _2;                         // scope 3 at $DIR/structs.rs:+4:13: +4:14
++         _4 = _13;                        // scope 2 at $DIR/structs.rs:+3:13: +3:16
++         StorageLive(_7);                 // scope 3 at $DIR/structs.rs:+4:9: +4:10
++         StorageLive(_8);                 // scope 3 at $DIR/structs.rs:+4:9: +4:10
++         StorageLive(_9);                 // scope 3 at $DIR/structs.rs:+4:9: +4:10
++         StorageLive(_10);                // scope 3 at $DIR/structs.rs:+4:9: +4:10
++         nop;                             // scope 3 at $DIR/structs.rs:+4:9: +4:10
++         _7 = _11;                        // scope 3 at $DIR/structs.rs:+4:13: +4:14
++         _8 = _12;                        // scope 3 at $DIR/structs.rs:+4:13: +4:14
++         _9 = _13;                        // scope 3 at $DIR/structs.rs:+4:13: +4:14
++         _10 = _14;                       // scope 3 at $DIR/structs.rs:+4:13: +4:14
++         nop;                             // scope 3 at $DIR/structs.rs:+4:13: +4:14
+          StorageLive(_6);                 // scope 4 at $DIR/structs.rs:+5:9: +5:10
+-         _6 = (_5.1: ());                 // scope 4 at $DIR/structs.rs:+5:13: +5:16
++         _6 = _8;                         // scope 4 at $DIR/structs.rs:+5:13: +5:16
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:19: +6:2
+          StorageDead(_6);                 // scope 4 at $DIR/structs.rs:+6:1: +6:2
+-         StorageDead(_5);                 // scope 3 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_7);                 // scope 3 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_8);                 // scope 3 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_9);                 // scope 3 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_10);                // scope 3 at $DIR/structs.rs:+6:1: +6:2
++         nop;                             // scope 3 at $DIR/structs.rs:+6:1: +6:2
+          StorageDead(_4);                 // scope 2 at $DIR/structs.rs:+6:1: +6:2
+          StorageDead(_3);                 // scope 1 at $DIR/structs.rs:+6:1: +6:2
+-         StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_11);                // scope 0 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_12);                // scope 0 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_13);                // scope 0 at $DIR/structs.rs:+6:1: +6:2
++         StorageDead(_14);                // scope 0 at $DIR/structs.rs:+6:1: +6:2
++         nop;                             // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/structs.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..b6439c00a00
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.dropping.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,44 @@
+- // MIR for `dropping` before ScalarReplacementOfAggregates
++ // MIR for `dropping` after ScalarReplacementOfAggregates
+  
+  fn dropping() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+      let _1: Tag;                         // in scope 0 at $DIR/structs.rs:+1:5: +1:32
+      let mut _2: S;                       // in scope 0 at $DIR/structs.rs:+1:5: +1:30
+      let mut _3: Tag;                     // in scope 0 at $DIR/structs.rs:+1:7: +1:13
+      let mut _4: Tag;                     // in scope 0 at $DIR/structs.rs:+1:15: +1:21
+      let mut _5: Tag;                     // in scope 0 at $DIR/structs.rs:+1:23: +1:29
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/structs.rs:+1:5: +1:32
+          StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+1:5: +1:30
+          StorageLive(_3);                 // scope 0 at $DIR/structs.rs:+1:7: +1:13
+          _3 = Tag(const 0_usize);         // scope 0 at $DIR/structs.rs:+1:7: +1:13
+          StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+1:15: +1:21
+          _4 = Tag(const 1_usize);         // scope 0 at $DIR/structs.rs:+1:15: +1:21
+          StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+1:23: +1:29
+          _5 = Tag(const 2_usize);         // scope 0 at $DIR/structs.rs:+1:23: +1:29
+          _2 = S(move _3, move _4, move _5); // scope 0 at $DIR/structs.rs:+1:5: +1:30
+          StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+1:29: +1:30
+          StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+1:29: +1:30
+          StorageDead(_3);                 // scope 0 at $DIR/structs.rs:+1:29: +1:30
+          _1 = move (_2.1: Tag);           // scope 0 at $DIR/structs.rs:+1:5: +1:32
+          drop(_1) -> bb1;                 // scope 0 at $DIR/structs.rs:+1:32: +1:33
+      }
+  
+      bb1: {
+          drop((_2.0: Tag)) -> bb3;        // scope 0 at $DIR/structs.rs:+1:32: +1:33
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+1:32: +1:33
+          StorageDead(_1);                 // scope 0 at $DIR/structs.rs:+1:32: +1:33
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:19: +2:2
+          return;                          // scope 0 at $DIR/structs.rs:+2:2: +2:2
+      }
+  
+      bb3: {
+          drop((_2.2: Tag)) -> bb2;        // scope 0 at $DIR/structs.rs:+1:32: +1:33
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..ff1e30c2d8f
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.enums.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,43 @@
+- // MIR for `enums` before ScalarReplacementOfAggregates
++ // MIR for `enums` after ScalarReplacementOfAggregates
+  
+  fn enums(_1: usize) -> usize {
+      debug a => _1;                       // in scope 0 at $DIR/structs.rs:+0:14: +0:15
+      let mut _0: usize;                   // return place in scope 0 at $DIR/structs.rs:+0:27: +0:32
+      let mut _2: std::option::Option<usize>; // in scope 0 at $DIR/structs.rs:+1:22: +1:29
+      let mut _3: usize;                   // in scope 0 at $DIR/structs.rs:+1:27: +1:28
+      let mut _4: isize;                   // in scope 0 at $DIR/structs.rs:+1:12: +1:19
+      scope 1 {
+          debug a => _5;                   // in scope 1 at $DIR/structs.rs:+1:17: +1:18
+          let _5: usize;                   // in scope 1 at $DIR/structs.rs:+1:17: +1:18
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/structs.rs:+1:22: +1:29
+          StorageLive(_3);                 // scope 1 at $DIR/structs.rs:+1:27: +1:28
+          _3 = _1;                         // scope 1 at $DIR/structs.rs:+1:27: +1:28
+          _2 = Option::<usize>::Some(move _3); // scope 1 at $DIR/structs.rs:+1:22: +1:29
+          StorageDead(_3);                 // scope 1 at $DIR/structs.rs:+1:28: +1:29
+          _4 = discriminant(_2);           // scope 1 at $DIR/structs.rs:+1:12: +1:19
+          switchInt(move _4) -> [1: bb1, otherwise: bb2]; // scope 1 at $DIR/structs.rs:+1:12: +1:19
+      }
+  
+      bb1: {
+          StorageLive(_5);                 // scope 1 at $DIR/structs.rs:+1:17: +1:18
+          _5 = ((_2 as Some).0: usize);    // scope 1 at $DIR/structs.rs:+1:17: +1:18
+          _0 = _5;                         // scope 1 at $DIR/structs.rs:+1:32: +1:33
+          StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+1:34: +1:35
+          goto -> bb3;                     // scope 0 at $DIR/structs.rs:+1:5: +1:46
+      }
+  
+      bb2: {
+          _0 = const 0_usize;              // scope 0 at $DIR/structs.rs:+1:43: +1:44
+          goto -> bb3;                     // scope 0 at $DIR/structs.rs:+1:5: +1:46
+      }
+  
+      bb3: {
+          StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+2:1: +2:2
+          return;                          // scope 0 at $DIR/structs.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..d45823d4bac
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.escaping.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,44 @@
+- // MIR for `escaping` before ScalarReplacementOfAggregates
++ // MIR for `escaping` after ScalarReplacementOfAggregates
+  
+  fn escaping() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:19: +0:19
+      let _1: ();                          // in scope 0 at $DIR/structs.rs:+1:5: +1:42
+      let mut _2: *const u32;              // in scope 0 at $DIR/structs.rs:+1:7: +1:41
+      let _3: &u32;                        // in scope 0 at $DIR/structs.rs:+1:7: +1:41
+      let _4: Escaping;                    // in scope 0 at $DIR/structs.rs:+1:8: +1:39
+      let mut _5: u32;                     // in scope 0 at $DIR/structs.rs:+1:34: +1:37
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/structs.rs:+1:5: +1:42
+          StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+1:7: +1:41
+          StorageLive(_3);                 // scope 0 at $DIR/structs.rs:+1:7: +1:41
+          StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+1:8: +1:39
+          StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+1:34: +1:37
+          _5 = g() -> bb1;                 // scope 0 at $DIR/structs.rs:+1:34: +1:37
+                                           // mir::Constant
+                                           // + span: $DIR/structs.rs:78:34: 78:35
+                                           // + literal: Const { ty: fn() -> u32 {g}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          _4 = Escaping { a: const 1_u32, b: const 2_u32, c: move _5 }; // scope 0 at $DIR/structs.rs:+1:8: +1:39
+          StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+1:38: +1:39
+          _3 = &(_4.0: u32);               // scope 0 at $DIR/structs.rs:+1:7: +1:41
+          _2 = &raw const (*_3);           // scope 0 at $DIR/structs.rs:+1:7: +1:41
+          _1 = f(move _2) -> bb2;          // scope 0 at $DIR/structs.rs:+1:5: +1:42
+                                           // mir::Constant
+                                           // + span: $DIR/structs.rs:78:5: 78:6
+                                           // + literal: Const { ty: fn(*const u32) {f}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+1:41: +1:42
+          StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+1:42: +1:43
+          StorageDead(_3);                 // scope 0 at $DIR/structs.rs:+1:42: +1:43
+          StorageDead(_1);                 // scope 0 at $DIR/structs.rs:+1:42: +1:43
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:19: +2:2
+          return;                          // scope 0 at $DIR/structs.rs:+2:2: +2:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..1aa11d17b67
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.flat.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,80 @@
+- // MIR for `flat` before ScalarReplacementOfAggregates
++ // MIR for `flat` after ScalarReplacementOfAggregates
+  
+  fn flat() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:15: +0:15
+      let _1: u8;                          // in scope 0 at $DIR/structs.rs:+1:15: +1:16
+      let _2: ();                          // in scope 0 at $DIR/structs.rs:+1:18: +1:19
+      let _3: &str;                        // in scope 0 at $DIR/structs.rs:+1:21: +1:22
+      let _4: std::option::Option<isize>;  // in scope 0 at $DIR/structs.rs:+1:24: +1:25
+      let mut _5: Foo;                     // in scope 0 at $DIR/structs.rs:+1:30: +1:70
+      let mut _6: ();                      // in scope 0 at $DIR/structs.rs:+1:45: +1:47
+      let mut _7: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:60: +1:68
++     let mut _8: u8;                      // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++     let mut _9: ();                      // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++     let mut _10: &str;                   // in scope 0 at $DIR/structs.rs:+1:30: +1:70
++     let mut _11: std::option::Option<isize>; // in scope 0 at $DIR/structs.rs:+1:30: +1:70
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/structs.rs:+1:15: +1:16
+          debug b => _2;                   // in scope 1 at $DIR/structs.rs:+1:18: +1:19
+          debug c => _3;                   // in scope 1 at $DIR/structs.rs:+1:21: +1:22
+          debug d => _4;                   // in scope 1 at $DIR/structs.rs:+1:24: +1:25
+          scope 2 {
+              scope 3 {
+                  scope 4 {
+                      scope 5 {
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         StorageLive(_8);                 // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         StorageLive(_9);                 // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         StorageLive(_10);                // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         StorageLive(_11);                // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         nop;                             // scope 0 at $DIR/structs.rs:+1:30: +1:70
+          StorageLive(_6);                 // scope 0 at $DIR/structs.rs:+1:45: +1:47
+          _6 = ();                         // scope 0 at $DIR/structs.rs:+1:45: +1:47
+          StorageLive(_7);                 // scope 0 at $DIR/structs.rs:+1:60: +1:68
+          _7 = Option::<isize>::Some(const -4_isize); // scope 0 at $DIR/structs.rs:+1:60: +1:68
+-         _5 = Foo { a: const 5_u8, b: move _6, c: const "a", d: move _7 }; // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         _8 = const 5_u8;                 // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         _9 = move _6;                    // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         _10 = const "a";                 // scope 0 at $DIR/structs.rs:+1:30: +1:70
+                                           // mir::Constant
+                                           // + span: $DIR/structs.rs:53:52: 53:55
+                                           // + literal: Const { ty: &str, val: Value(Slice(..)) }
++         _11 = move _7;                   // scope 0 at $DIR/structs.rs:+1:30: +1:70
++         nop;                             // scope 0 at $DIR/structs.rs:+1:30: +1:70
+          StorageDead(_7);                 // scope 0 at $DIR/structs.rs:+1:69: +1:70
+          StorageDead(_6);                 // scope 0 at $DIR/structs.rs:+1:69: +1:70
+          StorageLive(_1);                 // scope 0 at $DIR/structs.rs:+1:15: +1:16
+-         _1 = (_5.0: u8);                 // scope 0 at $DIR/structs.rs:+1:15: +1:16
++         _1 = _8;                         // scope 0 at $DIR/structs.rs:+1:15: +1:16
+          StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+1:18: +1:19
+-         _2 = (_5.1: ());                 // scope 0 at $DIR/structs.rs:+1:18: +1:19
++         _2 = _9;                         // scope 0 at $DIR/structs.rs:+1:18: +1:19
+          StorageLive(_3);                 // scope 0 at $DIR/structs.rs:+1:21: +1:22
+-         _3 = (_5.2: &str);               // scope 0 at $DIR/structs.rs:+1:21: +1:22
++         _3 = _10;                        // scope 0 at $DIR/structs.rs:+1:21: +1:22
+          StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+1:24: +1:25
+-         _4 = (_5.3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:24: +1:25
+-         StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+1:70: +1:71
++         _4 = _11;                        // scope 0 at $DIR/structs.rs:+1:24: +1:25
++         StorageDead(_8);                 // scope 0 at $DIR/structs.rs:+1:70: +1:71
++         StorageDead(_9);                 // scope 0 at $DIR/structs.rs:+1:70: +1:71
++         StorageDead(_10);                // scope 0 at $DIR/structs.rs:+1:70: +1:71
++         StorageDead(_11);                // scope 0 at $DIR/structs.rs:+1:70: +1:71
++         nop;                             // scope 0 at $DIR/structs.rs:+1:70: +1:71
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:15: +6:2
+          StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          StorageDead(_3);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          StorageDead(_1);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/structs.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..7b09ac18263
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.ref_copies.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,56 @@
+- // MIR for `ref_copies` before ScalarReplacementOfAggregates
++ // MIR for `ref_copies` after ScalarReplacementOfAggregates
+  
+  fn ref_copies(_1: &Foo) -> () {
+      debug x => _1;                       // in scope 0 at $DIR/structs.rs:+0:15: +0:16
+      let mut _0: ();                      // return place in scope 0 at $DIR/structs.rs:+0:24: +0:24
+      let _2: Foo;                         // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _5: u8;                          // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _6: ();                          // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _7: &str;                        // in scope 0 at $DIR/structs.rs:+1:9: +1:10
++     let _8: std::option::Option<isize>;  // in scope 0 at $DIR/structs.rs:+1:9: +1:10
+      scope 1 {
+-         debug y => _2;                   // in scope 1 at $DIR/structs.rs:+1:9: +1:10
++         debug y => Foo{ .0 => _5, .1 => _6, .2 => _7, .3 => _8, }; // in scope 1 at $DIR/structs.rs:+1:9: +1:10
+          let _3: u8;                      // in scope 1 at $DIR/structs.rs:+2:9: +2:10
+          scope 2 {
+              debug t => _3;               // in scope 2 at $DIR/structs.rs:+2:9: +2:10
+              let _4: &str;                // in scope 2 at $DIR/structs.rs:+3:9: +3:10
+              scope 3 {
+                  debug u => _4;           // in scope 3 at $DIR/structs.rs:+3:9: +3:10
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
+-         _2 = (*_1);                      // scope 0 at $DIR/structs.rs:+1:13: +1:15
++         StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_6);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_7);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         StorageLive(_8);                 // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         nop;                             // scope 0 at $DIR/structs.rs:+1:9: +1:10
++         _5 = ((*_1).0: u8);              // scope 0 at $DIR/structs.rs:+1:13: +1:15
++         _6 = ((*_1).1: ());              // scope 0 at $DIR/structs.rs:+1:13: +1:15
++         _7 = ((*_1).2: &str);            // scope 0 at $DIR/structs.rs:+1:13: +1:15
++         _8 = ((*_1).3: std::option::Option<isize>); // scope 0 at $DIR/structs.rs:+1:13: +1:15
++         nop;                             // scope 0 at $DIR/structs.rs:+1:13: +1:15
+          StorageLive(_3);                 // scope 1 at $DIR/structs.rs:+2:9: +2:10
+-         _3 = (_2.0: u8);                 // scope 1 at $DIR/structs.rs:+2:13: +2:16
++         _3 = _5;                         // scope 1 at $DIR/structs.rs:+2:13: +2:16
+          StorageLive(_4);                 // scope 2 at $DIR/structs.rs:+3:9: +3:10
+-         _4 = (_2.2: &str);               // scope 2 at $DIR/structs.rs:+3:13: +3:16
++         _4 = _7;                         // scope 2 at $DIR/structs.rs:+3:13: +3:16
+          _0 = const ();                   // scope 0 at $DIR/structs.rs:+0:24: +4:2
+          StorageDead(_4);                 // scope 2 at $DIR/structs.rs:+4:1: +4:2
+          StorageDead(_3);                 // scope 1 at $DIR/structs.rs:+4:1: +4:2
+-         StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+4:1: +4:2
++         StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+4:1: +4:2
++         StorageDead(_6);                 // scope 0 at $DIR/structs.rs:+4:1: +4:2
++         StorageDead(_7);                 // scope 0 at $DIR/structs.rs:+4:1: +4:2
++         StorageDead(_8);                 // scope 0 at $DIR/structs.rs:+4:1: +4:2
++         nop;                             // scope 0 at $DIR/structs.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/structs.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa.rs b/tests/mir-opt/sroa/structs.rs
index fff92cf8d9f..7946eeaeae4 100644
--- a/tests/mir-opt/sroa.rs
+++ b/tests/mir-opt/sroa/structs.rs
@@ -111,12 +111,12 @@ fn main() {
     constant();
 }
 
-// EMIT_MIR sroa.dropping.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.enums.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.structs.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.unions.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.flat.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.escaping.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.copies.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.ref_copies.ScalarReplacementOfAggregates.diff
-// EMIT_MIR sroa.constant.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.dropping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.enums.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.structs.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.unions.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.flat.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.escaping.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.copies.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.ref_copies.ScalarReplacementOfAggregates.diff
+// EMIT_MIR structs.constant.ScalarReplacementOfAggregates.diff
diff --git a/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..c94e4b137bc
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.structs.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,33 @@
+- // MIR for `structs` before ScalarReplacementOfAggregates
++ // MIR for `structs` after ScalarReplacementOfAggregates
+  
+  fn structs(_1: f32) -> f32 {
+      debug a => _1;                       // in scope 0 at $DIR/structs.rs:+0:16: +0:17
+      let mut _0: f32;                     // return place in scope 0 at $DIR/structs.rs:+0:27: +0:30
+      let mut _2: structs::U;              // in scope 0 at $DIR/structs.rs:+6:5: +6:21
+      let mut _3: f32;                     // in scope 0 at $DIR/structs.rs:+6:18: +6:19
++     let mut _4: usize;                   // in scope 0 at $DIR/structs.rs:+6:5: +6:21
++     let mut _5: f32;                     // in scope 0 at $DIR/structs.rs:+6:5: +6:21
+  
+      bb0: {
+-         StorageLive(_2);                 // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         StorageLive(_4);                 // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         StorageLive(_5);                 // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         nop;                             // scope 0 at $DIR/structs.rs:+6:5: +6:21
+          StorageLive(_3);                 // scope 0 at $DIR/structs.rs:+6:18: +6:19
+          _3 = _1;                         // scope 0 at $DIR/structs.rs:+6:18: +6:19
+-         _2 = U { _foo: const 0_usize, a: move _3 }; // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         _4 = const 0_usize;              // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         _5 = move _3;                    // scope 0 at $DIR/structs.rs:+6:5: +6:21
++         nop;                             // scope 0 at $DIR/structs.rs:+6:5: +6:21
+          StorageDead(_3);                 // scope 0 at $DIR/structs.rs:+6:20: +6:21
+-         _0 = (_2.1: f32);                // scope 0 at $DIR/structs.rs:+6:5: +6:23
+-         StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+7:1: +7:2
++         _0 = _5;                         // scope 0 at $DIR/structs.rs:+6:5: +6:23
++         StorageDead(_4);                 // scope 0 at $DIR/structs.rs:+7:1: +7:2
++         StorageDead(_5);                 // scope 0 at $DIR/structs.rs:+7:1: +7:2
++         nop;                             // scope 0 at $DIR/structs.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/structs.rs:+7:2: +7:2
+      }
+  }
+  
diff --git a/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
new file mode 100644
index 00000000000..5aa054589e4
--- /dev/null
+++ b/tests/mir-opt/sroa/structs.unions.ScalarReplacementOfAggregates.diff
@@ -0,0 +1,23 @@
+- // MIR for `unions` before ScalarReplacementOfAggregates
++ // MIR for `unions` after ScalarReplacementOfAggregates
+  
+  fn unions(_1: f32) -> u32 {
+      debug a => _1;                       // in scope 0 at $DIR/structs.rs:+0:15: +0:16
+      let mut _0: u32;                     // return place in scope 0 at $DIR/structs.rs:+0:26: +0:29
+      let mut _2: unions::Repr;            // in scope 0 at $DIR/structs.rs:+5:14: +5:27
+      let mut _3: f32;                     // in scope 0 at $DIR/structs.rs:+5:24: +5:25
+      scope 1 {
+      }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 1 at $DIR/structs.rs:+5:14: +5:27
+          StorageLive(_3);                 // scope 1 at $DIR/structs.rs:+5:24: +5:25
+          _3 = _1;                         // scope 1 at $DIR/structs.rs:+5:24: +5:25
+          _2 = Repr { f: move _3 };        // scope 1 at $DIR/structs.rs:+5:14: +5:27
+          StorageDead(_3);                 // scope 1 at $DIR/structs.rs:+5:26: +5:27
+          _0 = (_2.1: u32);                // scope 1 at $DIR/structs.rs:+5:14: +5:29
+          StorageDead(_2);                 // scope 0 at $DIR/structs.rs:+6:1: +6:2
+          return;                          // scope 0 at $DIR/structs.rs:+6:2: +6:2
+      }
+  }
+  
diff --git a/tests/run-make/coverage-reports/expected_show_coverage.closure.txt b/tests/run-make/coverage-reports/expected_show_coverage.closure.txt
index e463099a5ee..002ecec3b91 100644
--- a/tests/run-make/coverage-reports/expected_show_coverage.closure.txt
+++ b/tests/run-make/coverage-reports/expected_show_coverage.closure.txt
@@ -29,8 +29,8 @@
    29|      1|    some_string = Some(String::from("the string content"));
    30|      1|    let
    31|      1|        a
-   32|      1|    =
-   33|      1|        ||
+   32|       |    =
+   33|       |        ||
    34|      0|    {
    35|      0|        let mut countdown = 0;
    36|      0|        if is_false {
diff --git a/tests/run-make/rustdoc-verify-output-files/Makefile b/tests/run-make/rustdoc-verify-output-files/Makefile
index bfabbbc6586..0666122e8ab 100644
--- a/tests/run-make/rustdoc-verify-output-files/Makefile
+++ b/tests/run-make/rustdoc-verify-output-files/Makefile
@@ -22,15 +22,11 @@ all:
 	# Check if expected json file is generated
 	[ -e $(OUTPUT_DIR)/foobar.json ]
 
-	# TODO
-	# We should re-generate json doc once again and compare the diff with previously
-	# generated one. Because layout of json docs changes in each compilation, we can't
-	# do that currently.
-	#
-	# See https://github.com/rust-lang/rust/issues/103785#issuecomment-1307425590 for details.
+	# Copy first json output to check if it's exactly same after second compilation
+	cp -R $(OUTPUT_DIR)/foobar.json $(TMP_OUTPUT_DIR)/foobar.json
 
-	# remove generated json doc
-	rm $(OUTPUT_DIR)/foobar.json
+	# Generate json doc on the same output
+	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR) -Z unstable-options --output-format json
 
-	# Check if json doc compilation broke any of the html files generated previously
+	# Check if all docs(including both json and html formats) are still the same after multiple compilations
 	$(DIFF) -r -q $(OUTPUT_DIR) $(TMP_OUTPUT_DIR)
diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile
index 5b0b331ca46..397fc542909 100644
--- a/tests/run-make/translation/Makefile
+++ b/tests/run-make/translation/Makefile
@@ -13,22 +13,22 @@ all: normal custom missing broken sysroot sysroot-invalid sysroot-missing
 
 # Check that the test works normally, using the built-in fallback bundle.
 normal: test.rs
-	$(RUSTC) $< 2>&1 | grep "struct literal body without path"
+	$(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path"
 
 # Check that a primary bundle can be loaded and will be preferentially used
 # where possible.
 custom: test.rs working.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | grep "this is a test message"
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message"
 
 # Check that a primary bundle with a broken message (e.g. a interpolated
 # variable is missing) will use the fallback bundle.
 missing: test.rs missing.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | grep "struct literal body without path"
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path"
 
 # Check that a primary bundle without the desired message will use the fallback
 # bundle.
 broken: test.rs broken.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | grep "struct literal body without path"
+	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path"
 
 # Check that a locale can be loaded from the sysroot given a language
 # identifier by making a local copy of the sysroot and adding the custom locale
@@ -48,13 +48,13 @@ sysroot: test.rs working.ftl
 	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
 	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
 	ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message"
+	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "this is a test message"
 
 # Check that the compiler errors out when the sysroot requested cannot be
 # found. This test might start failing if there actually exists a Klingon
 # translation of rustc's error messages.
-sysroot-missing: 
-	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | grep "missing locale directory"
+sysroot-missing:
+	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | $(CGREP) "missing locale directory"
 
 # Check that the compiler errors out when the directory for the locale in the
 # sysroot is actually a file.
@@ -73,4 +73,4 @@ sysroot-invalid: test.rs working.ftl
 	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
 	mkdir -p $(FAKEROOT)/share/locale
 	touch $(FAKEROOT)/share/locale/zh-CN
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "`\$sysroot/share/locales/\$locale` is not a directory"
+	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/tests/rustdoc-js-std/option-type-signatures.js b/tests/rustdoc-js-std/option-type-signatures.js
new file mode 100644
index 00000000000..dee4819e81a
--- /dev/null
+++ b/tests/rustdoc-js-std/option-type-signatures.js
@@ -0,0 +1,7 @@
+const QUERY = 'option, fnonce -> option';
+
+const EXPECTED = {
+    'others': [
+        { 'path': 'std::option::Option', 'name': 'map' },
+    ],
+};
diff --git a/tests/rustdoc-js/where-clause.js b/tests/rustdoc-js/where-clause.js
new file mode 100644
index 00000000000..6cb42a455a3
--- /dev/null
+++ b/tests/rustdoc-js/where-clause.js
@@ -0,0 +1,19 @@
+const QUERY = ['trait<nested>', '-> trait<nested>', 't1, t2'];
+
+const EXPECTED = [
+    {
+        'in_args': [
+           { 'path': 'where_clause', 'name': 'abracadabra' },
+        ],
+    },
+    {
+        'others': [
+            { 'path': 'where_clause', 'name': 'alacazam' },
+        ],
+    },
+    {
+        'others': [
+            { 'path': 'where_clause', 'name': 'presto' },
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/where-clause.rs b/tests/rustdoc-js/where-clause.rs
new file mode 100644
index 00000000000..808561feee2
--- /dev/null
+++ b/tests/rustdoc-js/where-clause.rs
@@ -0,0 +1,16 @@
+pub struct Nested;
+
+pub trait Trait<T> {
+    fn thank_you(x: T);
+}
+
+pub fn abracadabra<X>(_: X) where X: Trait<Nested> {}
+
+pub fn alacazam<X>() -> X where X: Trait<Nested> {}
+
+pub trait T1 {}
+pub trait T2<'a, T> {
+    fn please(_: &'a T);
+}
+
+pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {}
diff --git a/tests/rustdoc/type-layout.rs b/tests/rustdoc/type-layout.rs
index 5e0a0411a62..bd88e73af5c 100644
--- a/tests/rustdoc/type-layout.rs
+++ b/tests/rustdoc/type-layout.rs
@@ -83,3 +83,11 @@ pub enum WithNiche {
     None,
     Some(std::num::NonZeroU32),
 }
+
+// @hasraw type_layout/enum.Uninhabited.html 'Size: '
+// @hasraw - '0 bytes (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)'
+pub enum Uninhabited {}
+
+// @hasraw type_layout/struct.Uninhabited2.html 'Size: '
+// @hasraw - '8 bytes (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)'
+pub struct Uninhabited2(std::convert::Infallible, u64);
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
index 01e6434b075..3151c712566 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs
@@ -514,6 +514,19 @@ struct OptUnitField {
 }
 
 #[derive(Diagnostic)]
+#[diag(no_crate_example)]
+struct BoolField {
+    #[primary_span]
+    spans: Span,
+    #[help]
+    foo: bool,
+    #[help(no_crate_help)]
+    //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()`
+    // only allow plain 'bool' fields
+    bar: Option<bool>,
+}
+
+#[derive(Diagnostic)]
 #[diag(no_crate_example, code = "E0123")]
 struct LabelWithTrailingPath {
     #[label(no_crate_label, foo)]
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index fc0cd8419e4..513b675e5dd 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -352,8 +352,14 @@ error: invalid applicability
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
    |                                                     ^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()`
+  --> $DIR/diagnostic-derive.rs:523:5
+   |
+LL |     #[help(no_crate_help)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
 error: `#[label(foo)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:519:29
+  --> $DIR/diagnostic-derive.rs:532:29
    |
 LL |     #[label(no_crate_label, foo)]
    |                             ^^^
@@ -361,19 +367,19 @@ LL |     #[label(no_crate_label, foo)]
    = help: a diagnostic slug must be the first argument to the attribute
 
 error: `#[label(foo = ...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:527:29
+  --> $DIR/diagnostic-derive.rs:540:29
    |
 LL |     #[label(no_crate_label, foo = "...")]
    |                             ^^^^^^^^^^^
 
 error: `#[label(foo(...))]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:535:29
+  --> $DIR/diagnostic-derive.rs:548:29
    |
 LL |     #[label(no_crate_label, foo("..."))]
    |                             ^^^^^^^^^^
 
 error: `#[primary_span]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:547:5
+  --> $DIR/diagnostic-derive.rs:560:5
    |
 LL |     #[primary_span]
    |     ^^^^^^^^^^^^^^^
@@ -381,13 +387,13 @@ LL |     #[primary_span]
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
 error: `#[error(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:567:1
+  --> $DIR/diagnostic-derive.rs:580:1
    |
 LL | #[error(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:567:1
+  --> $DIR/diagnostic-derive.rs:580:1
    |
 LL | / #[error(no_crate_example, code = "E0123")]
 LL | |
@@ -399,13 +405,13 @@ LL | | struct ErrorAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[warn_(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:574:1
+  --> $DIR/diagnostic-derive.rs:587:1
    |
 LL | #[warn_(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:574:1
+  --> $DIR/diagnostic-derive.rs:587:1
    |
 LL | / #[warn_(no_crate_example, code = "E0123")]
 LL | |
@@ -417,13 +423,13 @@ LL | | struct WarnAttribute {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:581:1
+  --> $DIR/diagnostic-derive.rs:594:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:581:1
+  --> $DIR/diagnostic-derive.rs:594:1
    |
 LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
@@ -435,19 +441,19 @@ LL | | struct LintAttributeOnSessionDiag {}
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:588:1
+  --> $DIR/diagnostic-derive.rs:601:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[lint(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:588:1
+  --> $DIR/diagnostic-derive.rs:601:1
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostic slug not specified
-  --> $DIR/diagnostic-derive.rs:588:1
+  --> $DIR/diagnostic-derive.rs:601:1
    |
 LL | / #[lint(no_crate_example, code = "E0123")]
 LL | |
@@ -460,19 +466,19 @@ LL | | struct LintAttributeOnLintDiag {}
    = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
 error: specified multiple times
-  --> $DIR/diagnostic-derive.rs:598:53
+  --> $DIR/diagnostic-derive.rs:611:53
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
    |                                                     ^^^^^^^^^^^^
    |
 note: previously specified here
-  --> $DIR/diagnostic-derive.rs:598:39
+  --> $DIR/diagnostic-derive.rs:611:39
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
    |                                       ^^^^^^^^^^^^
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:607:24
+  --> $DIR/diagnostic-derive.rs:620:24
    |
 LL |     suggestion: (Span, usize),
    |                        ^^^^^
@@ -480,7 +486,7 @@ LL |     suggestion: (Span, usize),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: wrong types for suggestion
-  --> $DIR/diagnostic-derive.rs:615:17
+  --> $DIR/diagnostic-derive.rs:628:17
    |
 LL |     suggestion: (Span,),
    |                 ^^^^^^^
@@ -488,13 +494,13 @@ LL |     suggestion: (Span,),
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
 error: suggestion without `code = "..."`
-  --> $DIR/diagnostic-derive.rs:622:5
+  --> $DIR/diagnostic-derive.rs:635:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:629:1
+  --> $DIR/diagnostic-derive.rs:642:1
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -502,7 +508,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)]
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:632:1
+  --> $DIR/diagnostic-derive.rs:645:1
    |
 LL | #[multipart_suggestion()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -510,7 +516,7 @@ LL | #[multipart_suggestion()]
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[multipart_suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:636:5
+  --> $DIR/diagnostic-derive.rs:649:5
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -518,7 +524,7 @@ LL |     #[multipart_suggestion(no_crate_suggestion)]
    = help: consider creating a `Subdiagnostic` instead
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:644:1
+  --> $DIR/diagnostic-derive.rs:657:1
    |
 LL | #[suggestion(no_crate_suggestion, code = "...")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -526,7 +532,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")]
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
 error: `#[label]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:653:1
+  --> $DIR/diagnostic-derive.rs:666:1
    |
 LL | #[label]
    | ^^^^^^^^
@@ -534,7 +540,7 @@ LL | #[label]
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:687:5
+  --> $DIR/diagnostic-derive.rs:700:5
    |
 LL |     #[subdiagnostic(bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -542,13 +548,13 @@ LL |     #[subdiagnostic(bad)]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic = ...]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:695:5
+  --> $DIR/diagnostic-derive.rs:708:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:703:5
+  --> $DIR/diagnostic-derive.rs:716:5
    |
 LL |     #[subdiagnostic(bad, bad)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -556,7 +562,7 @@ LL |     #[subdiagnostic(bad, bad)]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:711:5
+  --> $DIR/diagnostic-derive.rs:724:5
    |
 LL |     #[subdiagnostic("bad")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -564,7 +570,7 @@ LL |     #[subdiagnostic("bad")]
    = help: `eager` is the only supported nested attribute for `subdiagnostic`
 
 error: `#[subdiagnostic(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:719:5
+  --> $DIR/diagnostic-derive.rs:732:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -572,25 +578,25 @@ LL |     #[subdiagnostic(eager)]
    = help: eager subdiagnostics are not supported on lints
 
 error: expected at least one string literal for `code(...)`
-  --> $DIR/diagnostic-derive.rs:777:18
+  --> $DIR/diagnostic-derive.rs:790:18
    |
 LL |     #[suggestion(code())]
    |                  ^^^^^^
 
 error: `code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:785:23
+  --> $DIR/diagnostic-derive.rs:798:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
 error: `code = "..."`/`code(...)` must contain only string literals
-  --> $DIR/diagnostic-derive.rs:793:18
+  --> $DIR/diagnostic-derive.rs:806:18
    |
 LL |     #[suggestion(code = 3)]
    |                  ^^^^^^^^
 
 error: `#[suggestion(...)]` is not a valid attribute
-  --> $DIR/diagnostic-derive.rs:808:5
+  --> $DIR/diagnostic-derive.rs:821:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "")]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -612,43 +618,43 @@ LL |     #[nonsense]
    |       ^^^^^^^^
 
 error: cannot find attribute `error` in this scope
-  --> $DIR/diagnostic-derive.rs:567:3
+  --> $DIR/diagnostic-derive.rs:580:3
    |
 LL | #[error(no_crate_example, code = "E0123")]
    |   ^^^^^
 
 error: cannot find attribute `warn_` in this scope
-  --> $DIR/diagnostic-derive.rs:574:3
+  --> $DIR/diagnostic-derive.rs:587:3
    |
 LL | #[warn_(no_crate_example, code = "E0123")]
    |   ^^^^^ help: a built-in attribute with a similar name exists: `warn`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:581:3
+  --> $DIR/diagnostic-derive.rs:594:3
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `lint` in this scope
-  --> $DIR/diagnostic-derive.rs:588:3
+  --> $DIR/diagnostic-derive.rs:601:3
    |
 LL | #[lint(no_crate_example, code = "E0123")]
    |   ^^^^ help: a built-in attribute with a similar name exists: `link`
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:629:3
+  --> $DIR/diagnostic-derive.rs:642:3
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:632:3
+  --> $DIR/diagnostic-derive.rs:645:3
    |
 LL | #[multipart_suggestion()]
    |   ^^^^^^^^^^^^^^^^^^^^
 
 error: cannot find attribute `multipart_suggestion` in this scope
-  --> $DIR/diagnostic-derive.rs:636:7
+  --> $DIR/diagnostic-derive.rs:649:7
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
    |       ^^^^^^^^^^^^^^^^^^^^
@@ -670,7 +676,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg`
   --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC
    = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 84 previous errors
+error: aborting due to 85 previous errors
 
 Some errors have detailed explanations: E0277, E0425.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-types/issue-67684.rs b/tests/ui/associated-types/issue-67684.rs
index 49efe8a1bda..c6920cf8d40 100644
--- a/tests/ui/associated-types/issue-67684.rs
+++ b/tests/ui/associated-types/issue-67684.rs
@@ -1,4 +1,10 @@
-// check-pass
+// revisions: check build
+// [check]check-pass
+//
+// This second configuration aims to verify that we do not ICE in ConstProp because of
+// normalization failure.
+// [build]build-pass
+// [build]compile-flags: -Zmir-opt-level=3 --emit=mir
 
 #![allow(dead_code)]
 
diff --git a/tests/ui/async-await/issue-108572.rs b/tests/ui/async-await/issue-108572.rs
new file mode 100644
index 00000000000..efcb8b8ebab
--- /dev/null
+++ b/tests/ui/async-await/issue-108572.rs
@@ -0,0 +1,12 @@
+// edition: 2021
+
+use std::future::Future;
+fn foo() -> impl Future<Output=()> {
+    async { }
+}
+
+fn main() {
+    let fut = foo();
+    fut.poll();
+    //~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
+}
diff --git a/tests/ui/async-await/issue-108572.stderr b/tests/ui/async-await/issue-108572.stderr
new file mode 100644
index 00000000000..0dbcf4d660a
--- /dev/null
+++ b/tests/ui/async-await/issue-108572.stderr
@@ -0,0 +1,12 @@
+error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
+  --> $DIR/issue-108572.rs:10:9
+   |
+LL |     fut.poll();
+   |         ^^^^ method not found in `impl Future<Output = ()>`
+   |
+   = help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
+   = help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/auto-traits/suspicious-negative-impls-lint.rs b/tests/ui/auto-traits/suspicious-negative-impls-lint.rs
new file mode 100644
index 00000000000..34842e5944b
--- /dev/null
+++ b/tests/ui/auto-traits/suspicious-negative-impls-lint.rs
@@ -0,0 +1,21 @@
+#![feature(negative_impls)]
+#![deny(suspicious_auto_trait_impls)]
+
+use std::marker::PhantomData;
+
+struct ContainsVec<T>(Vec<T>);
+impl !Send for ContainsVec<u32> {}
+//~^ ERROR
+//~| WARNING this will change its meaning
+
+pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U);
+impl<T> !Send for WithPhantomDataSend<*const T, u8> {}
+//~^ ERROR
+//~| WARNING this will change its meaning
+
+pub struct WithLifetime<'a, T>(&'a (), T);
+impl<T> !Sync for WithLifetime<'static, Option<T>> {}
+//~^ ERROR
+//~| WARNING this will change its meaning
+
+fn main() {}
diff --git a/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr b/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr
new file mode 100644
index 00000000000..ee03ea12557
--- /dev/null
+++ b/tests/ui/auto-traits/suspicious-negative-impls-lint.stderr
@@ -0,0 +1,52 @@
+error: cross-crate traits with a default impl, like `Send`, should not be specialized
+  --> $DIR/suspicious-negative-impls-lint.rs:7:1
+   |
+LL | impl !Send for ContainsVec<u32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `u32` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $DIR/suspicious-negative-impls-lint.rs:6:1
+   |
+LL | struct ContainsVec<T>(Vec<T>);
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: the lint level is defined here
+  --> $DIR/suspicious-negative-impls-lint.rs:2:9
+   |
+LL | #![deny(suspicious_auto_trait_impls)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cross-crate traits with a default impl, like `Send`, should not be specialized
+  --> $DIR/suspicious-negative-impls-lint.rs:12:1
+   |
+LL | impl<T> !Send for WithPhantomDataSend<*const T, u8> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `*const T` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $DIR/suspicious-negative-impls-lint.rs:11:1
+   |
+LL | pub struct WithPhantomDataSend<T, U>(PhantomData<T>, U);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cross-crate traits with a default impl, like `Sync`, should not be specialized
+  --> $DIR/suspicious-negative-impls-lint.rs:17:1
+   |
+LL | impl<T> !Sync for WithLifetime<'static, Option<T>> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `Option<T>` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $DIR/suspicious-negative-impls-lint.rs:16:1
+   |
+LL | pub struct WithLifetime<'a, T>(&'a (), T);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
index 1bda7a49713..127a3f5b2dc 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.rs
@@ -8,6 +8,7 @@ fn a() {
         //~^ NOTE `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE `vec[_]` is assigned to here
+            //~| NOTE in this expansion of desugaring of drop and replace
             _a.use_ref();
             //~^ NOTE borrow later used here
         }
@@ -22,6 +23,7 @@ fn b() {
         //~^ `vec[_]` is borrowed here
             vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE `vec[_]` is assigned to here
+            //~| NOTE in this expansion of desugaring of drop and replace
             _b.use_ref();
             //~^ NOTE borrow later used here
         }
diff --git a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
index 70b9e4f4433..5e1251b0590 100644
--- a/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
+++ b/tests/ui/borrowck/borrowck-vec-pattern-nesting.stderr
@@ -6,24 +6,24 @@ LL |         [box ref _a, _, _] => {
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
-LL |
+...
 LL |             _a.use_ref();
    |             ------------ borrow later used here
 
 error[E0506]: cannot assign to `vec[_]` because it is borrowed
-  --> $DIR/borrowck-vec-pattern-nesting.rs:23:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:24:13
    |
 LL |         &mut [ref _b @ ..] => {
    |               ------ `vec[_]` is borrowed here
 LL |
 LL |             vec[0] = Box::new(4);
    |             ^^^^^^ `vec[_]` is assigned to here but it was already borrowed
-LL |
+...
 LL |             _b.use_ref();
    |             ------------ borrow later used here
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:34:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:36:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -41,7 +41,7 @@ LL +         [_a,
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:46:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:48:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -55,7 +55,7 @@ LL |     let a = &vec[0];
    |             +
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:55:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:57:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -73,7 +73,7 @@ LL +         [
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:65:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:67:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
@@ -87,7 +87,7 @@ LL |     let a = &vec[0];
    |             +
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:74:11
+  --> $DIR/borrowck-vec-pattern-nesting.rs:76:11
    |
 LL |     match vec {
    |           ^^^ cannot move out of here
@@ -106,7 +106,7 @@ LL +         [_a, _b, _c] => {}
    |
 
 error[E0508]: cannot move out of type `[Box<isize>]`, a non-copy slice
-  --> $DIR/borrowck-vec-pattern-nesting.rs:85:13
+  --> $DIR/borrowck-vec-pattern-nesting.rs:87:13
    |
 LL |     let a = vec[0];
    |             ^^^^^^
diff --git a/tests/ui/borrowck/drop-in-loop.rs b/tests/ui/borrowck/drop-in-loop.rs
new file mode 100644
index 00000000000..866c27ef203
--- /dev/null
+++ b/tests/ui/borrowck/drop-in-loop.rs
@@ -0,0 +1,24 @@
+// A version of `issue-70919-drop-in-loop`, but without
+// the necessary `drop` call.
+//
+// This should fail to compile, since the `Drop` impl
+// for `WrapperWithDrop` could observe the changed
+// `base` value.
+
+struct WrapperWithDrop<'a>(&'a mut bool);
+impl<'a> Drop for WrapperWithDrop<'a> {
+    fn drop(&mut self) {
+    }
+}
+
+fn drop_in_loop() {
+    let mut base = true;
+    let mut wrapper = WrapperWithDrop(&mut base);
+    loop {
+        base = false; //~ ERROR: cannot assign to `base`
+        wrapper = WrapperWithDrop(&mut base);
+    }
+}
+
+fn main() {
+}
diff --git a/tests/ui/borrowck/drop-in-loop.stderr b/tests/ui/borrowck/drop-in-loop.stderr
new file mode 100644
index 00000000000..d5734e7ec97
--- /dev/null
+++ b/tests/ui/borrowck/drop-in-loop.stderr
@@ -0,0 +1,14 @@
+error[E0506]: cannot assign to `base` because it is borrowed
+  --> $DIR/drop-in-loop.rs:18:9
+   |
+LL |     let mut wrapper = WrapperWithDrop(&mut base);
+   |                                       --------- `base` is borrowed here
+LL |     loop {
+LL |         base = false;
+   |         ^^^^^^^^^^^^ `base` is assigned to here but it was already borrowed
+LL |         wrapper = WrapperWithDrop(&mut base);
+   |         ------- borrow might be used here, when `wrapper` is dropped and runs the `Drop` code for type `WrapperWithDrop`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-45199.rs b/tests/ui/borrowck/issue-45199.rs
index ded46e56e34..6a6b25541f3 100644
--- a/tests/ui/borrowck/issue-45199.rs
+++ b/tests/ui/borrowck/issue-45199.rs
@@ -5,6 +5,7 @@ fn test_drop_replace() {
     b = Box::new(1);    //~ NOTE first assignment
     b = Box::new(2);    //~ ERROR cannot assign twice to immutable variable `b`
                         //~| NOTE cannot assign twice to immutable
+                        //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn test_call() {
@@ -13,12 +14,14 @@ fn test_call() {
                             //~| SUGGESTION mut b
     b = Box::new(2);        //~ ERROR cannot assign twice to immutable variable `b`
                             //~| NOTE cannot assign twice to immutable
+                            //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn test_args(b: Box<i32>) {  //~ HELP consider making this binding mutable
                                 //~| SUGGESTION mut b
     b = Box::new(2);            //~ ERROR cannot assign to immutable argument `b`
                                 //~| NOTE cannot assign to immutable argument
+                                //~| NOTE in this expansion of desugaring of drop and replace
 }
 
 fn main() {}
diff --git a/tests/ui/borrowck/issue-45199.stderr b/tests/ui/borrowck/issue-45199.stderr
index 47aa3090827..163f2370ba0 100644
--- a/tests/ui/borrowck/issue-45199.stderr
+++ b/tests/ui/borrowck/issue-45199.stderr
@@ -10,7 +10,7 @@ LL |     b = Box::new(2);
    |     ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign twice to immutable variable `b`
-  --> $DIR/issue-45199.rs:14:5
+  --> $DIR/issue-45199.rs:15:5
    |
 LL |     let b = Box::new(1);
    |         -
@@ -22,7 +22,7 @@ LL |     b = Box::new(2);
    |     ^ cannot assign twice to immutable variable
 
 error[E0384]: cannot assign to immutable argument `b`
-  --> $DIR/issue-45199.rs:20:5
+  --> $DIR/issue-45199.rs:22:5
    |
 LL | fn test_args(b: Box<i32>) {
    |              - help: consider making this binding mutable: `mut b`
diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs
index efa313a9d23..0b2372d1274 100644
--- a/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs
+++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.rs
@@ -5,7 +5,6 @@ fn main() {
     greeting = "DEALLOCATED".to_string();
     //~^ ERROR cannot assign
     drop(greeting);
-    //~^ ERROR cannot move
 
     println!("thread result: {:?}", res);
 }
diff --git a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
index 0870b423769..967451c68be 100644
--- a/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
+++ b/tests/ui/borrowck/issue-58776-borrowck-scans-children.stderr
@@ -12,21 +12,6 @@ LL |     greeting = "DEALLOCATED".to_string();
 LL |     println!("thread result: {:?}", res);
    |                                     --- borrow later used here
 
-error[E0505]: cannot move out of `greeting` because it is borrowed
-  --> $DIR/issue-58776-borrowck-scans-children.rs:7:10
-   |
-LL |     let res = (|| (|| &greeting)())();
-   |                --      -------- borrow occurs due to use in closure
-   |                |
-   |                borrow of `greeting` occurs here
-...
-LL |     drop(greeting);
-   |          ^^^^^^^^ move out of `greeting` occurs here
-...
-LL |     println!("thread result: {:?}", res);
-   |                                     --- borrow later used here
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0505, E0506.
-For more information about an error, try `rustc --explain E0505`.
+For more information about this error, try `rustc --explain E0506`.
diff --git a/tests/ui/borrowck/issue-70919-drop-in-loop.rs b/tests/ui/borrowck/issue-70919-drop-in-loop.rs
new file mode 100644
index 00000000000..a8d5849a31c
--- /dev/null
+++ b/tests/ui/borrowck/issue-70919-drop-in-loop.rs
@@ -0,0 +1,25 @@
+// Regression test for issue #70919
+// Tests that we don't emit a spurious "borrow might be used" error
+// when we have an explicit `drop` in a loop
+
+// check-pass
+
+struct WrapperWithDrop<'a>(&'a mut bool);
+impl<'a> Drop for WrapperWithDrop<'a> {
+    fn drop(&mut self) {
+    }
+}
+
+fn drop_in_loop() {
+    let mut base = true;
+    let mut wrapper = WrapperWithDrop(&mut base);
+    loop {
+        drop(wrapper);
+
+        base = false;
+        wrapper = WrapperWithDrop(&mut base);
+    }
+}
+
+fn main() {
+}
diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs
index 24b87892753..76a57936e69 100644
--- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs
+++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.rs
@@ -13,5 +13,7 @@ impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and nega
 unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
 
 impl !Send for TestType<i32> {}
+//~^ WARNING
+//~| WARNING this will change its meaning
 
 fn main() {}
diff --git a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr
index 2463f38a922..020199da991 100644
--- a/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr
+++ b/tests/ui/coherence/coherence-conflicting-negative-trait-impl.stderr
@@ -16,7 +16,23 @@ LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
 LL | unsafe impl<T: 'static> Send for TestType<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
 
-error: aborting due to 2 previous errors
+warning: cross-crate traits with a default impl, like `Send`, should not be specialized
+  --> $DIR/coherence-conflicting-negative-trait-impl.rs:15:1
+   |
+LL | impl !Send for TestType<i32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `i32` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $DIR/coherence-conflicting-negative-trait-impl.rs:7:1
+   |
+LL | struct TestType<T>(::std::marker::PhantomData<T>);
+   | ^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(suspicious_auto_trait_impls)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0119, E0751.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/coherence/coherence-orphan.rs b/tests/ui/coherence/coherence-orphan.rs
index 3beac04c7e8..bed782203af 100644
--- a/tests/ui/coherence/coherence-orphan.rs
+++ b/tests/ui/coherence/coherence-orphan.rs
@@ -14,7 +14,8 @@ impl TheTrait<TheType> for isize { }
 
 impl TheTrait<isize> for TheType { }
 
-impl !Send for Vec<isize> { }
-//~^ ERROR E0117
+impl !Send for Vec<isize> { } //~ ERROR E0117
+//~^ WARNING
+//~| WARNING this will change its meaning
 
 fn main() { }
diff --git a/tests/ui/coherence/coherence-orphan.stderr b/tests/ui/coherence/coherence-orphan.stderr
index 01f166a21f7..9ec1d0dc32a 100644
--- a/tests/ui/coherence/coherence-orphan.stderr
+++ b/tests/ui/coherence/coherence-orphan.stderr
@@ -21,6 +21,19 @@ LL | impl !Send for Vec<isize> { }
    |
    = note: define and implement a trait or new type instead
 
-error: aborting due to 2 previous errors
+warning: cross-crate traits with a default impl, like `Send`, should not be specialized
+  --> $DIR/coherence-orphan.rs:17:1
+   |
+LL | impl !Send for Vec<isize> { }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `isize` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+   = note: `#[warn(suspicious_auto_trait_impls)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0117`.
diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
new file mode 100644
index 00000000000..d9a74b4f3e2
--- /dev/null
+++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
@@ -0,0 +1,9 @@
+#![feature(const_slice_index)]
+
+const A: [(); 5] = [(), (), (), (), ()];
+
+// Since the indexing is on a ZST, the addresses are all fine,
+// but we should still catch the bad range.
+const B: &[()] = unsafe { A.get_unchecked(3..1) };
+
+fn main() {}
diff --git a/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
new file mode 100644
index 00000000000..775e475dfeb
--- /dev/null
+++ b/tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
@@ -0,0 +1,18 @@
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/slice/index.rs:LL:COL
+   |
+   = note: overflow executing `unchecked_sub`
+   |
+note: inside `<std::ops::Range<usize> as SliceIndex<[()]>>::get_unchecked`
+  --> $SRC_DIR/core/src/slice/index.rs:LL:COL
+note: inside `core::slice::<impl [()]>::get_unchecked::<std::ops::Range<usize>>`
+  --> $SRC_DIR/core/src/slice/mod.rs:LL:COL
+note: inside `B`
+  --> $DIR/ub-slice-get-unchecked.rs:7:27
+   |
+LL | const B: &[()] = unsafe { A.get_unchecked(3..1) };
+   |                           ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
new file mode 100644
index 00000000000..5cf90c5d93c
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(return_position_impl_trait_in_trait)]
+//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
+
+trait Trait {
+    type Type;
+
+    // Check that we're adjusting bound vars correctly when installing the default
+    // method projection assumptions.
+    fn method(&self) -> impl Trait<Type = impl Sized + '_>;
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
new file mode 100644
index 00000000000..7c7ebcdb7e7
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/default-method-binder-shifting.stderr
@@ -0,0 +1,11 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-method-binder-shifting.rs:3:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs
new file mode 100644
index 00000000000..746a4a929ae
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.rs
@@ -0,0 +1,16 @@
+#![feature(return_position_impl_trait_in_trait)]
+//~^ WARN the feature `return_position_impl_trait_in_trait` is incomplete
+
+trait MyTrait {
+    fn foo(&self) -> impl Sized;
+    fn bar(&self) -> impl Sized;
+}
+
+impl MyTrait for i32 {
+//~^ ERROR not all trait items implemented, missing: `foo`
+    fn bar(&self) -> impl Sized {
+        self.foo()
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr
new file mode 100644
index 00000000000..d7f2e460fb0
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-project-to-rpitit-with-no-value.stderr
@@ -0,0 +1,21 @@
+warning: the feature `return_position_impl_trait_in_trait` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-project-to-rpitit-with-no-value.rs:1:12
+   |
+LL | #![feature(return_position_impl_trait_in_trait)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0046]: not all trait items implemented, missing: `foo`
+  --> $DIR/dont-project-to-rpitit-with-no-value.rs:9:1
+   |
+LL |     fn foo(&self) -> impl Sized;
+   |     ---------------------------- `foo` from trait
+...
+LL | impl MyTrait for i32 {
+   | ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr
index 662c74bcdc0..9c67f17e963 100644
--- a/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr
+++ b/tests/ui/impl-trait/recursive-impl-trait-type-indirect.drop_tracking_mir.stderr
@@ -114,6 +114,9 @@ error[E0720]: cannot resolve opaque type
    |
 LL | fn generator_hold() -> impl Sized {
    |                        ^^^^^^^^^^ recursive opaque type
+...
+LL |         let x = generator_hold();
+   |             - generator captures itself here
 
 error[E0720]: cannot resolve opaque type
   --> $DIR/recursive-impl-trait-type-indirect.rs:90:26
diff --git a/tests/ui/issues/issue-106755.rs b/tests/ui/issues/issue-106755.rs
index 46ece725fb7..5eabc3bfb13 100644
--- a/tests/ui/issues/issue-106755.rs
+++ b/tests/ui/issues/issue-106755.rs
@@ -15,5 +15,7 @@ impl<T: MyTrait> !Send for TestType<T> {} //~ ERROR found both positive and nega
 unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
 
 impl !Send for TestType<i32> {}
+//~^ WARNING
+//~| WARNING this will change its meaning
 
 fn main() {}
diff --git a/tests/ui/issues/issue-106755.stderr b/tests/ui/issues/issue-106755.stderr
index 54397034062..6b3a8427e77 100644
--- a/tests/ui/issues/issue-106755.stderr
+++ b/tests/ui/issues/issue-106755.stderr
@@ -16,7 +16,23 @@ LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
 LL | unsafe impl<T: 'static> Send for TestType<T> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
 
-error: aborting due to 2 previous errors
+warning: cross-crate traits with a default impl, like `Send`, should not be specialized
+  --> $DIR/issue-106755.rs:17:1
+   |
+LL | impl !Send for TestType<i32> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #93367 <https://github.com/rust-lang/rust/issues/93367>
+   = note: `i32` is not a generic parameter
+note: try using the same sequence of generic parameters as the struct definition
+  --> $DIR/issue-106755.rs:9:1
+   |
+LL | struct TestType<T>(::std::marker::PhantomData<T>);
+   | ^^^^^^^^^^^^^^^^^^
+   = note: `#[warn(suspicious_auto_trait_impls)]` on by default
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0119, E0751.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/lint/unconditional_panic_98444.rs b/tests/ui/lint/unconditional_panic_98444.rs
new file mode 100644
index 00000000000..011fabfbbe9
--- /dev/null
+++ b/tests/ui/lint/unconditional_panic_98444.rs
@@ -0,0 +1,7 @@
+// build-fail
+
+fn main() {
+    let xs: [i32; 5] = [1, 2, 3, 4, 5];
+    let _ = &xs;
+    let _ = xs[7]; //~ ERROR: this operation will panic at runtime [unconditional_panic]
+}
diff --git a/tests/ui/lint/unconditional_panic_98444.stderr b/tests/ui/lint/unconditional_panic_98444.stderr
new file mode 100644
index 00000000000..a347458097f
--- /dev/null
+++ b/tests/ui/lint/unconditional_panic_98444.stderr
@@ -0,0 +1,10 @@
+error: this operation will panic at runtime
+  --> $DIR/unconditional_panic_98444.rs:6:13
+   |
+LL |     let _ = xs[7];
+   |             ^^^^^ index out of bounds: the length is 5 but the index is 7
+   |
+   = note: `#[deny(unconditional_panic)]` on by default
+
+error: aborting due to previous error
+
diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
index c9b16e43910..293fdca1cc9 100644
--- a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
+++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs
@@ -5,6 +5,7 @@ fn test() {
     drop(b);
     b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b`
                      //~| NOTE cannot assign twice to immutable
+                     //~| NOTE in this expansion of desugaring of drop and replace
     drop(b);
 }
 
diff --git a/tests/ui/mir/unsize-trait.rs b/tests/ui/mir/unsize-trait.rs
new file mode 100644
index 00000000000..45b5308c093
--- /dev/null
+++ b/tests/ui/mir/unsize-trait.rs
@@ -0,0 +1,15 @@
+// Check that the interpreter does not ICE when trying to unsize `B` to `[u8]`.
+// This is a `build` test to ensure that const-prop-lint runs.
+// build-pass
+
+#![feature(unsize)]
+
+fn foo<B>(buffer: &mut [B; 2])
+    where B: std::marker::Unsize<[u8]>,
+{
+    let buffer: &[u8] = &buffer[0];
+}
+
+fn main() {
+    foo(&mut [[0], [5]]);
+}
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs b/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs
new file mode 100644
index 00000000000..d8772e86894
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/type-test-subject-non-trivial-region.rs
@@ -0,0 +1,19 @@
+// See #108639 for description.
+// check-pass
+
+trait Trait {
+    type Item<'a>: 'a;
+}
+
+fn assert_static<T: 'static>(_: T) {}
+fn relate<T>(_: T, _: T) {}
+
+fn test_args<I: Trait>() {
+    let closure = |a, b| {
+        relate(&a, b);
+        assert_static(a);
+    };
+    closure(None::<I::Item<'_>>, &None::<I::Item<'_>>);
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs b/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs
new file mode 100644
index 00000000000..fce6f2fee7f
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/type-test-subject-opaque-1.rs
@@ -0,0 +1,18 @@
+// Regression test for #107426.
+// check-pass
+
+use std::marker::PhantomData;
+#[derive(Clone, Copy)]
+pub struct Scope<'a>(&'a PhantomData<&'a mut &'a ()>);
+fn event<'a, F: FnMut() + 'a>(_: Scope<'a>, _: F) {}
+fn make_fn<'a>(_: Scope<'a>) -> impl Fn() + Copy + 'a {
+    || {}
+}
+
+fn foo(cx: Scope) {
+    let open_toggle = make_fn(cx);
+
+    || event(cx, open_toggle);
+}
+
+fn main() {}
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-opaque-2.rs b/tests/ui/nll/closure-requirements/type-test-subject-opaque-2.rs
new file mode 100644
index 00000000000..55905850f0c
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/type-test-subject-opaque-2.rs
@@ -0,0 +1,17 @@
+// Resgression test for #107516.
+// check-pass
+
+fn iter1<'a: 'a>() -> impl Iterator<Item = &'static str> {
+    None.into_iter()
+}
+
+fn iter2<'a>() -> impl Iterator<Item = &'a str> {
+    None.into_iter()
+}
+
+struct Bivar<'a, I: Iterator<Item = &'a str> + 'a>(I);
+
+fn main() {
+    let _ = || Bivar(iter1());
+    let _ = || Bivar(iter2());
+}
diff --git a/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs b/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs
new file mode 100644
index 00000000000..b5a95c17009
--- /dev/null
+++ b/tests/ui/nll/closure-requirements/type-test-subject-unnamed-region.rs
@@ -0,0 +1,24 @@
+// See #108635 for description.
+// check-pass
+
+trait Trait {
+    type Item<'a>: 'a;
+}
+
+fn assert_static<T: 'static>(_: T) {}
+
+fn test_args<I: Trait>() {
+    let closure = |a, _b| assert_static(a);
+
+    closure(None::<I::Item<'_>>, &None::<I::Item<'_>>);
+}
+
+fn test_upvars<I: Trait>() {
+    let upvars = (None::<I::Item<'_>>, &None::<I::Item<'_>>);
+    let _closure = || {
+        let (a, _b) = upvars;
+        assert_static(a);
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
index dbda04c42c5..11ada59c066 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-closure.stderr
@@ -110,7 +110,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+   = note: where <T as Anything<'_#2r>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-one-region-closure.rs:62:1
diff --git a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
index 250c796e2c7..47d4f2e46c6 100644
--- a/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr
@@ -86,7 +86,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+   = note: where <T as Anything<'_#2r>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-one-region-trait-bound-closure.rs:52:1
diff --git a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
index 90f04914286..530dd86819d 100644
--- a/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
+++ b/tests/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr
@@ -11,7 +11,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
            ]
    = note: late-bound region is '_#4r
    = note: number of external vids: 5
-   = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: '_#3r
+   = note: where <T as Anything<'_#1r, '_#2r>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:34:1
@@ -23,14 +23,14 @@ LL | |     T: Anything<'b, 'c>,
    |
    = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
 
-error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:38:39
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
+   = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<'_#5r, '_#6r>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
@@ -44,7 +44,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:43:1
@@ -57,14 +57,14 @@ LL | |     'a: 'a,
    |
    = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
 
-error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
+error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
   --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
    |
 LL |     with_signature(cell, t, |cell, t| require(cell, t));
    |                                       ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
-   = note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
+   = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: 'a`...
+   = note: ...so that the type `<T as Anything<'_#6r, '_#7r>>::AssocType` will meet its required lifetime bounds
 
 note: external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:61:29
@@ -78,7 +78,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:53:1
@@ -103,7 +103,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:65:1
@@ -128,7 +128,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 5
-   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: '_#4r
+   = note: where <T as Anything<'_#2r, '_#3r>>::AssocType: '_#4r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:74:1
@@ -154,7 +154,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
            ]
    = note: late-bound region is '_#3r
    = note: number of external vids: 4
-   = note: where <T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(0, 'b)>>::AssocType: '_#2r
+   = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:83:1
@@ -194,7 +194,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 4
-   = note: where <T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(1, 'b)>>::AssocType: '_#3r
+   = note: where <T as Anything<'_#2r, '_#2r>>::AssocType: '_#3r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:92:1
@@ -219,7 +219,7 @@ LL |     with_signature(cell, t, |cell, t| require(cell, t));
                (),
            ]
    = note: number of external vids: 3
-   = note: where <T as Anything<ReEarlyBound(0, 'a), ReEarlyBound(0, 'a)>>::AssocType: '_#2r
+   = note: where <T as Anything<'_#1r, '_#1r>>::AssocType: '_#2r
 
 note: no external requirements
   --> $DIR/projection-two-region-trait-bound-closure.rs:101:1
diff --git a/tests/ui/parser/issues/issue-108242-semicolon-recovery.rs b/tests/ui/parser/issues/issue-108242-semicolon-recovery.rs
new file mode 100644
index 00000000000..2fc0b29477b
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108242-semicolon-recovery.rs
@@ -0,0 +1,5 @@
+fn foo() {}
+fn main() {
+    foo(;
+    foo(;
+} //~ ERROR mismatched closing delimiter
diff --git a/tests/ui/parser/issues/issue-108242-semicolon-recovery.stderr b/tests/ui/parser/issues/issue-108242-semicolon-recovery.stderr
new file mode 100644
index 00000000000..f68d6d5010d
--- /dev/null
+++ b/tests/ui/parser/issues/issue-108242-semicolon-recovery.stderr
@@ -0,0 +1,13 @@
+error: mismatched closing delimiter: `}`
+  --> $DIR/issue-108242-semicolon-recovery.rs:4:8
+   |
+LL | fn main() {
+   |           - closing delimiter possibly meant for this
+LL |     foo(;
+LL |     foo(;
+   |        ^ unclosed delimiter
+LL | }
+   | ^ mismatched closing delimiter
+
+error: aborting due to previous error
+
diff --git a/tests/ui/stability-attribute/auxiliary/const-stability-attribute-implies.rs b/tests/ui/stability-attribute/auxiliary/const-stability-attribute-implies.rs
new file mode 100644
index 00000000000..f78871b5a1d
--- /dev/null
+++ b/tests/ui/stability-attribute/auxiliary/const-stability-attribute-implies.rs
@@ -0,0 +1,12 @@
+#![crate_type = "lib"]
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
+#[rustc_const_stable(feature = "const_foo", since = "1.62.0")]
+pub const fn foo() {}
+
+#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_foo")]
+pub const fn foobar() {}
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
new file mode 100644
index 00000000000..6d6d793c62b
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.rs
@@ -0,0 +1,16 @@
+#![crate_type = "lib"]
+#![feature(staged_api)]
+#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
+#![rustc_const_stable(feature = "stability_attribute_implies", since = "1.0.0")]
+
+// Tests that `implied_by = "const_bar"` results in an error being emitted if `const_bar` does not
+// exist.
+
+#[stable(feature = "stability_attribute_implies", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
+//~^ ERROR feature `const_bar` implying `const_foobar` does not exist
+pub const fn foobar() -> u32 {
+    0
+}
+
+const VAR: u32 = foobar();
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
new file mode 100644
index 00000000000..6d8b01a5495
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-missing.stderr
@@ -0,0 +1,8 @@
+error: feature `const_bar` implying `const_foobar` does not exist
+  --> $DIR/const-stability-attribute-implies-missing.rs:10:1
+   |
+LL | #[rustc_const_unstable(feature = "const_foobar", issue = "1", implied_by = "const_bar")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.rs
new file mode 100644
index 00000000000..47e8d2b3609
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.rs
@@ -0,0 +1,16 @@
+// aux-build:const-stability-attribute-implies.rs
+#![crate_type = "lib"]
+
+// Tests that despite the `const_foobar` feature being implied by now-stable feature `const_foo`,
+// if `const_foobar` isn't allowed in this crate then an error will be emitted.
+
+extern crate const_stability_attribute_implies;
+use const_stability_attribute_implies::{foo, foobar};
+
+pub const fn bar() -> u32 {
+    foo(); // no error - stable
+    foobar(); //~ ERROR `foobar` is not yet stable as a const fn
+    0
+}
+
+pub const VAR: u32 = bar();
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr
new file mode 100644
index 00000000000..8ef5a364ecc
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr
@@ -0,0 +1,10 @@
+error: `foobar` is not yet stable as a const fn
+  --> $DIR/const-stability-attribute-implies-no-feature.rs:12:5
+   |
+LL |     foobar();
+   |     ^^^^^^^^
+   |
+   = help: add `#![feature(const_foobar)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.rs
new file mode 100644
index 00000000000..ffaa171d8a5
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.rs
@@ -0,0 +1,19 @@
+// aux-build:const-stability-attribute-implies.rs
+#![crate_type = "lib"]
+#![deny(stable_features)]
+#![feature(const_foo)]
+//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
+
+// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
+// diagnostic mentioning partial stabilization, and that given the implied unstable feature is
+// unused (there is no `foobar` call), that the compiler suggests removing the flag.
+
+extern crate const_stability_attribute_implies;
+use const_stability_attribute_implies::foo;
+
+pub const fn bar() -> u32 {
+    foo();
+    0
+}
+
+pub const VAR: u32 = bar();
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.stderr
new file mode 100644
index 00000000000..f6a099cd25e
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-using-stable.stderr
@@ -0,0 +1,22 @@
+error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
+  --> $DIR/const-stability-attribute-implies-using-stable.rs:4:12
+   |
+LL | #![feature(const_foo)]
+   |            ^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/const-stability-attribute-implies-using-stable.rs:3:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `const_foobar`
+   |
+LL | #![feature(const_foobar)]
+   |            ~~~~~~~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(const_foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.rs b/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.rs
new file mode 100644
index 00000000000..2061c5c75bd
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.rs
@@ -0,0 +1,21 @@
+// aux-build:const-stability-attribute-implies.rs
+#![crate_type = "lib"]
+#![deny(stable_features)]
+#![feature(const_foo)]
+//~^ ERROR the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
+
+// Tests that the use of `implied_by` in the `#[rustc_const_unstable]` attribute results in a
+// diagnostic mentioning partial stabilization and that given the implied unstable feature is
+// used (there is a `const_foobar` call), that the compiler suggests changing to that feature and
+// doesn't error about its use.
+
+extern crate const_stability_attribute_implies;
+use const_stability_attribute_implies::{foo, foobar};
+
+pub const fn bar() -> u32 {
+    foo();
+    foobar(); // no error!
+    0
+}
+
+pub const VAR: u32 = bar();
diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.stderr
new file mode 100644
index 00000000000..06385667658
--- /dev/null
+++ b/tests/ui/stability-attribute/const-stability-attribute-implies-using-unstable.stderr
@@ -0,0 +1,22 @@
+error: the feature `const_foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `const_foobar`
+  --> $DIR/const-stability-attribute-implies-using-unstable.rs:4:12
+   |
+LL | #![feature(const_foo)]
+   |            ^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/const-stability-attribute-implies-using-unstable.rs:3:9
+   |
+LL | #![deny(stable_features)]
+   |         ^^^^^^^^^^^^^^^
+help: if you are using features which are still unstable, change to using `const_foobar`
+   |
+LL | #![feature(const_foobar)]
+   |            ~~~~~~~~~~~~
+help: if you are using features which are now stable, remove this line
+   |
+LL - #![feature(const_foo)]
+   |
+
+error: aborting due to previous error
+
diff --git a/tests/ui/suggestions/issue-107860.rs b/tests/ui/suggestions/issue-107860.rs
new file mode 100644
index 00000000000..a6449cd44d0
--- /dev/null
+++ b/tests/ui/suggestions/issue-107860.rs
@@ -0,0 +1,6 @@
+// edition: 2021
+
+async fn str<T>(T: &str) -> &str { &str }
+//~^ ERROR mismatched types
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-107860.stderr b/tests/ui/suggestions/issue-107860.stderr
new file mode 100644
index 00000000000..92e3cf8c43b
--- /dev/null
+++ b/tests/ui/suggestions/issue-107860.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-107860.rs:3:36
+   |
+LL | async fn str<T>(T: &str) -> &str { &str }
+   |                                    ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<...>}`
+   |
+   = note: expected reference `&str`
+              found reference `&for<'a> fn(&'a str) -> impl Future<Output = &'a str> {str::<_>}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/multiline-multipart-suggestion.rs b/tests/ui/suggestions/multiline-multipart-suggestion.rs
new file mode 100644
index 00000000000..77d0322d05f
--- /dev/null
+++ b/tests/ui/suggestions/multiline-multipart-suggestion.rs
@@ -0,0 +1,19 @@
+// compile-flags: --error-format=human --color=always
+// ignore-windows
+
+fn short(foo_bar: &Vec<&i32>) -> &i32 { //~ ERROR missing lifetime specifier
+    &12
+}
+
+fn long( //~ ERROR missing lifetime specifier
+    foo_bar: &Vec<&i32>,
+    something_very_long_so_that_the_line_will_wrap_around__________: i32,
+) -> &i32 {
+    &12
+}
+
+fn long2( //~ ERROR missing lifetime specifier
+    foo_bar: &Vec<&i32>) -> &i32 {
+    &12
+}
+fn main() {}
diff --git a/tests/ui/suggestions/multiline-multipart-suggestion.stderr b/tests/ui/suggestions/multiline-multipart-suggestion.stderr
new file mode 100644
index 00000000000..045a86b4f54
--- /dev/null
+++ b/tests/ui/suggestions/multiline-multipart-suggestion.stderr
@@ -0,0 +1,46 @@
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiline-multipart-suggestion.rs:4:34
+   |
+LL | fn short(foo_bar: &Vec<&i32>) -> &i32 {
+   |                   ----------     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL | fn short<'a>(foo_bar: &'a Vec<&'a i32>) -> &'a i32 {
+   |         ++++           ++      ++           ++
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiline-multipart-suggestion.rs:11:6
+   |
+LL |     foo_bar: &Vec<&i32>,
+   |              ----------
+LL |     something_very_long_so_that_the_line_will_wrap_around__________: i32,
+LL | ) -> &i32 {
+   |      ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL ~ fn long<'a>(
+LL ~     foo_bar: &'a Vec<&'a i32>,
+LL |     something_very_long_so_that_the_line_will_wrap_around__________: i32,
+LL ~ ) -> &'a i32 {
+   |
+
+error[E0106]: missing lifetime specifier
+  --> $DIR/multiline-multipart-suggestion.rs:16:29
+   |
+LL |     foo_bar: &Vec<&i32>) -> &i32 {
+   |              ----------     ^ expected named lifetime parameter
+   |
+   = help: this function's return type contains a borrowed value, but the signature does not say which one of `foo_bar`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+   |
+LL ~ fn long2<'a>(
+LL ~     foo_bar: &'a Vec<&'a i32>) -> &'a i32 {
+   |
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
diff --git a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs
new file mode 100644
index 00000000000..506cad25f63
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.rs
@@ -0,0 +1,9 @@
+#![feature(non_lifetime_binders)]
+//~^ WARN the feature `non_lifetime_binders` is incomplete
+
+fn foo() where for<T> T: Copy {}
+
+fn main() {
+    foo();
+    //~^ ERROR the trait bound `T: Copy` is not satisfied
+}
diff --git a/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr
new file mode 100644
index 00000000000..07e02d47f27
--- /dev/null
+++ b/tests/ui/traits/non_lifetime_binders/bad-copy-cond.stderr
@@ -0,0 +1,24 @@
+warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/bad-copy-cond.rs:1:12
+   |
+LL | #![feature(non_lifetime_binders)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/bad-copy-cond.rs:7:5
+   |
+LL |     foo();
+   |     ^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `foo`
+  --> $DIR/bad-copy-cond.rs:4:26
+   |
+LL | fn foo() where for<T> T: Copy {}
+   |                          ^^^^ required by this bound in `foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/triagebot.toml b/triagebot.toml
index f7607d522c1..403a7087ee1 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -471,6 +471,11 @@ If this was intentional then you can ignore this comment.
 [mentions."src/tools/x"]
 message = "`src/tools/x` was changed. Bump version of Cargo.toml in `src/tools/x` so tidy will suggest installing the new version."
 
+[mentions."src/bootstrap/defaults/config.compiler.toml"]
+message = "This PR changes src/bootstrap/defaults/config.compiler.toml. If appropriate, please also update `config.codegen.toml` so the defaults are in sync."
+[mentions."src/bootstrap/defaults/config.codegen.toml"]
+message = "This PR changes src/bootstrap/defaults/config.codegen.toml. If appropriate, please also update `config.compiler.toml` so the defaults are in sync."
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"