about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bootstrap.example.toml3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/validate_attr.rs12
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/lib.rs6
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs2
-rw-r--r--compiler/rustc_borrowck/src/prefixes.rs3
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/debuginfo.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs54
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs71
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs53
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs9
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs33
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs53
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/statement.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/debuginfo.rs14
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/cast.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0608.md15
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0719.md14
-rw-r--r--compiler/rustc_expand/src/base.rs17
-rw-r--r--compiler/rustc_expand/src/expand.rs9
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs38
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs9
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs53
-rw-r--r--compiler/rustc_infer/src/infer/canonical/instantiate.rs74
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs18
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs6
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp1
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs45
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs26
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs120
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs24
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs8
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs53
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs14
-rw-r--r--compiler/rustc_middle/src/ty/context.rs47
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs14
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/region.rs36
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs22
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs12
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/expr/as_place.rs3
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs77
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs5
-rw-r--r--compiler/rustc_mir_transform/src/add_subtyping_projections.rs3
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs4
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs71
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs5
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs8
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs2
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs2
-rw-r--r--compiler/rustc_mir_transform/src/patch.rs2
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_place_mention.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs155
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs10
-rw-r--r--compiler/rustc_mir_transform/src/strip_debuginfo.rs17
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs24
-rw-r--r--compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs34
-rw-r--r--compiler/rustc_next_trait_solver/src/canonical/mod.rs12
-rw-r--r--compiler/rustc_next_trait_solver/src/placeholder.rs18
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs5
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs74
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs58
-rw-r--r--compiler/rustc_public/src/mir/body.rs11
-rw-r--r--compiler/rustc_public/src/mir/visit.rs2
-rw-r--r--compiler/rustc_public/src/unstable/convert/internal.rs3
-rw-r--r--compiler/rustc_public/src/unstable/convert/stable/mir.rs2
-rw-r--r--compiler/rustc_public/src/unstable/convert/stable/ty.rs7
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs5
-rw-r--r--compiler/rustc_session/src/session.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs5
-rw-r--r--compiler/rustc_target/src/spec/base/android.rs4
-rw-r--r--compiler/rustc_target/src/spec/base/linux.rs3
-rw-r--r--compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs5
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs13
-rw-r--r--compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs3
-rw-r--r--compiler/rustc_trait_selection/src/regions.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_type_ir/src/binder.rs43
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs23
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs4
-rw-r--r--compiler/rustc_type_ir/src/flags.rs19
-rw-r--r--compiler/rustc_type_ir/src/fold.rs24
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs6
-rw-r--r--compiler/rustc_type_ir/src/lib.rs17
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs4
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs4
-rw-r--r--compiler/rustc_type_ir/src/ty_kind/closure.rs5
-rw-r--r--library/alloc/src/boxed.rs31
-rw-r--r--library/core/src/slice/iter.rs69
-rw-r--r--library/coretests/tests/iter/sources.rs11
-rw-r--r--library/std/src/sys/net/hostname/mod.rs2
-rw-r--r--library/std/src/sys/thread_local/mod.rs2
-rw-r--r--library/std/src/sys/thread_local/native/eager.rs4
-rw-r--r--library/std/src/sys/thread_local/native/lazy.rs4
-rw-r--r--library/std/src/sys/thread_local/native/mod.rs12
-rw-r--r--library/std/src/sys/thread_local/no_threads.rs69
-rw-r--r--library/std/src/sys/thread_local/os.rs155
-rw-r--r--library/std/src/thread/local.rs233
-rw-r--r--library/std/src/thread/mod.rs1
-rw-r--r--library/std/tests/thread.rs2
-rw-r--r--src/bootstrap/defaults/bootstrap.dist.toml2
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs4
-rw-r--r--src/bootstrap/src/core/builder/mod.rs2
-rw-r--r--src/ci/citool/Cargo.toml2
-rw-r--r--src/ci/citool/src/main.rs4
-rw-r--r--src/ci/citool/src/utils.rs18
-rw-r--r--src/ci/citool/tests/test-jobs.yml2
-rw-r--r--src/ci/docker/host-x86_64/pr-check-1/Dockerfile1
-rw-r--r--src/ci/docker/host-x86_64/pr-check-2/Dockerfile2
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile1
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md14
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/lints/levels.md2
-rw-r--r--src/doc/rustc/src/platform-support.md6
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md50
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-unknown-none.md5
-rw-r--r--src/doc/rustc/src/platform-support/arm-linux.md4
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md51
-rw-r--r--src/doc/rustc/src/platform-support/armv7a-none-eabi.md5
-rw-r--r--src/doc/rustc/src/platform-support/armv7r-none-eabi.md7
-rw-r--r--src/doc/rustc/src/platform-support/armv8r-none-eabihf.md7
-rw-r--r--src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md6
-rw-r--r--src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md6
-rw-r--r--src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md6
-rw-r--r--src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md6
-rw-r--r--src/doc/rustc/src/platform-support/unknown-uefi.md8
-rw-r--r--src/etc/lldb_providers.py5
-rw-r--r--src/etc/rust_analyzer_eglot.el8
-rw-r--r--src/etc/rust_analyzer_helix.toml14
-rw-r--r--src/etc/rust_analyzer_settings.json8
-rw-r--r--src/etc/rust_analyzer_zed.json23
-rw-r--r--src/librustdoc/clean/cfg.rs267
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/librustdoc/clean/types.rs264
-rw-r--r--src/librustdoc/formats/cache.rs31
-rw-r--r--src/librustdoc/html/highlight.rs3
-rw-r--r--src/librustdoc/html/highlight/tests.rs14
-rw-r--r--src/librustdoc/html/render/context.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs4
-rw-r--r--src/librustdoc/html/render/search_index.rs78
-rw-r--r--src/librustdoc/html/render/span_map.rs68
-rw-r--r--src/librustdoc/html/sources.rs7
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts22
-rw-r--r--src/librustdoc/html/static/js/search.js121
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs4
-rw-r--r--src/tools/compiletest/src/common.rs6
-rw-r--r--src/tools/compiletest/src/directives.rs318
-rw-r--r--src/tools/compiletest/src/directives/auxiliary.rs35
-rw-r--r--src/tools/compiletest/src/directives/cfg.rs14
-rw-r--r--src/tools/compiletest/src/directives/needs.rs6
-rw-r--r--src/tools/compiletest/src/directives/tests.rs142
-rw-r--r--src/tools/compiletest/src/edition.rs35
-rw-r--r--src/tools/compiletest/src/lib.rs4
-rw-r--r--src/tools/compiletest/src/runtest/debugger.rs27
-rw-r--r--src/tools/compiletest/src/runtest/debuginfo.rs6
-rw-r--r--src/tools/miri/tests/pass/static_align.rs60
-rw-r--r--src/tools/miri/tests/pass/thread_local-panic.rs8
-rw-r--r--src/tools/miri/tests/pass/thread_local-panic.stderr5
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml10
-rw-r--r--src/tools/rust-analyzer/Cargo.lock22
-rw-r--r--src/tools/rust-analyzer/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs231
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/drop.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs167
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs439
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs458
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs57
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs443
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs189
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs196
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs184
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs297
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs155
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs292
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs46
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs40
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs69
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs84
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs132
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs82
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs42
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs10
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs14
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs11
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs57
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs110
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs3
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs44
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs2
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md2
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json6
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json2
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--tests/codegen-llvm/autodiff/abi_handling.rs4
-rw-r--r--tests/codegen-llvm/autodiff/batched.rs2
-rw-r--r--tests/codegen-llvm/autodiff/scalar.rs2
-rw-r--r--tests/codegen-llvm/autodiff/sret.rs2
-rw-r--r--tests/codegen-llvm/autodiff/void_ret.rs41
-rw-r--r--tests/codegen-llvm/debug-fndef-size.rs4
-rw-r--r--tests/codegen-llvm/debuginfo-dse.rs362
-rw-r--r--tests/crashes/120016.rs14
-rw-r--r--tests/debuginfo/opt/dead_refs.rs50
-rw-r--r--tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir18
-rw-r--r--tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff4
-rw-r--r--tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff30
-rw-r--r--tests/mir-opt/dead-store-elimination/ref.rs31
-rw-r--r--tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff25
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff26
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff30
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff29
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff37
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff29
-rw-r--r--tests/mir-opt/debuginfo/simplifycfg.rs207
-rw-r--r--tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_closure_inherent.rs19
-rw-r--r--tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent.rs17
-rw-r--r--tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent_ambiguous.rs25
-rw-r--r--tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff12
-rw-r--r--tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff12
-rw-r--r--tests/mir-opt/inline/forced_inherent_async.rs18
-rw-r--r--tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff21
-rw-r--r--tests/mir-opt/inline/forced_inherent_dead_code.rs21
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff2
-rw-r--r--tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff2
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff15
-rw-r--r--tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff15
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff1
-rw-r--r--tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff1
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff12
-rw-r--r--tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff12
-rw-r--r--tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir4
-rw-r--r--tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir46
-rw-r--r--tests/mir-opt/pre-codegen/clone_as_copy.rs16
-rw-r--r--tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir13
-rw-r--r--tests/mir-opt/pre-codegen/dead_on_invalid_place.rs27
-rw-r--r--tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir44
-rw-r--r--tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir94
-rw-r--r--tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir84
-rw-r--r--tests/mir-opt/pre-codegen/loops.rs1
-rw-r--r--tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir306
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir205
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir211
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir219
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir177
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir177
-rw-r--r--tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/run-make/panic-abort-eh_frame/rmake.rs11
-rw-r--r--tests/rustdoc-gui/search-result-color.goml45
-rw-r--r--tests/rustdoc-gui/search-tab.goml2
-rw-r--r--tests/rustdoc-gui/sidebar.goml2
-rw-r--r--tests/rustdoc-js-std/asrawfd.js4
-rw-r--r--tests/rustdoc-js-std/quoted.js18
-rw-r--r--tests/rustdoc-js-std/trait-unbox.js (renamed from tests/rustdoc-js-std/bufread-fill-buf.js)6
-rw-r--r--tests/rustdoc-js/trait-methods.js20
-rw-r--r--tests/rustdoc-js/trait-methods.rs18
-rw-r--r--tests/ui-fulldeps/mod_dir_path_canonicalized.rs1
-rw-r--r--tests/ui/associated-type-bounds/duplicate-bound-err.rs114
-rw-r--r--tests/ui/associated-type-bounds/duplicate-bound-err.stderr268
-rw-r--r--tests/ui/associated-type-bounds/duplicate-bound.rs240
-rw-r--r--tests/ui/associated-type-bounds/duplicate.rs278
-rw-r--r--tests/ui/associated-type-bounds/duplicate.stderr751
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding-2.stderr2
-rw-r--r--tests/ui/associated-types/associated-types-overridden-binding.stderr2
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr (renamed from tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr)6
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr21
-rw-r--r--tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs4
-rw-r--r--tests/ui/attributes/unsafe/double-unsafe-attributes.rs2
-rw-r--r--tests/ui/attributes/unsafe/double-unsafe-attributes.stderr6
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs2
-rw-r--r--tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr6
-rw-r--r--tests/ui/closures/impl-closure-147146.rs7
-rw-r--r--tests/ui/closures/impl-closure-147146.stderr15
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs5
-rw-r--r--tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr2
-rw-r--r--tests/ui/compiletest-self-test/compile-flags-incremental.rs17
-rw-r--r--tests/ui/coroutine/handle_opaques_before_coroutines.rs15
-rw-r--r--tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr4
-rw-r--r--tests/ui/error-codes/E0719.rs5
-rw-r--r--tests/ui/error-codes/E0719.stderr34
-rw-r--r--tests/ui/errors/auxiliary/remapped_dep.rs2
-rw-r--r--tests/ui/errors/remap-path-prefix-reverse.local-self.stderr2
-rw-r--r--tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr2
-rw-r--r--tests/ui/errors/remap-path-prefix-reverse.rs1
-rw-r--r--tests/ui/errors/remap-path-prefix.rs2
-rw-r--r--tests/ui/extern/extern-types-field-offset.rs5
-rw-r--r--tests/ui/feature-gates/feature-gate-never_patterns.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-static_align-thread_local.rs11
-rw-r--r--tests/ui/force-inlining/inherent.rs21
-rw-r--r--tests/ui/force-inlining/inherent.stderr13
-rw-r--r--tests/ui/force-inlining/invalid.rs1
-rw-r--r--tests/ui/force-inlining/invalid.stderr38
-rw-r--r--tests/ui/higher-ranked/trait-bounds/issue-59311.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr2
-rw-r--r--tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs16
-rw-r--r--tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs8
-rw-r--r--tests/ui/imports/auxiliary/same-res-ambigious-extern.rs11
-rw-r--r--tests/ui/imports/same-res-ambigious.fail.stderr20
-rw-r--r--tests/ui/imports/same-res-ambigious.nightly-fail.stderr20
-rw-r--r--tests/ui/imports/same-res-ambigious.rs11
-rw-r--r--tests/ui/indexing/ambiguity-after-deref-step.rs9
-rw-r--r--tests/ui/indexing/ambiguity-after-deref-step.stderr17
-rw-r--r--tests/ui/indexing/index_message.stderr4
-rw-r--r--tests/ui/issues/issue-27842.stderr12
-rw-r--r--tests/ui/lifetimes/re-empty-in-error.stderr2
-rw-r--r--tests/ui/macros/macro-local-data-key-priv.stderr2
-rw-r--r--tests/ui/macros/macro-rules-attr-error.rs19
-rw-r--r--tests/ui/macros/macro-rules-attr-error.stderr14
-rw-r--r--tests/ui/methods/overflow-if-subtyping.rs30
-rw-r--r--tests/ui/nll/user-annotations/dump-fn-method.rs4
-rw-r--r--tests/ui/nll/user-annotations/dump-fn-method.stderr4
-rw-r--r--tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs57
-rw-r--r--tests/ui/parser/issues/issue-87086-colon-path-sep.rs3
-rw-r--r--tests/ui/parser/issues/issue-87086-colon-path-sep.stderr20
-rw-r--r--tests/ui/parser/macro/bad-macro-definition.rs3
-rw-r--r--tests/ui/parser/macro/bad-macro-definition.stderr8
-rw-r--r--tests/ui/parser/macro/macro-attr-bad.rs6
-rw-r--r--tests/ui/parser/macro/macro-attr-bad.stderr26
-rw-r--r--tests/ui/parser/macro/macro-derive-bad.rs3
-rw-r--r--tests/ui/parser/macro/macro-derive-bad.stderr8
-rw-r--r--tests/ui/parser/match-arm-without-body.rs4
-rw-r--r--tests/ui/parser/match-arm-without-body.stderr11
-rw-r--r--tests/ui/parser/type-ascription-in-pattern.rs17
-rw-r--r--tests/ui/parser/type-ascription-in-pattern.stderr80
-rw-r--r--tests/ui/proc-macro/expand-expr.rs2
-rw-r--r--tests/ui/proc-macro/pretty-print-hack-show.rs1
-rw-r--r--tests/ui/span/suggestion-non-ascii.stderr4
-rw-r--r--tests/ui/static/static-align.rs84
-rw-r--r--tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed18
-rw-r--r--tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs18
-rw-r--r--tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr18
-rw-r--r--tests/ui/thread-local/long-docs.rs266
-rw-r--r--tests/ui/thread-local/no-unstable.rs17
-rw-r--r--tests/ui/thread-local/no-unstable.stderr57
-rw-r--r--tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs60
-rw-r--r--tests/ui/type/pattern_types/const_generics.rs3
-rw-r--r--tests/ui/type/pattern_types/transmute.current.stderr (renamed from tests/ui/type/pattern_types/transmute.stderr)4
-rw-r--r--tests/ui/type/pattern_types/transmute.next.stderr21
-rw-r--r--tests/ui/type/pattern_types/transmute.rs3
-rw-r--r--tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr2
-rw-r--r--triagebot.toml4
478 files changed, 11219 insertions, 4808 deletions
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 0a39c6d8f24..f623a3db002 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -476,9 +476,6 @@
 # when the stage 0 compiler is actually built from in-tree sources.
 #build.compiletest-allow-stage0 = false
 
-# Whether to use the precompiled stage0 libtest with compiletest.
-#build.compiletest-use-stage0-libtest = true
-
 # Default value for the `--extra-checks` flag of tidy.
 #
 # See `./x test tidy --help` for details.
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index a73430c9d00..a10ad27fcc6 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -72,7 +72,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
     const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
+        Allow(Target::Fn),
+        Allow(Target::Method(MethodKind::Inherent)),
+    ]);
+
     const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs
index 7a7624893bd..927417f89f8 100644
--- a/compiler/rustc_attr_parsing/src/validate_attr.rs
+++ b/compiler/rustc_attr_parsing/src/validate_attr.rs
@@ -207,10 +207,9 @@ pub fn check_attribute_safety(
             }
         }
 
-        // - Normal builtin attribute, or any non-builtin attribute
-        // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
-        //   not permitted on non-builtin attributes or normal builtin attributes
-        (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
+        // - Normal builtin attribute
+        // - Writing `#[unsafe(..)]` is not permitted on normal builtin attributes
+        (Some(AttributeSafety::Normal), Safety::Unsafe(unsafe_span)) => {
             psess.dcx().emit_err(errors::InvalidAttrUnsafe {
                 span: unsafe_span,
                 name: attr_item.path.clone(),
@@ -224,9 +223,8 @@ pub fn check_attribute_safety(
         }
 
         // - Non-builtin attribute
-        // - No explicit `#[unsafe(..)]` written.
-        (None, Safety::Default) => {
-            // OK
+        (None, Safety::Unsafe(_) | Safety::Default) => {
+            // OK (not checked here)
         }
 
         (
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index efb622e2155..fa1be4cec1e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3968,7 +3968,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                         }
                         ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::Subslice { .. }
-                        | ProjectionElem::Subtype(_)
                         | ProjectionElem::Index(_)
                         | ProjectionElem::UnwrapUnsafeBinder(_) => kind,
                     },
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 5642cdf87fd..e13c1c712d8 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -402,7 +402,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                 ProjectionElem::Downcast(..) if opt.including_downcast => return None,
                 ProjectionElem::Downcast(..) => (),
                 ProjectionElem::OpaqueCast(..) => (),
-                ProjectionElem::Subtype(..) => (),
                 ProjectionElem::UnwrapUnsafeBinder(_) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
@@ -484,9 +483,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
                 }
                 ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
-                ProjectionElem::Subtype(ty)
-                | ProjectionElem::OpaqueCast(ty)
-                | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
+                ProjectionElem::OpaqueCast(ty) | ProjectionElem::UnwrapUnsafeBinder(ty) => {
+                    PlaceTy::from_ty(*ty)
+                }
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 6d69040c711..727cf19cd8b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -192,7 +192,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                     [
                         ..,
                         ProjectionElem::Index(_)
-                        | ProjectionElem::Subtype(_)
                         | ProjectionElem::ConstantIndex { .. }
                         | ProjectionElem::OpaqueCast { .. }
                         | ProjectionElem::Subslice { .. }
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 268cb47fd12..a85dcf64d8d 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -278,7 +278,7 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
         mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
     ) -> Ty<'tcx> {
         fold_regions(tcx, self.inner, |r, depth| match r.kind() {
-            ty::ReBound(debruijn, br) => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) => {
                 debug_assert_eq!(debruijn, depth);
                 map(ty::RegionVid::from_usize(br.var.index()))
             }
@@ -1989,10 +1989,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                 },
                 // `OpaqueCast`: only transmutes the type, so no moves there.
                 // `Downcast`  : only changes information about a `Place` without moving.
-                // `Subtype`   : only transmutes the type, so no moves.
                 // So it's safe to skip these.
                 ProjectionElem::OpaqueCast(_)
-                | ProjectionElem::Subtype(_)
                 | ProjectionElem::Downcast(_, _)
                 | ProjectionElem::UnwrapUnsafeBinder(_) => (),
             }
@@ -2218,7 +2216,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
         for (place_base, elem) in place.iter_projections().rev() {
             match elem {
                 ProjectionElem::Index(_/*operand*/) |
-                ProjectionElem::Subtype(_) |
                 ProjectionElem::OpaqueCast(_) |
                 ProjectionElem::ConstantIndex { .. } |
                 // assigning to P[i] requires P to be valid.
@@ -2610,7 +2607,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
                     | ProjectionElem::Index(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
-                    | ProjectionElem::Subtype(..)
                     | ProjectionElem::OpaqueCast { .. }
                     | ProjectionElem::Downcast(..)
                     | ProjectionElem::UnwrapUnsafeBinder(_) => {
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index cf3e82426e8..60676ac6b86 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -249,7 +249,6 @@ fn place_components_conflict<'tcx>(
                 | (ProjectionElem::ConstantIndex { .. }, _, _)
                 | (ProjectionElem::Subslice { .. }, _, _)
                 | (ProjectionElem::OpaqueCast { .. }, _, _)
-                | (ProjectionElem::Subtype(_), _, _)
                 | (ProjectionElem::Downcast { .. }, _, _)
                 | (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
                     // Recursive case. This can still be disjoint on a
@@ -510,7 +509,6 @@ fn place_projection_conflict<'tcx>(
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::OpaqueCast { .. }
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Downcast(..),
diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs
index 83cca38a5c0..9e51264d8ed 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -77,9 +77,6 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
                         | ProjectionElem::Index(_) => {
                             cursor = cursor_base;
                         }
-                        ProjectionElem::Subtype(..) => {
-                            panic!("Subtype projection is not allowed before borrow check")
-                        }
                         ProjectionElem::Deref => {
                             match self.kind {
                                 PrefixSet::Shallow => {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 606d3d95d9e..781fb5ba113 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1558,6 +1558,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             ),
                         }
                     }
+                    CastKind::Subtype => {
+                        bug!("CastKind::Subtype shouldn't exist in borrowck")
+                    }
                 }
             }
 
@@ -1882,9 +1885,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                 )
                 .unwrap();
             }
-            ProjectionElem::Subtype(_) => {
-                bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
-            }
         }
     }
 }
@@ -2412,9 +2412,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 | ProjectionElem::UnwrapUnsafeBinder(_) => {
                     // other field access
                 }
-                ProjectionElem::Subtype(_) => {
-                    bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
-                }
             }
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 2cc5b82ddd3..ebf2ccf74de 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -789,7 +789,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt:
                     let operand = codegen_operand(fx, operand);
                     crate::unsize::coerce_unsized_into(fx, operand, lval);
                 }
-                Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
+                Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, ref operand, _to_ty) => {
                     let operand = codegen_operand(fx, operand);
                     lval.write_cvalue_transmute(fx, operand);
                 }
@@ -996,7 +996,7 @@ pub(crate) fn codegen_place<'tcx>(
                 cplace = cplace.place_deref(fx);
             }
             PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
-            PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
+            PlaceElem::UnwrapUnsafeBinder(ty) => {
                 cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
             }
             PlaceElem::Field(field, _ty) => {
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 04e10cf1708..db9b80c0f6a 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -660,7 +660,7 @@ impl<'tcx> CPlace<'tcx> {
         }
     }
 
-    /// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before
+    /// Used for `ProjectionElem::UnwrapUnsafeBinder`, `ty` has to be monomorphized before
     /// passed on.
     pub(crate) fn place_transmute_type(
         self,
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index 4c8585192a1..0f015cc23f5 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -29,13 +29,24 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
         _variable_alloca: Self::Value,
         _direct_offset: Size,
         _indirect_offsets: &[Size],
-        _fragment: Option<Range<Size>>,
+        _fragment: &Option<Range<Size>>,
     ) {
         // FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
         #[cfg(feature = "master")]
         _variable_alloca.set_location(_dbg_loc);
     }
 
+    fn dbg_var_value(
+        &mut self,
+        _dbg_var: Self::DIVariable,
+        _dbg_loc: Self::DILocation,
+        _value: Self::Value,
+        _direct_offset: Size,
+        _indirect_offsets: &[Size],
+        _fragment: &Option<Range<Size>>,
+    ) {
+    }
+
     fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
         // TODO(antoyo): insert reference to gdb debug scripts section global.
     }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index cc09fa5b69b..93b1cf272ab 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -538,9 +538,7 @@ pub(crate) fn inline_asm_call<'ll>(
             bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)),
         )
     }));
-    let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) };
-    let md = bx.get_metadata_value(md);
-    llvm::LLVMSetMetadata(call, kind, md);
+    bx.cx.set_metadata_node(call, kind, &srcloc);
 
     Some(call)
 }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5271d0b4bb8..e7cb18ab22d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -1,12 +1,12 @@
 use std::borrow::{Borrow, Cow};
+use std::iter;
 use std::ops::Deref;
-use std::{iter, ptr};
 
 use rustc_ast::expand::typetree::FncTree;
 pub(crate) mod autodiff;
 pub(crate) mod gpu_offload;
 
-use libc::{c_char, c_uint, size_t};
+use libc::{c_char, c_uint};
 use rustc_abi as abi;
 use rustc_abi::{Align, Size, WrappingRange};
 use rustc_codegen_ssa::MemFlags;
@@ -396,10 +396,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             md.push(weight(is_cold));
         }
 
-        unsafe {
-            let md_node = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len() as size_t);
-            self.cx.set_metadata(switch, llvm::MD_prof, md_node);
-        }
+        self.cx.set_metadata_node(switch, llvm::MD_prof, &md);
     }
 
     fn invoke(
@@ -801,22 +798,16 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
             return;
         }
 
-        unsafe {
-            let llty = self.cx.val_ty(load);
-            let md = [
-                llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
-                llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
-            ];
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
-            self.set_metadata(load, llvm::MD_range, md);
-        }
+        let llty = self.cx.val_ty(load);
+        let md = [
+            llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.start)),
+            llvm::LLVMValueAsMetadata(self.cx.const_uint_big(llty, range.end.wrapping_add(1))),
+        ];
+        self.set_metadata_node(load, llvm::MD_range, &md);
     }
 
     fn nonnull_metadata(&mut self, load: &'ll Value) {
-        unsafe {
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
-            self.set_metadata(load, llvm::MD_nonnull, md);
-        }
+        self.set_metadata_node(load, llvm::MD_nonnull, &[]);
     }
 
     fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
@@ -865,8 +856,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                     //
                     // [1]: https://llvm.org/docs/LangRef.html#store-instruction
                     let one = llvm::LLVMValueAsMetadata(self.cx.const_i32(1));
-                    let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, &one, 1);
-                    self.set_metadata(store, llvm::MD_nontemporal, md);
+                    self.set_metadata_node(store, llvm::MD_nontemporal, &[one]);
                 }
             }
             store
@@ -1381,10 +1371,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn set_invariant_load(&mut self, load: &'ll Value) {
-        unsafe {
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
-            self.set_metadata(load, llvm::MD_invariant_load, md);
-        }
+        self.set_metadata_node(load, llvm::MD_invariant_load, &[]);
     }
 
     fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
@@ -1528,25 +1515,16 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
 }
 impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
     fn align_metadata(&mut self, load: &'ll Value, align: Align) {
-        unsafe {
-            let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, md.as_ptr(), md.len());
-            self.set_metadata(load, llvm::MD_align, md);
-        }
+        let md = [llvm::LLVMValueAsMetadata(self.cx.const_u64(align.bytes()))];
+        self.set_metadata_node(load, llvm::MD_align, &md);
     }
 
     fn noundef_metadata(&mut self, load: &'ll Value) {
-        unsafe {
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
-            self.set_metadata(load, llvm::MD_noundef, md);
-        }
+        self.set_metadata_node(load, llvm::MD_noundef, &[]);
     }
 
     pub(crate) fn set_unpredictable(&mut self, inst: &'ll Value) {
-        unsafe {
-            let md = llvm::LLVMMDNodeInContext2(self.cx.llcx, ptr::null(), 0);
-            self.set_metadata(inst, llvm::MD_unpredictable, md);
-        }
+        self.set_metadata_node(inst, llvm::MD_unpredictable, &[]);
     }
 }
 impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index c3485f56391..4a749642265 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
 
     let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
 
-    builder.store_to_place(call, dest.val);
+    let fn_ret_ty = builder.cx.val_ty(call);
+    if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) {
+        // If we return void or an empty struct, then our caller (due to how we generated it)
+        // does not expect a return value. As such, we have no pointer (or place) into which
+        // we could store our value, and would store into an undef, which would cause UB.
+        // As such, we just ignore the return value in those cases.
+        builder.store_to_place(call, dest.val);
+    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 40375ef6510..b4ca85a26c8 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -494,16 +494,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                 let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
                 let alloc = self.create_metadata(bytes);
                 let data = [section, alloc];
-                let meta =
-                    unsafe { llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()) };
-                let val = self.get_metadata_value(meta);
-                unsafe {
-                    llvm::LLVMAddNamedMetadataOperand(
-                        self.llmod,
-                        c"wasm.custom_sections".as_ptr(),
-                        val,
-                    )
-                };
+                self.module_add_named_metadata_node(self.llmod(), c"wasm.custom_sections", &data);
             }
         } else {
             base::set_link_section(g, attrs);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index b1da6f7c740..922575dd63c 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -34,7 +34,7 @@ use smallvec::SmallVec;
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
-use crate::llvm::{Metadata, MetadataKindId};
+use crate::llvm::{Metadata, MetadataKindId, Module};
 use crate::type_::Type;
 use crate::value::Value;
 use crate::{attributes, common, coverageinfo, debuginfo, llvm, llvm_util};
@@ -495,14 +495,7 @@ pub(crate) unsafe fn create_module<'ll>(
         format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"));
 
     let name_metadata = cx.create_metadata(rustc_producer.as_bytes());
-
-    unsafe {
-        llvm::LLVMAddNamedMetadataOperand(
-            llmod,
-            c"llvm.ident".as_ptr(),
-            &cx.get_metadata_value(llvm::LLVMMDNodeInContext2(llcx, &name_metadata, 1)),
-        );
-    }
+    cx.module_add_named_metadata_node(llmod, c"llvm.ident", &[name_metadata]);
 
     // Emit RISC-V specific target-abi metadata
     // to workaround lld as the LTO plugin not
@@ -1002,6 +995,11 @@ impl CodegenCx<'_, '_> {
 }
 
 impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
+    /// Wrapper for `LLVMMDNodeInContext2`, i.e. `llvm::MDNode::get`.
+    pub(crate) fn md_node_in_context(&self, md_list: &[&'ll Metadata]) -> &'ll Metadata {
+        unsafe { llvm::LLVMMDNodeInContext2(self.llcx(), md_list.as_ptr(), md_list.len()) }
+    }
+
     /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`.
     pub(crate) fn set_metadata<'a>(
         &self,
@@ -1012,6 +1010,61 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         let node = self.get_metadata_value(md);
         llvm::LLVMSetMetadata(val, kind_id, node);
     }
+
+    /// Helper method for the sequence of calls:
+    /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
+    /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
+    /// - `LLVMSetMetadata` (to set that node as metadata of `kind_id` for `instruction`)
+    pub(crate) fn set_metadata_node(
+        &self,
+        instruction: &'ll Value,
+        kind_id: MetadataKindId,
+        md_list: &[&'ll Metadata],
+    ) {
+        let md = self.md_node_in_context(md_list);
+        self.set_metadata(instruction, kind_id, md);
+    }
+
+    /// Helper method for the sequence of calls:
+    /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
+    /// - `LLVMMetadataAsValue` (to adapt that node to an `llvm::Value`)
+    /// - `LLVMAddNamedMetadataOperand` (to set that node as metadata of `kind_name` for `module`)
+    pub(crate) fn module_add_named_metadata_node(
+        &self,
+        module: &'ll Module,
+        kind_name: &CStr,
+        md_list: &[&'ll Metadata],
+    ) {
+        let md = self.md_node_in_context(md_list);
+        let md_as_val = self.get_metadata_value(md);
+        unsafe { llvm::LLVMAddNamedMetadataOperand(module, kind_name.as_ptr(), md_as_val) };
+    }
+
+    /// Helper method for the sequence of calls:
+    /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
+    /// - `LLVMRustGlobalAddMetadata` (to set that node as metadata of `kind_id` for `global`)
+    pub(crate) fn global_add_metadata_node(
+        &self,
+        global: &'ll Value,
+        kind_id: MetadataKindId,
+        md_list: &[&'ll Metadata],
+    ) {
+        let md = self.md_node_in_context(md_list);
+        unsafe { llvm::LLVMRustGlobalAddMetadata(global, kind_id, md) };
+    }
+
+    /// Helper method for the sequence of calls:
+    /// - `LLVMMDNodeInContext2` (to create an `llvm::MDNode` from a list of metadata)
+    /// - `LLVMGlobalSetMetadata` (to set that node as metadata of `kind_id` for `global`)
+    pub(crate) fn global_set_metadata_node(
+        &self,
+        global: &'ll Value,
+        kind_id: MetadataKindId,
+        md_list: &[&'ll Metadata],
+    ) {
+        let md = self.md_node_in_context(md_list);
+        unsafe { llvm::LLVMGlobalSetMetadata(global, kind_id, md) };
+    }
 }
 
 impl HasDataLayout for CodegenCx<'_, '_> {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
index 40842915222..52d04625749 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
@@ -35,3 +35,6 @@ declare_constant!(DW_OP_plus_uconst: u64);
 /// Double-checked by a static assertion in `RustWrapper.cpp`.
 #[allow(non_upper_case_globals)]
 pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;
+// It describes the actual value of a source variable which might not exist in registers or in memory.
+#[allow(non_upper_case_globals)]
+pub(crate) const DW_OP_stack_value: u64 = 0x9f;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index bc20c759413..2f9e7cae54f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1607,17 +1607,11 @@ pub(crate) fn apply_vcall_visibility_metadata<'ll, 'tcx>(
     let trait_ref_typeid = typeid_for_trait_ref(cx.tcx, trait_ref);
     let typeid = cx.create_metadata(trait_ref_typeid.as_bytes());
 
-    unsafe {
-        let v = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
-        llvm::LLVMRustGlobalAddMetadata(
-            vtable,
-            llvm::MD_type,
-            llvm::LLVMMDNodeInContext2(cx.llcx, v.as_ptr(), v.len()),
-        );
-        let vcall_visibility = llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64));
-        let vcall_visibility_metadata = llvm::LLVMMDNodeInContext2(cx.llcx, &vcall_visibility, 1);
-        llvm::LLVMGlobalSetMetadata(vtable, llvm::MD_vcall_visibility, vcall_visibility_metadata);
-    }
+    let type_ = [llvm::LLVMValueAsMetadata(cx.const_usize(0)), typeid];
+    cx.global_add_metadata_node(vtable, llvm::MD_type, &type_);
+
+    let vcall_visibility = [llvm::LLVMValueAsMetadata(cx.const_u64(vcall_visibility as u64))];
+    cx.global_set_metadata_node(vtable, llvm::MD_vcall_visibility, &vcall_visibility);
 }
 
 /// Creates debug information for the given vtable, which is for the
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index af64e4ebed0..c6ad1c2e18e 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -156,7 +156,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
         variable_alloca: Self::Value,
         direct_offset: Size,
         indirect_offsets: &[Size],
-        fragment: Option<Range<Size>>,
+        fragment: &Option<Range<Size>>,
     ) {
         use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
 
@@ -187,7 +187,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
             llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
         };
         unsafe {
-            // FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
             llvm::LLVMDIBuilderInsertDeclareRecordAtEnd(
                 di_builder,
                 variable_alloca,
@@ -199,6 +198,56 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
         };
     }
 
+    fn dbg_var_value(
+        &mut self,
+        dbg_var: &'ll DIVariable,
+        dbg_loc: &'ll DILocation,
+        value: Self::Value,
+        direct_offset: Size,
+        indirect_offsets: &[Size],
+        fragment: &Option<Range<Size>>,
+    ) {
+        use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
+
+        // Convert the direct and indirect offsets and fragment byte range to address ops.
+        let mut addr_ops = SmallVec::<[u64; 8]>::new();
+
+        if direct_offset.bytes() > 0 {
+            addr_ops.push(DW_OP_plus_uconst);
+            addr_ops.push(direct_offset.bytes() as u64);
+            addr_ops.push(DW_OP_stack_value);
+        }
+        for &offset in indirect_offsets {
+            addr_ops.push(DW_OP_deref);
+            if offset.bytes() > 0 {
+                addr_ops.push(DW_OP_plus_uconst);
+                addr_ops.push(offset.bytes() as u64);
+            }
+        }
+        if let Some(fragment) = fragment {
+            // `DW_OP_LLVM_fragment` takes as arguments the fragment's
+            // offset and size, both of them in bits.
+            addr_ops.push(DW_OP_LLVM_fragment);
+            addr_ops.push(fragment.start.bits() as u64);
+            addr_ops.push((fragment.end - fragment.start).bits() as u64);
+        }
+
+        let di_builder = DIB(self.cx());
+        let addr_expr = unsafe {
+            llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len())
+        };
+        unsafe {
+            llvm::LLVMDIBuilderInsertDbgValueRecordAtEnd(
+                di_builder,
+                value,
+                dbg_var,
+                addr_expr,
+                dbg_loc,
+                self.llbb(),
+            );
+        }
+    }
+
     fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
         unsafe {
             llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e9f92267a7d..7fbba029407 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1991,6 +1991,15 @@ unsafe extern "C" {
         Block: &'ll BasicBlock,
     ) -> &'ll DbgRecord;
 
+    pub(crate) fn LLVMDIBuilderInsertDbgValueRecordAtEnd<'ll>(
+        Builder: &DIBuilder<'ll>,
+        Val: &'ll Value,
+        VarInfo: &'ll Metadata,
+        Expr: &'ll Metadata,
+        DebugLoc: &'ll Metadata,
+        Block: &'ll BasicBlock,
+    ) -> &'ll DbgRecord;
+
     pub(crate) fn LLVMDIBuilderCreateAutoVariable<'ll>(
         Builder: &DIBuilder<'ll>,
         Scope: &'ll Metadata,
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 5b97898a4b8..1e5cf8374e3 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -302,26 +302,14 @@ impl<'ll, 'tcx> LayoutTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn add_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
         let typeid_metadata = self.create_metadata(typeid);
-        unsafe {
-            let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
-            llvm::LLVMRustGlobalAddMetadata(
-                function,
-                llvm::MD_type,
-                llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
-            )
-        }
+        let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
+        self.global_add_metadata_node(function, llvm::MD_type, &v);
     }
 
     fn set_type_metadata(&self, function: &'ll Value, typeid: &[u8]) {
         let typeid_metadata = self.create_metadata(typeid);
-        unsafe {
-            let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
-            llvm::LLVMGlobalSetMetadata(
-                function,
-                llvm::MD_type,
-                llvm::LLVMMDNodeInContext2(self.llcx, v.as_ptr(), v.len()),
-            )
-        }
+        let v = [llvm::LLVMValueAsMetadata(self.const_usize(0)), typeid_metadata];
+        self.global_set_metadata_node(function, llvm::MD_type, &v);
     }
 
     fn typeid_metadata(&self, typeid: &[u8]) -> Option<&'ll Metadata> {
@@ -329,32 +317,12 @@ impl<'ll, 'tcx> TypeMembershipCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
-        let kcfi_type_metadata = self.const_u32(kcfi_typeid);
-        unsafe {
-            llvm::LLVMRustGlobalAddMetadata(
-                function,
-                llvm::MD_kcfi_type,
-                llvm::LLVMMDNodeInContext2(
-                    self.llcx,
-                    &llvm::LLVMValueAsMetadata(kcfi_type_metadata),
-                    1,
-                ),
-            )
-        }
+        let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
+        self.global_add_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
     }
 
     fn set_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
-        let kcfi_type_metadata = self.const_u32(kcfi_typeid);
-        unsafe {
-            llvm::LLVMGlobalSetMetadata(
-                function,
-                llvm::MD_kcfi_type,
-                llvm::LLVMMDNodeInContext2(
-                    self.llcx,
-                    &llvm::LLVMValueAsMetadata(kcfi_type_metadata),
-                    1,
-                ),
-            )
-        }
+        let kcfi_type_metadata = [llvm::LLVMValueAsMetadata(self.const_u32(kcfi_typeid))];
+        self.global_set_metadata_node(function, llvm::MD_kcfi_type, &kcfi_type_metadata);
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index e644a43f883..ac123143738 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -17,7 +17,6 @@ use rustc_middle::middle::exported_symbols::{
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
-use rustc_span::sym;
 use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
 use tracing::{debug, warn};
 
@@ -1324,37 +1323,7 @@ struct WasmLd<'a> {
 
 impl<'a> WasmLd<'a> {
     fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> {
-        // If the atomics feature is enabled for wasm then we need a whole bunch
-        // of flags:
-        //
-        // * `--shared-memory` - the link won't even succeed without this, flags
-        //   the one linear memory as `shared`
-        //
-        // * `--max-memory=1G` - when specifying a shared memory this must also
-        //   be specified. We conservatively choose 1GB but users should be able
-        //   to override this with `-C link-arg`.
-        //
-        // * `--import-memory` - it doesn't make much sense for memory to be
-        //   exported in a threaded module because typically you're
-        //   sharing memory and instantiating the module multiple times. As a
-        //   result if it were exported then we'd just have no sharing.
-        //
-        // On wasm32-unknown-unknown, we also export symbols for glue code to use:
-        //    * `--export=*tls*` - when `#[thread_local]` symbols are used these
-        //      symbols are how the TLS segments are initialized and configured.
-        let mut wasm_ld = WasmLd { cmd, sess };
-        if sess.target_features.contains(&sym::atomics) {
-            wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]);
-            if sess.target.os == "unknown" || sess.target.os == "none" {
-                wasm_ld.link_args(&[
-                    "--export=__wasm_init_tls",
-                    "--export=__tls_size",
-                    "--export=__tls_align",
-                    "--export=__tls_base",
-                ]);
-            }
-        }
-        wasm_ld
+        WasmLd { cmd, sess }
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index c2c023af090..0a37a904193 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -150,10 +150,6 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
                     {
                         layout.for_variant(self.fx.cx, vidx)
                     }
-                    mir::PlaceElem::Subtype(subtype_ty) => {
-                        let subtype_ty = self.fx.monomorphize(subtype_ty);
-                        self.fx.cx.layout_of(subtype_ty)
-                    }
                     _ => {
                         self.locals[place_ref.local] = LocalKind::Memory;
                         return;
@@ -264,6 +260,10 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer
             PlaceContext::MutatingUse(MutatingUseContext::Yield) => bug!(),
         }
     }
+
+    fn visit_statement_debuginfo(&mut self, _: &mir::StmtDebugInfo<'tcx>, _: Location) {
+        // Debuginfo does not generate actual code.
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b2dc4fe32b0..e371f1a7623 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1320,6 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             for statement in &data.statements {
                 self.codegen_statement(bx, statement);
             }
+            self.codegen_stmt_debuginfos(bx, &data.after_last_stmt_debuginfos);
 
             let merging_succ = self.codegen_terminator(bx, bb, data.terminator());
             if let MergingSucc::False = merging_succ {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index b8f635ab781..0c9acf087f9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -253,6 +253,53 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         spill_slot
     }
 
+    // Indicates that local is set to a new value. The `layout` and `projection` are used to
+    // calculate the offset.
+    pub(crate) fn debug_new_val_to_local(
+        &self,
+        bx: &mut Bx,
+        local: mir::Local,
+        base: PlaceRef<'tcx, Bx::Value>,
+        projection: &[mir::PlaceElem<'tcx>],
+    ) {
+        let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
+        if !full_debug_info {
+            return;
+        }
+
+        let vars = match &self.per_local_var_debug_info {
+            Some(per_local) => &per_local[local],
+            None => return,
+        };
+
+        let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
+            calculate_debuginfo_offset(bx, projection, base.layout);
+        for var in vars.iter() {
+            let Some(dbg_var) = var.dbg_var else {
+                continue;
+            };
+            let Some(dbg_loc) = self.dbg_loc(var.source_info) else {
+                continue;
+            };
+            bx.dbg_var_value(
+                dbg_var,
+                dbg_loc,
+                base.val.llval,
+                direct_offset,
+                &indirect_offsets,
+                &var.fragment,
+            );
+        }
+    }
+
+    pub(crate) fn debug_poison_to_local(&self, bx: &mut Bx, local: mir::Local) {
+        let ty = self.monomorphize(self.mir.local_decls[local].ty);
+        let layout = bx.cx().layout_of(ty);
+        let to_backend_ty = bx.cx().immediate_backend_type(layout);
+        let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
+        self.debug_new_val_to_local(bx, local, place_ref, &[]);
+    }
+
     /// Apply debuginfo and/or name, after creating the `alloca` for a local,
     /// or initializing the local with an operand (whichever applies).
     pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
@@ -424,7 +471,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 alloca.val.llval,
                 Size::ZERO,
                 &[Size::ZERO],
-                var.fragment,
+                &var.fragment,
             );
         } else {
             bx.dbg_var_addr(
@@ -433,7 +480,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 base.val.llval,
                 direct_offset,
                 &indirect_offsets,
-                var.fragment,
+                &var.fragment,
             );
         }
     }
@@ -455,7 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
                 bx.clear_dbg_loc();
 
-                bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment);
+                bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], &fragment);
             }
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index d851c332980..88a8e2a844c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -71,16 +71,23 @@ pub enum OperandValue<V> {
 }
 
 impl<V: CodegenObject> OperandValue<V> {
+    /// Return the data pointer and optional metadata as backend values
+    /// if this value can be treat as a pointer.
+    pub(crate) fn try_pointer_parts(self) -> Option<(V, Option<V>)> {
+        match self {
+            OperandValue::Immediate(llptr) => Some((llptr, None)),
+            OperandValue::Pair(llptr, llextra) => Some((llptr, Some(llextra))),
+            OperandValue::Ref(_) | OperandValue::ZeroSized => None,
+        }
+    }
+
     /// Treat this value as a pointer and return the data pointer and
     /// optional metadata as backend values.
     ///
     /// If you're making a place, use [`Self::deref`] instead.
     pub(crate) fn pointer_parts(self) -> (V, Option<V>) {
-        match self {
-            OperandValue::Immediate(llptr) => (llptr, None),
-            OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
-            _ => bug!("OperandValue cannot be a pointer: {self:?}"),
-        }
+        self.try_pointer_parts()
+            .unwrap_or_else(|| bug!("OperandValue cannot be a pointer: {self:?}"))
     }
 
     /// Treat this value as a pointer and return the place to which it points.
@@ -956,11 +963,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             let layout = o.layout.for_variant(bx.cx(), vidx);
                             o = OperandRef { val: o.val, layout }
                         }
-                        mir::PlaceElem::Subtype(subtype_ty) => {
-                            let subtype_ty = self.monomorphize(subtype_ty);
-                            let layout = self.cx.layout_of(subtype_ty);
-                            o = OperandRef { val: o.val, layout }
-                        }
                         _ => return None,
                     }
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 0090be9fdef..50f56f913a5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -347,7 +347,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 mir::ProjectionElem::OpaqueCast(ty) => {
                     bug!("encountered OpaqueCast({ty}) in codegen")
                 }
-                mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
                 mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
                     cg_base.project_type(bx, self.monomorphize(ty))
                 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 0a4b0f8d494..d629003bff5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -86,7 +86,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
-            mir::Rvalue::Cast(mir::CastKind::Transmute, ref operand, _ty) => {
+            mir::Rvalue::Cast(
+                mir::CastKind::Transmute | mir::CastKind::Subtype,
+                ref operand,
+                _ty,
+            ) => {
                 let src = self.codegen_operand(bx, operand);
                 self.codegen_transmute(bx, src, dest);
             }
@@ -486,7 +490,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                 bug!("Unsupported cast of {operand:?} to {cast:?}");
                             })
                     }
-                    mir::CastKind::Transmute => {
+                    mir::CastKind::Transmute | mir::CastKind::Subtype => {
                         self.codegen_transmute_operand(bx, operand, cast)
                     }
                 };
diff --git a/compiler/rustc_codegen_ssa/src/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs
index 0a50d7f18db..88590b6271b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/statement.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/statement.rs
@@ -1,4 +1,4 @@
-use rustc_middle::mir::{self, NonDivergingIntrinsic};
+use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo};
 use rustc_middle::span_bug;
 use tracing::instrument;
 
@@ -8,6 +8,7 @@ use crate::traits::*;
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "debug", skip(self, bx))]
     pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) {
+        self.codegen_stmt_debuginfos(bx, &statement.debuginfos);
         self.set_debug_loc(bx, statement.source_info);
         match statement.kind {
             mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
@@ -101,4 +102,49 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             | mir::StatementKind::Nop => {}
         }
     }
+
+    pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) {
+        match debuginfo {
+            StmtDebugInfo::AssignRef(dest, place) => {
+                let local_ref = match self.locals[place.local] {
+                    // For an rvalue like `&(_1.1)`, when `BackendRepr` is `BackendRepr::Memory`, we allocate a block of memory to this place.
+                    // The place is an indirect pointer, we can refer to it directly.
+                    LocalRef::Place(place_ref) => Some((place_ref, place.projection.as_slice())),
+                    // For an rvalue like `&((*_1).1)`, we are calculating the address of `_1.1`.
+                    // The deref projection is no-op here.
+                    LocalRef::Operand(operand_ref) if place.is_indirect_first_projection() => {
+                        Some((operand_ref.deref(bx.cx()), &place.projection[1..]))
+                    }
+                    // For an rvalue like `&1`, when `BackendRepr` is `BackendRepr::Scalar`,
+                    // we cannot get the address.
+                    // N.B. `non_ssa_locals` returns that this is an SSA local.
+                    LocalRef::Operand(_) => None,
+                    LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => None,
+                }
+                .filter(|(_, projection)| {
+                    // Drop unsupported projections.
+                    projection.iter().all(|p| p.can_use_in_debuginfo())
+                });
+                if let Some((base, projection)) = local_ref {
+                    self.debug_new_val_to_local(bx, *dest, base, projection);
+                } else {
+                    // If the address cannot be calculated, use poison to indicate that the value has been optimized out.
+                    self.debug_poison_to_local(bx, *dest);
+                }
+            }
+            StmtDebugInfo::InvalidAssign(local) => {
+                self.debug_poison_to_local(bx, *local);
+            }
+        }
+    }
+
+    pub(crate) fn codegen_stmt_debuginfos(
+        &mut self,
+        bx: &mut Bx,
+        debuginfos: &[StmtDebugInfo<'tcx>],
+    ) {
+        for debuginfo in debuginfos {
+            self.codegen_stmt_debuginfo(bx, debuginfo);
+        }
+    }
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
index b9d4950e0ad..a4da6c915de 100644
--- a/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs
@@ -77,7 +77,19 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
         indirect_offsets: &[Size],
         // Byte range in the `dbg_var` covered by this fragment,
         // if this is a fragment of a composite `DIVariable`.
-        fragment: Option<Range<Size>>,
+        fragment: &Option<Range<Size>>,
+    );
+    fn dbg_var_value(
+        &mut self,
+        dbg_var: Self::DIVariable,
+        dbg_loc: Self::DILocation,
+        value: Self::Value,
+        direct_offset: Size,
+        // NB: each offset implies a deref (i.e. they're steps in a pointer chain).
+        indirect_offsets: &[Size],
+        // Byte range in the `dbg_var` covered by this fragment,
+        // if this is a fragment of a composite `DIVariable`.
+        fragment: &Option<Range<Size>>,
     );
     fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
     fn clear_dbg_loc(&mut self);
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 34d1fdd8c86..8a6827bca2b 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -293,7 +293,6 @@ where
             ProjectionElem::Index(index) if in_local(index) => return true,
 
             ProjectionElem::Deref
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::Field(_, _)
             | ProjectionElem::OpaqueCast(_)
             | ProjectionElem::ConstantIndex { .. }
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 0075740e031..b058d4b8ad4 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -133,7 +133,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 }
             }
 
-            CastKind::Transmute => {
+            CastKind::Transmute | CastKind::Subtype => {
                 assert!(src.layout.is_sized());
                 assert!(dest.layout.is_sized());
                 assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index d05871bfc77..2fd1657f6ba 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -395,8 +395,6 @@ where
                 span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
             }
             UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
-            // We don't want anything happening here, this is here as a dummy.
-            Subtype(_) => base.transmute(base.layout(), self)?,
             Field(field, _) => self.project_field(base, field)?,
             Downcast(_, variant) => self.project_downcast(base, variant)?,
             Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
diff --git a/compiler/rustc_error_codes/src/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md
index d0ebc3a26f0..3c29484f575 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0608.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0608.md
@@ -1,5 +1,5 @@
-An attempt to use index on a type which doesn't implement the `std::ops::Index`
-trait was performed.
+Attempted to index a value whose type doesn't implement the
+`std::ops::Index` trait.
 
 Erroneous code example:
 
@@ -7,8 +7,8 @@ Erroneous code example:
 0u8[2]; // error: cannot index into a value of type `u8`
 ```
 
-To be able to index into a type it needs to implement the `std::ops::Index`
-trait. Example:
+Only values with types that implement the `std::ops::Index` trait
+can be indexed with square brackets. Example:
 
 ```
 let v: Vec<u8> = vec![0, 1, 2, 3];
@@ -16,3 +16,10 @@ let v: Vec<u8> = vec![0, 1, 2, 3];
 // The `Vec` type implements the `Index` trait so you can do:
 println!("{}", v[2]);
 ```
+
+Tuples and structs are indexed with dot (`.`), not with brackets (`[]`),
+and tuple element names are their positions:
+```ignore(pseudo code)
+// this (pseudo code) expression is true for any tuple:
+tuple == (tuple.0, tuple.1, ...)
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md
index cd981db1058..6aec38b42a3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0719.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0719.md
@@ -1,4 +1,4 @@
-An associated type value was specified more than once.
+An associated item was specified more than once in a trait object.
 
 Erroneous code example:
 
@@ -7,21 +7,15 @@ trait FooTrait {}
 trait BarTrait {}
 
 // error: associated type `Item` in trait `Iterator` is specified twice
-struct Foo<T: Iterator<Item: FooTrait, Item: BarTrait>> { f: T }
+type Foo = dyn Iterator<Item = u32, Item = u32>;
 ```
 
-`Item` in trait `Iterator` cannot be specified multiple times for struct `Foo`.
-To fix this, create a new trait that is a combination of the desired traits and
-specify the associated type with the new trait.
+To fix this, remove the duplicate specifier:
 
 Corrected example:
 
 ```
-trait FooTrait {}
-trait BarTrait {}
-trait FooBarTrait: FooTrait + BarTrait {}
-
-struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok!
+type Foo = dyn Iterator<Item = u32>; // ok!
 ```
 
 For more information about associated types, see [the book][bk-at]. For more
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 33b712e3aed..810a5a21a05 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -10,7 +10,7 @@ use rustc_ast::attr::{AttributeExt, MarkedAttrs};
 use rustc_ast::token::MetaVarKind;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
+use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind, Safety};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync;
 use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult};
@@ -345,6 +345,21 @@ pub trait AttrProcMacro {
         annotation: TokenStream,
         annotated: TokenStream,
     ) -> Result<TokenStream, ErrorGuaranteed>;
+
+    // Default implementation for safe attributes; override if the attribute can be unsafe.
+    fn expand_with_safety<'cx>(
+        &self,
+        ecx: &'cx mut ExtCtxt<'_>,
+        safety: Safety,
+        span: Span,
+        annotation: TokenStream,
+        annotated: TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        if let Safety::Unsafe(span) = safety {
+            ecx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
+        }
+        self.expand(ecx, span, annotation, annotated)
+    }
 }
 
 impl<F> AttrProcMacro for F
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 172bc3d1d9f..3dfa3cdcc35 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -812,11 +812,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         _ => item.to_tokens(),
                     };
                     let attr_item = attr.get_normal_item();
+                    let safety = attr_item.unsafety;
                     if let AttrArgs::Eq { .. } = attr_item.args {
                         self.cx.dcx().emit_err(UnsupportedKeyValue { span });
                     }
                     let inner_tokens = attr_item.args.inner_tokens();
-                    match expander.expand(self.cx, span, inner_tokens, tokens) {
+                    match expander.expand_with_safety(self.cx, safety, span, inner_tokens, tokens) {
                         Ok(tok_result) => {
                             let fragment = self.parse_ast_fragment(
                                 tok_result,
@@ -840,6 +841,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
                     }
                 } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {
+                    // `LegacyAttr` is only used for builtin attribute macros, which have their
+                    // safety checked by `check_builtin_meta_item`, so we don't need to check
+                    // `unsafety` here.
                     match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
                         Ok(meta) => {
                             let item_clone = macro_stats.then(|| item.clone());
@@ -882,6 +886,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         }
                     }
                 } else if let SyntaxExtensionKind::NonMacroAttr = ext {
+                    if let ast::Safety::Unsafe(span) = attr.get_normal_item().unsafety {
+                        self.cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute");
+                    }
                     // `-Zmacro-stats` ignores these because they don't do any real expansion.
                     self.cx.expanded_inert_attrs.mark(&attr);
                     item.visit_attrs(|attrs| attrs.insert(pos, attr));
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index d4504ba720e..c548cea537f 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -8,7 +8,7 @@ use rustc_ast::token::NtPatKind::*;
 use rustc_ast::token::TokenKind::*;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{self, DelimSpan, TokenStream};
-use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
+use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId, Safety};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
@@ -131,6 +131,7 @@ pub(super) enum MacroRule {
     Func { lhs: Vec<MatcherLoc>, lhs_span: Span, rhs: mbe::TokenTree },
     /// An attr rule, for use with `#[m]`
     Attr {
+        unsafe_rule: bool,
         args: Vec<MatcherLoc>,
         args_span: Span,
         body: Vec<MatcherLoc>,
@@ -248,7 +249,18 @@ impl TTMacroExpander for MacroRulesMacroExpander {
 impl AttrProcMacro for MacroRulesMacroExpander {
     fn expand(
         &self,
+        _cx: &mut ExtCtxt<'_>,
+        _sp: Span,
+        _args: TokenStream,
+        _body: TokenStream,
+    ) -> Result<TokenStream, ErrorGuaranteed> {
+        unreachable!("`expand` called on `MacroRulesMacroExpander`, expected `expand_with_safety`")
+    }
+
+    fn expand_with_safety(
+        &self,
         cx: &mut ExtCtxt<'_>,
+        safety: Safety,
         sp: Span,
         args: TokenStream,
         body: TokenStream,
@@ -260,6 +272,7 @@ impl AttrProcMacro for MacroRulesMacroExpander {
             self.node_id,
             self.name,
             self.transparency,
+            safety,
             args,
             body,
             &self.rules,
@@ -408,6 +421,7 @@ fn expand_macro_attr(
     node_id: NodeId,
     name: Ident,
     transparency: Transparency,
+    safety: Safety,
     args: TokenStream,
     body: TokenStream,
     rules: &[MacroRule],
@@ -429,13 +443,26 @@ fn expand_macro_attr(
     // Track nothing for the best performance.
     match try_match_macro_attr(psess, name, &args, &body, rules, &mut NoopTracker) {
         Ok((i, rule, named_matches)) => {
-            let MacroRule::Attr { rhs, .. } = rule else {
+            let MacroRule::Attr { rhs, unsafe_rule, .. } = rule else {
                 panic!("try_macro_match_attr returned non-attr rule");
             };
             let mbe::TokenTree::Delimited(rhs_span, _, rhs) = rhs else {
                 cx.dcx().span_bug(sp, "malformed macro rhs");
             };
 
+            match (safety, unsafe_rule) {
+                (Safety::Default, false) | (Safety::Unsafe(_), true) => {}
+                (Safety::Default, true) => {
+                    cx.dcx().span_err(sp, "unsafe attribute invocation requires `unsafe`");
+                }
+                (Safety::Unsafe(span), false) => {
+                    cx.dcx().span_err(span, "unnecessary `unsafe` on safe attribute invocation");
+                }
+                (Safety::Safe(span), _) => {
+                    cx.dcx().span_bug(span, "unexpected `safe` keyword");
+                }
+            }
+
             let id = cx.current_expansion.id;
             let tts = transcribe(psess, &named_matches, rhs, *rhs_span, transparency, id)
                 .map_err(|e| e.emit())?;
@@ -681,6 +708,11 @@ pub fn compile_declarative_macro(
     let mut rules = Vec::new();
 
     while p.token != token::Eof {
+        let unsafe_rule = p.eat_keyword_noexpect(kw::Unsafe);
+        let unsafe_keyword_span = p.prev_token.span;
+        if unsafe_rule && let Some(guar) = check_no_eof(sess, &p, "expected `attr`") {
+            return dummy_syn_ext(guar);
+        }
         let (args, is_derive) = if p.eat_keyword_noexpect(sym::attr) {
             kinds |= MacroKinds::ATTR;
             if !features.macro_attr() {
@@ -705,6 +737,10 @@ pub fn compile_declarative_macro(
                 feature_err(sess, sym::macro_derive, span, "`macro_rules!` derives are unstable")
                     .emit();
             }
+            if unsafe_rule {
+                sess.dcx()
+                    .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules");
+            }
             if let Some(guar) = check_no_eof(sess, &p, "expected `()` after `derive`") {
                 return dummy_syn_ext(guar);
             }
@@ -730,6 +766,10 @@ pub fn compile_declarative_macro(
             (None, true)
         } else {
             kinds |= MacroKinds::BANG;
+            if unsafe_rule {
+                sess.dcx()
+                    .span_err(unsafe_keyword_span, "`unsafe` is only supported on `attr` rules");
+            }
             (None, false)
         };
         let lhs_tt = p.parse_token_tree();
@@ -741,10 +781,10 @@ pub fn compile_declarative_macro(
         if let Some(guar) = check_no_eof(sess, &p, "expected right-hand side of macro rule") {
             return dummy_syn_ext(guar);
         }
-        let rhs_tt = p.parse_token_tree();
-        let rhs_tt = parse_one_tt(rhs_tt, RulePart::Body, sess, node_id, features, edition);
-        check_emission(check_rhs(sess, &rhs_tt));
-        check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs_tt));
+        let rhs = p.parse_token_tree();
+        let rhs = parse_one_tt(rhs, RulePart::Body, sess, node_id, features, edition);
+        check_emission(check_rhs(sess, &rhs));
+        check_emission(check_meta_variables(&sess.psess, node_id, args.as_ref(), &lhs_tt, &rhs));
         let lhs_span = lhs_tt.span();
         // Convert the lhs into `MatcherLoc` form, which is better for doing the
         // actual matching.
@@ -760,11 +800,11 @@ pub fn compile_declarative_macro(
             };
             let args = mbe::macro_parser::compute_locs(&delimited.tts);
             let body_span = lhs_span;
-            rules.push(MacroRule::Attr { args, args_span, body: lhs, body_span, rhs: rhs_tt });
+            rules.push(MacroRule::Attr { unsafe_rule, args, args_span, body: lhs, body_span, rhs });
         } else if is_derive {
-            rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs: rhs_tt });
+            rules.push(MacroRule::Derive { body: lhs, body_span: lhs_span, rhs });
         } else {
-            rules.push(MacroRule::Func { lhs, lhs_span, rhs: rhs_tt });
+            rules.push(MacroRule::Func { lhs, lhs_span, rhs });
         }
         if p.token == token::Eof {
             break;
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 38ae7852ca9..b069a74bf5a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -195,11 +195,10 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
-            | ty::CoroutineWitness(..)
-            | ty::Alias(ty::Free, _)
-            | ty::Bound(..)
-            | ty::Placeholder(_)
-            | ty::Infer(_) => {
+            | ty::CoroutineWitness(..) => {
+                Err(self.tcx.dcx().delayed_bug("cannot define inherent `impl` for closure types"))
+            }
+            ty::Alias(ty::Free, _) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) => {
                 bug!("unexpected impl self type of impl: {:?} {:?}", id, self_ty);
             }
             // We could bail out here, but that will silence other useful errors.
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 621431ae234..5a61248cab8 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -230,10 +230,12 @@ pub(crate) fn orphan_check_impl(
             ty::Closure(..)
             | ty::CoroutineClosure(..)
             | ty::Coroutine(..)
-            | ty::CoroutineWitness(..)
-            | ty::Bound(..)
-            | ty::Placeholder(..)
-            | ty::Infer(..) => {
+            | ty::CoroutineWitness(..) => {
+                return Err(tcx
+                    .dcx()
+                    .delayed_bug("cannot define inherent `impl` for closure types"));
+            }
+            ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => {
                 let sp = tcx.def_span(impl_def_id);
                 span_bug!(sp, "weird self type for autotrait impl")
             }
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index ba54fa8cc0d..129b26d8ff0 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -12,7 +12,7 @@ use tracing::{debug, instrument};
 
 use super::ItemCtxt;
 use super::predicates_of::assert_only_contains_predicates_from;
-use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter};
+use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter};
 
 /// For associated types we include both bounds written on the type
 /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`.
@@ -37,7 +37,14 @@ fn associated_type_bounds<'tcx>(
 
         let icx = ItemCtxt::new(tcx, assoc_item_def_id);
         let mut bounds = Vec::new();
-        icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
+        icx.lowerer().lower_bounds(
+            item_ty,
+            hir_bounds,
+            &mut bounds,
+            ty::List::empty(),
+            filter,
+            OverlappingAsssocItemConstraints::Allowed,
+        );
 
         match filter {
             PredicateFilter::All
@@ -174,21 +181,25 @@ fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
     for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
         let existing = match var.kind() {
             ty::GenericArgKind::Lifetime(re) => {
-                if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
+                if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
+                    re.kind()
+                {
                     mapping.insert(bv.var, tcx.mk_param_from_def(param))
                 } else {
                     return None;
                 }
             }
             ty::GenericArgKind::Type(ty) => {
-                if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
+                if let ty::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) = *ty.kind() {
                     mapping.insert(bv.var, tcx.mk_param_from_def(param))
                 } else {
                     return None;
                 }
             }
             ty::GenericArgKind::Const(ct) => {
-                if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
+                if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(ty::INNERMOST), bv) =
+                    ct.kind()
+                {
                     mapping.insert(bv.var, tcx.mk_param_from_def(param))
                 } else {
                     return None;
@@ -253,7 +264,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
             return ty;
         }
 
-        if let ty::Bound(binder, old_bound) = *ty.kind()
+        if let ty::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = *ty.kind()
             && self.binder == binder
         {
             let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
@@ -279,7 +290,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
     }
 
     fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        if let ty::ReBound(binder, old_bound) = re.kind()
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(binder), old_bound) = re.kind()
             && self.binder == binder
         {
             let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
@@ -307,7 +318,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
             return ct;
         }
 
-        if let ty::ConstKind::Bound(binder, old_bound) = ct.kind()
+        if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(binder), old_bound) = ct.kind()
             && self.binder == binder
         {
             let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
@@ -347,7 +358,14 @@ fn opaque_type_bounds<'tcx>(
     ty::print::with_reduced_queries!({
         let icx = ItemCtxt::new(tcx, opaque_def_id);
         let mut bounds = Vec::new();
-        icx.lowerer().lower_bounds(item_ty, hir_bounds, &mut bounds, ty::List::empty(), filter);
+        icx.lowerer().lower_bounds(
+            item_ty,
+            hir_bounds,
+            &mut bounds,
+            ty::List::empty(),
+            filter,
+            OverlappingAsssocItemConstraints::Allowed,
+        );
         // Implicit bounds are added to opaque types unless a `?Trait` bound is found
         match filter {
             PredicateFilter::All
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index dd3590f9ac5..ffdf2a2f4c0 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -18,7 +18,9 @@ use super::item_bounds::explicit_item_bounds_with_filter;
 use crate::collect::ItemCtxt;
 use crate::constrained_generic_params as cgp;
 use crate::delegation::inherit_predicates_for_delegation_item;
-use crate::hir_ty_lowering::{HirTyLowerer, PredicateFilter, RegionInferReason};
+use crate::hir_ty_lowering::{
+    HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
+};
 
 /// Returns a list of all type predicates (explicit and implicit) for the definition with
 /// ID `def_id`. This includes all predicates returned by `explicit_predicates_of`, plus
@@ -187,6 +189,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::All,
+            OverlappingAsssocItemConstraints::Allowed,
         );
         icx.lowerer().add_sizedness_bounds(
             &mut bounds,
@@ -289,6 +292,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                     &mut bounds,
                     bound_vars,
                     PredicateFilter::All,
+                    OverlappingAsssocItemConstraints::Allowed,
                 );
                 predicates.extend(bounds);
             }
@@ -659,7 +663,14 @@ pub(super) fn implied_predicates_with_filter<'tcx>(
 
     let self_param_ty = tcx.types.self_param;
     let mut bounds = Vec::new();
-    icx.lowerer().lower_bounds(self_param_ty, superbounds, &mut bounds, ty::List::empty(), filter);
+    icx.lowerer().lower_bounds(
+        self_param_ty,
+        superbounds,
+        &mut bounds,
+        ty::List::empty(),
+        filter,
+        OverlappingAsssocItemConstraints::Allowed,
+    );
     match filter {
         PredicateFilter::All
         | PredicateFilter::SelfOnly
@@ -984,6 +995,7 @@ impl<'tcx> ItemCtxt<'tcx> {
                 &mut bounds,
                 bound_vars,
                 filter,
+                OverlappingAsssocItemConstraints::Allowed,
             );
         }
 
@@ -1063,6 +1075,7 @@ pub(super) fn const_conditions<'tcx>(
                     &mut bounds,
                     bound_vars,
                     PredicateFilter::ConstIfConst,
+                    OverlappingAsssocItemConstraints::Allowed,
                 );
             }
             _ => {}
@@ -1083,6 +1096,7 @@ pub(super) fn const_conditions<'tcx>(
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::ConstIfConst,
+            OverlappingAsssocItemConstraints::Allowed,
         );
     }
 
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 2a633810cd7..f8d0ea3e7bf 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
     // which is `O(nt)` where `t` is the depth of type-parameter constraints,
     // remembering that `t` should be less than 7 in practice.
     //
+    // FIXME(hkBst): the big-O bound above would be accurate for the number
+    // of calls to `parameters_for`, which itself is some O(complexity of type).
+    // That would make this potentially cubic instead of merely quadratic...
+    // ...unless we cache those `parameters_for` calls.
+    //
     // Basically, I iterate over all projections and swap every
     // "ready" projection to the start of the list, such that
     // all of the projections before `i` are topologically sorted
     // and constrain all the parameters in `input_parameters`.
     //
-    // In the example, `input_parameters` starts by containing `U` - which
-    // is constrained by the trait-ref - and so on the first pass we
+    // In the first example, `input_parameters` starts by containing `U`,
+    // which is constrained by the self type `U`. Then, on the first pass we
     // observe that `<U as Iterator>::Item = T` is a "ready" projection that
-    // constrains `T` and swap it to front. As it is the sole projection,
+    // constrains `T` and swap it to the front. As it is the sole projection,
     // no more swaps can take place afterwards, with the result being
     //   * <U as Iterator>::Item = T
     //   * T: Debug
@@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
         for j in i..predicates.len() {
             // Note that we don't have to care about binders here,
             // as the impl trait ref never contains any late-bound regions.
-            if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
-                // Special case: watch out for some kind of sneaky attempt
-                // to project out an associated type defined by this very
-                // trait.
-                let unbound_trait_ref = projection.projection_term.trait_ref(tcx);
-                if Some(unbound_trait_ref) == impl_trait_ref {
-                    continue;
-                }
-
-                // A projection depends on its input types and determines its output
-                // type. For example, if we have
-                //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
-                // Then the projection only applies if `T` is known, but it still
-                // does not determine `U`.
-                let inputs = parameters_for(tcx, projection.projection_term, true);
-                let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
-                if !relies_only_on_inputs {
-                    continue;
-                }
+            if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() &&
+
+            // Special case: watch out for some kind of sneaky attempt to
+            // project out an associated type defined by this very trait.
+            !impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) &&
+
+            // A projection depends on its input types and determines its output
+            // type. For example, if we have
+            //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
+            // then the projection only applies if `T` is known, but it still
+            // does not determine `U`.
+                parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p))
+            {
                 input_parameters.extend(parameters_for(tcx, projection.term, false));
-            } else {
-                continue;
+
+                predicates.swap(i, j);
+                i += 1;
+                changed = true;
             }
-            // fancy control flow to bypass borrow checker
-            predicates.swap(i, j);
-            i += 1;
-            changed = true;
         }
         debug!(
             "setup_constraining_predicates: predicates={:?} \
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 99dc8e6e522..7accab8df87 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -21,7 +21,8 @@ use tracing::{debug, instrument};
 use super::errors::GenericsArgsErrExtend;
 use crate::errors;
 use crate::hir_ty_lowering::{
-    AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
+    AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter,
+    RegionInferReason,
 };
 
 #[derive(Debug, Default)]
@@ -338,6 +339,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
         predicate_filter: PredicateFilter,
+        overlapping_assoc_constraints: OverlappingAsssocItemConstraints,
     ) where
         'tcx: 'hir,
     {
@@ -362,6 +364,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         param_ty,
                         bounds,
                         predicate_filter,
+                        overlapping_assoc_constraints,
                     );
                 }
                 hir::GenericBound::Outlives(lifetime) => {
@@ -402,7 +405,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         trait_ref: ty::PolyTraitRef<'tcx>,
         constraint: &hir::AssocItemConstraint<'tcx>,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
-        duplicates: &mut FxIndexMap<DefId, Span>,
+        duplicates: Option<&mut FxIndexMap<DefId, Span>>,
         path_span: Span,
         predicate_filter: PredicateFilter,
     ) -> Result<(), ErrorGuaranteed> {
@@ -458,17 +461,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             )
             .expect("failed to find associated item");
 
-        duplicates
-            .entry(assoc_item.def_id)
-            .and_modify(|prev_span| {
-                self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
-                    span: constraint.span,
-                    prev_span: *prev_span,
-                    item_name: constraint.ident,
-                    def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
-                });
-            })
-            .or_insert(constraint.span);
+        if let Some(duplicates) = duplicates {
+            duplicates
+                .entry(assoc_item.def_id)
+                .and_modify(|prev_span| {
+                    self.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
+                        span: constraint.span,
+                        prev_span: *prev_span,
+                        item_name: constraint.ident,
+                        def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
+                    });
+                })
+                .or_insert(constraint.span);
+        }
 
         let projection_term = if let ty::AssocTag::Fn = assoc_tag {
             let bound_vars = tcx.late_bound_vars(constraint.hir_id);
@@ -600,6 +605,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             bounds,
                             projection_ty.bound_vars(),
                             predicate_filter,
+                            OverlappingAsssocItemConstraints::Allowed,
                         );
                     }
                     PredicateFilter::SelfOnly
@@ -915,7 +921,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
             ty::Param(param) => {
                 self.params.insert(param.index);
             }
-            ty::Bound(db, bt) if *db >= self.depth => {
+            ty::Bound(ty::BoundVarIndexKind::Bound(db), bt) if *db >= self.depth => {
                 self.vars.insert(match bt.kind {
                     ty::BoundTyKind::Param(def_id) => def_id,
                     ty::BoundTyKind::Anon => {
@@ -938,7 +944,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
             ty::ReEarlyParam(param) => {
                 self.params.insert(param.index);
             }
-            ty::ReBound(db, br) if db >= self.depth => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.depth => {
                 self.vars.insert(match br.kind {
                     ty::BoundRegionKind::Named(def_id) => def_id,
                     ty::BoundRegionKind::Anon | ty::BoundRegionKind::ClosureEnv => {
@@ -961,7 +967,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GenericParamAndBoundVarCollector<'_, 't
             ty::ConstKind::Param(param) => {
                 self.params.insert(param.index);
             }
-            ty::ConstKind::Bound(db, _) if db >= self.depth => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(db), _) if db >= self.depth => {
                 let guar = self.cx.dcx().delayed_bug("unexpected escaping late-bound const var");
                 return ControlFlow::Break(guar);
             }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
index c248cd7fec2..c0b13773089 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs
@@ -23,7 +23,9 @@ use tracing::{debug, instrument};
 
 use super::HirTyLowerer;
 use crate::errors::SelfInTypeAlias;
-use crate::hir_ty_lowering::{GenericArgCountMismatch, PredicateFilter, RegionInferReason};
+use crate::hir_ty_lowering::{
+    GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason,
+};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     /// Lower a trait object type from the HIR to our internal notion of a type.
@@ -60,6 +62,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 dummy_self,
                 &mut user_written_bounds,
                 PredicateFilter::SelfOnly,
+                OverlappingAsssocItemConstraints::Forbidden,
             );
             if let Err(GenericArgCountMismatch { invalid_args, .. }) = result.correct {
                 potential_assoc_types.extend(invalid_args);
@@ -157,10 +160,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 self.dcx()
                     .struct_span_err(
                         span,
-                        format!(
-                            "conflicting associated type bounds for `{item}` when \
-                            expanding trait alias"
-                        ),
+                        format!("conflicting associated type bounds for `{item}`"),
                     )
                     .with_span_label(
                         old_proj_span,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 9b198d04454..eb660804c2b 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -332,6 +332,15 @@ pub(crate) enum GenericArgPosition {
     MethodCall,
 }
 
+/// Whether to allow duplicate associated iten constraints in a trait ref, e.g.
+/// `Trait<Assoc = Ty, Assoc = Ty>`. This is forbidden in `dyn Trait<...>`
+/// but allowed everywhere else.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub(crate) enum OverlappingAsssocItemConstraints {
+    Allowed,
+    Forbidden,
+}
+
 /// A marker denoting that the generic arguments that were
 /// provided did not match the respective generic parameters.
 #[derive(Clone, Debug)]
@@ -752,6 +761,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self_ty: Ty<'tcx>,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         predicate_filter: PredicateFilter,
+        overlapping_assoc_item_constraints: OverlappingAsssocItemConstraints,
     ) -> GenericArgCountResult {
         let tcx = self.tcx();
 
@@ -908,7 +918,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
         }
 
-        let mut dup_constraints = FxIndexMap::default();
+        let mut dup_constraints = (overlapping_assoc_item_constraints
+            == OverlappingAsssocItemConstraints::Forbidden)
+            .then_some(FxIndexMap::default());
+
         for constraint in trait_segment.args().constraints {
             // Don't register any associated item constraints for negative bounds,
             // since we should have emitted an error for them earlier, and they
@@ -927,7 +940,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 poly_trait_ref,
                 constraint,
                 bounds,
-                &mut dup_constraints,
+                dup_constraints.as_mut(),
                 constraint.span,
                 predicate_filter,
             );
@@ -2484,6 +2497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     &mut bounds,
                     ty::List::empty(),
                     PredicateFilter::All,
+                    OverlappingAsssocItemConstraints::Allowed,
                 );
                 self.add_sizedness_bounds(
                     &mut bounds,
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d1ce0afddf9..f9cdc923670 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -3551,35 +3551,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
                     // Try to give some advice about indexing tuples.
                     if let ty::Tuple(types) = base_t.kind() {
-                        let mut needs_note = true;
-                        // If the index is an integer, we can show the actual
-                        // fixed expression:
+                        err.help(
+                            "tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.",
+                        );
+                        // If index is an unsuffixed integer, show the fixed expression:
                         if let ExprKind::Lit(lit) = idx.kind
                             && let ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) = lit.node
-                            && i.get()
-                                < types
-                                    .len()
-                                    .try_into()
-                                    .expect("expected tuple index to be < usize length")
+                            && i.get() < types.len().try_into().expect("tuple length fits in u128")
                         {
                             err.span_suggestion(
                                 brackets_span,
-                                "to access tuple elements, use",
+                                format!("to access tuple element `{i}`, use"),
                                 format!(".{i}"),
                                 Applicability::MachineApplicable,
                             );
-                            needs_note = false;
-                        } else if let ExprKind::Path(..) = idx.peel_borrows().kind {
-                            err.span_label(
-                                idx.span,
-                                "cannot access tuple elements at a variable index",
-                            );
-                        }
-                        if needs_note {
-                            err.help(
-                                "to access tuple elements, use tuple indexing \
-                                        syntax (e.g., `tuple.0`)",
-                            );
                         }
                     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 833ce433d56..35253e4c291 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -611,19 +611,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         typeck_results.rvalue_scopes = rvalue_scopes;
     }
 
-    /// Unify the inference variables corresponding to coroutine witnesses, and save all the
-    /// predicates that were stalled on those inference variables.
-    ///
-    /// This process allows to conservatively save all predicates that do depend on the coroutine
-    /// interior types, for later processing by `check_coroutine_obligations`.
-    ///
-    /// We must not attempt to select obligations after this method has run, or risk query cycle
-    /// ICE.
+    /// Drain all obligations that are stalled on coroutines defined in this body.
     #[instrument(level = "debug", skip(self))]
-    pub(crate) fn resolve_coroutine_interiors(&self) {
-        // Try selecting all obligations that are not blocked on inference variables.
-        // Once we start unifying coroutine witnesses, trying to select obligations on them will
-        // trigger query cycle ICEs, as doing so requires MIR.
+    pub(crate) fn drain_stalled_coroutine_obligations(&self) {
+        // Make as much inference progress as possible before
+        // draining the stalled coroutine obligations as this may
+        // change obligations from being stalled on infer vars to
+        // being stalled on a coroutine.
         self.select_obligations_where_possible(|_| {});
 
         let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index acc0481e457..9f5a85b6926 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -243,18 +243,15 @@ fn typeck_with_inspect<'tcx>(
 
     debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
 
-    // This must be the last thing before `report_ambiguity_errors`.
-    fcx.resolve_coroutine_interiors();
-
-    debug!(pending_obligations = ?fcx.fulfillment_cx.borrow().pending_obligations());
-
     // We need to handle opaque types before emitting ambiguity errors as applying
     // defining uses may guide type inference.
     if fcx.next_trait_solver() {
         fcx.handle_opaque_type_uses_next();
     }
 
-    fcx.select_obligations_where_possible(|_| {});
+    // This must be the last thing before `report_ambiguity_errors` below except `select_obligations_where_possible`.
+    // So don't put anything after this.
+    fcx.drain_stalled_coroutine_obligations();
     if fcx.infcx.tainted_by_errors().is_none() {
         fcx.report_ambiguity_errors();
     }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 3c5e4a91c98..e445def4faa 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -303,8 +303,6 @@ struct Canonicalizer<'cx, 'tcx> {
     sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
     canonicalize_mode: &'cx dyn CanonicalizeMode,
     needs_canonical_flags: TypeFlags,
-
-    binder_index: ty::DebruijnIndex,
 }
 
 impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
@@ -312,24 +310,12 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>,
-    {
-        self.binder_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.binder_index.shift_out(1);
-        t
-    }
-
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match r.kind() {
-            ty::ReBound(index, ..) => {
-                if index >= self.binder_index {
-                    bug!("escaping late-bound region during canonicalization");
-                } else {
-                    r
-                }
+            ty::ReBound(ty::BoundVarIndexKind::Bound(_), ..) => r,
+
+            ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
+                bug!("canonicalized bound var found during canonicalization");
             }
 
             ty::ReStatic
@@ -403,12 +389,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
                 self.canonicalize_ty_var(CanonicalVarKind::PlaceholderTy(placeholder), t)
             }
 
-            ty::Bound(debruijn, _) => {
-                if debruijn >= self.binder_index {
-                    bug!("escaping bound type during canonicalization")
-                } else {
-                    t
-                }
+            ty::Bound(ty::BoundVarIndexKind::Bound(_), _) => t,
+
+            ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
+                bug!("canonicalized bound var found during canonicalization");
             }
 
             ty::Closure(..)
@@ -479,12 +463,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
             ty::ConstKind::Infer(InferConst::Fresh(_)) => {
                 bug!("encountered a fresh const during canonicalization")
             }
-            ty::ConstKind::Bound(debruijn, _) => {
-                if debruijn >= self.binder_index {
-                    bug!("escaping bound const during canonicalization")
-                } else {
-                    return ct;
-                }
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(_), _) => {
+                return ct;
+            }
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => {
+                bug!("canonicalized bound var found during canonicalization");
             }
             ty::ConstKind::Placeholder(placeholder) => {
                 return self
@@ -569,7 +552,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             query_state,
             indices: FxHashMap::default(),
             sub_root_lookup_table: Default::default(),
-            binder_index: ty::INNERMOST,
         };
         if canonicalizer.query_state.var_values.spilled() {
             canonicalizer.indices = canonicalizer
@@ -751,8 +733,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
         let var = self.canonical_var(var_kind, r.into());
-        let br = ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon };
-        ty::Region::new_bound(self.cx(), self.binder_index, br)
+        ty::Region::new_canonical_bound(self.cx(), var)
     }
 
     /// Given a type variable `ty_var` of the given kind, first check
@@ -766,8 +747,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
     ) -> Ty<'tcx> {
         debug_assert!(!self.infcx.is_some_and(|infcx| ty_var != infcx.shallow_resolve(ty_var)));
         let var = self.canonical_var(var_kind, ty_var.into());
-        let bt = ty::BoundTy { var, kind: ty::BoundTyKind::Anon };
-        Ty::new_bound(self.tcx, self.binder_index, bt)
+        Ty::new_canonical_bound(self.tcx, var)
     }
 
     /// Given a type variable `const_var` of the given kind, first check
@@ -783,7 +763,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
             !self.infcx.is_some_and(|infcx| ct_var != infcx.shallow_resolve_const(ct_var))
         );
         let var = self.canonical_var(var_kind, ct_var.into());
-        let bc = ty::BoundConst { var };
-        ty::Const::new_bound(self.tcx, self.binder_index, bc)
+        ty::Const::new_canonical_bound(self.tcx, var)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index cc052fbd85c..c215a9db2a0 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{
     self, DelayedMap, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
     TypeVisitableExt, TypeVisitor,
 };
-use rustc_type_ir::TypeVisitable;
+use rustc_type_ir::{TypeFlags, TypeVisitable};
 
 use crate::infer::canonical::{Canonical, CanonicalVarValues};
 
@@ -66,7 +66,6 @@ where
 
     value.fold_with(&mut CanonicalInstantiator {
         tcx,
-        current_index: ty::INNERMOST,
         var_values: var_values.var_values,
         cache: Default::default(),
     })
@@ -79,12 +78,9 @@ struct CanonicalInstantiator<'tcx> {
     // The values that the bound vars are are being instantiated with.
     var_values: ty::GenericArgsRef<'tcx>,
 
-    /// As with `BoundVarReplacer`, represents the index of a binder *just outside*
-    /// the ones we have visited.
-    current_index: ty::DebruijnIndex,
-
-    // Instantiation is a pure function of `DebruijnIndex` and `Ty`.
-    cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>,
+    // Because we use `ty::BoundVarIndexKind::Canonical`, we can cache
+    // based only on the entire ty, not worrying about a `DebruijnIndex`
+    cache: DelayedMap<Ty<'tcx>, Ty<'tcx>>,
 }
 
 impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
@@ -92,29 +88,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
         self.tcx
     }
 
-    fn fold_binder<T: TypeFoldable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: ty::Binder<'tcx, T>,
-    ) -> ty::Binder<'tcx, T> {
-        self.current_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.current_index.shift_out(1);
-        t
-    }
-
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
+            ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) => {
                 self.var_values[bound_ty.var.as_usize()].expect_ty()
             }
             _ => {
-                if !t.has_vars_bound_at_or_above(self.current_index) {
+                if !t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
                     t
-                } else if let Some(&t) = self.cache.get(&(self.current_index, t)) {
+                } else if let Some(&t) = self.cache.get(&t) {
                     t
                 } else {
                     let res = t.super_fold_with(self);
-                    assert!(self.cache.insert((self.current_index, t), res));
+                    assert!(self.cache.insert(t, res));
                     res
                 }
             }
@@ -123,7 +109,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match r.kind() {
-            ty::ReBound(debruijn, br) if debruijn == self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Canonical, br) => {
                 self.var_values[br.var.as_usize()].expect_region()
             }
             _ => r,
@@ -132,7 +118,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match ct.kind() {
-            ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) => {
                 self.var_values[bound_const.var.as_usize()].expect_const()
             }
             _ => ct.super_fold_with(self),
@@ -140,22 +126,14 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
     }
 
     fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p }
+        if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p }
     }
 
     fn fold_clauses(&mut self, c: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
-        if !c.has_vars_bound_at_or_above(self.current_index) {
+        if !c.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
             return c;
         }
 
-        // Since instantiation is a function of `DebruijnIndex`, we don't want
-        // to have to cache more copies of clauses when we're inside of binders.
-        // Since we currently expect to only have clauses in the outermost
-        // debruijn index, we just fold if we're inside of a binder.
-        if self.current_index > ty::INNERMOST {
-            return c.super_fold_with(self);
-        }
-
         // Our cache key is `(clauses, var_values)`, but we also don't care about
         // var values that aren't named in the clauses, since they can change without
         // affecting the output. Since `ParamEnv`s are cached first, we compute the
@@ -185,45 +163,29 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for CanonicalInstantiator<'tcx> {
 fn highest_var_in_clauses<'tcx>(c: ty::Clauses<'tcx>) -> usize {
     struct HighestVarInClauses {
         max_var: usize,
-        current_index: ty::DebruijnIndex,
     }
     impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HighestVarInClauses {
-        fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
-            &mut self,
-            t: &ty::Binder<'tcx, T>,
-        ) -> Self::Result {
-            self.current_index.shift_in(1);
-            let t = t.super_visit_with(self);
-            self.current_index.shift_out(1);
-            t
-        }
         fn visit_ty(&mut self, t: Ty<'tcx>) {
-            if let ty::Bound(debruijn, bound_ty) = *t.kind()
-                && debruijn == self.current_index
-            {
+            if let ty::Bound(ty::BoundVarIndexKind::Canonical, bound_ty) = *t.kind() {
                 self.max_var = self.max_var.max(bound_ty.var.as_usize());
-            } else if t.has_vars_bound_at_or_above(self.current_index) {
+            } else if t.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
                 t.super_visit_with(self);
             }
         }
         fn visit_region(&mut self, r: ty::Region<'tcx>) {
-            if let ty::ReBound(debruijn, bound_region) = r.kind()
-                && debruijn == self.current_index
-            {
+            if let ty::ReBound(ty::BoundVarIndexKind::Canonical, bound_region) = r.kind() {
                 self.max_var = self.max_var.max(bound_region.var.as_usize());
             }
         }
         fn visit_const(&mut self, ct: ty::Const<'tcx>) {
-            if let ty::ConstKind::Bound(debruijn, bound_const) = ct.kind()
-                && debruijn == self.current_index
-            {
+            if let ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bound_const) = ct.kind() {
                 self.max_var = self.max_var.max(bound_const.var.as_usize());
-            } else if ct.has_vars_bound_at_or_above(self.current_index) {
+            } else if ct.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) {
                 ct.super_visit_with(self);
             }
         }
     }
-    let mut visitor = HighestVarInClauses { max_var: 0, current_index: ty::INNERMOST };
+    let mut visitor = HighestVarInClauses { max_var: 0 };
     c.visit_with(&mut visitor);
     visitor.max_var
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index b3959113d5d..37a19605206 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -440,28 +440,28 @@ impl<'tcx> InferCtxt<'tcx> {
                     // and only use it for placeholders. We need to handle the
                     // `sub_root` of type inference variables which would make this
                     // more involved. They are also a lot rarer than region variables.
-                    if let ty::Bound(debruijn, b) = *result_value.kind()
+                    if let ty::Bound(index_kind, b) = *result_value.kind()
                         && !matches!(
                             query_response.variables[b.var.as_usize()],
                             CanonicalVarKind::Ty { .. }
                         )
                     {
-                        // We only allow a `ty::INNERMOST` index in generic parameters.
-                        assert_eq!(debruijn, ty::INNERMOST);
+                        // We only allow a `Canonical` index in generic parameters.
+                        assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                         opt_values[b.var] = Some(*original_value);
                     }
                 }
                 GenericArgKind::Lifetime(result_value) => {
-                    if let ty::ReBound(debruijn, b) = result_value.kind() {
-                        // We only allow a `ty::INNERMOST` index in generic parameters.
-                        assert_eq!(debruijn, ty::INNERMOST);
+                    if let ty::ReBound(index_kind, b) = result_value.kind() {
+                        // We only allow a `Canonical` index in generic parameters.
+                        assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                         opt_values[b.var] = Some(*original_value);
                     }
                 }
                 GenericArgKind::Const(result_value) => {
-                    if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
-                        // We only allow a `ty::INNERMOST` index in generic parameters.
-                        assert_eq!(debruijn, ty::INNERMOST);
+                    if let ty::ConstKind::Bound(index_kind, b) = result_value.kind() {
+                        // We only allow a `Canonical` index in generic parameters.
+                        assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                         opt_values[b.var] = Some(*original_value);
                     }
                 }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index c9fc124d3bf..f3ebfde06ab 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> {
     /// `$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.)
-    ///
-    /// These are stored in a map keyed to the id of the innermost
-    /// enclosing fn body / static initializer expression. This is
-    /// because the location where the obligation was incurred can be
-    /// relevant with respect to which sublifetime assumptions are in
-    /// place. The reason that we store under the fn-id, and not
-    /// something more fine-grained, is so that it is easier for
-    /// regionck to be sure that it has found *all* the region
-    /// obligations (otherwise, it's easy to fail to walk to a
-    /// particular node-id).
-    ///
-    /// Before running `resolve_regions_and_report_errors`, the creator
-    /// of the inference context is expected to invoke
-    /// [`InferCtxt::process_registered_region_obligations`]
-    /// for each body-id in this map, which will process the
-    /// obligations within. This is expected to be done 'late enough'
-    /// that all type inference variables have been bound and so forth.
     region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
 
     /// The outlives bounds that we assume must hold about placeholders that
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index f06eb58a371..6592360cf0a 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -44,8 +44,8 @@ pub fn extract_verify_if_eq<'tcx>(
     let verify_if_eq = verify_if_eq_b.skip_binder();
     m.relate(verify_if_eq.ty, test_ty).ok()?;
 
-    if let ty::RegionKind::ReBound(depth, br) = verify_if_eq.bound.kind() {
-        assert!(depth == ty::INNERMOST);
+    if let ty::RegionKind::ReBound(index_kind, br) = verify_if_eq.bound.kind() {
+        assert!(matches!(index_kind, ty::BoundVarIndexKind::Bound(ty::INNERMOST)));
         match m.map.get(&br) {
             Some(&r) => Some(r),
             None => {
@@ -156,7 +156,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx>
         pattern: ty::Region<'tcx>,
         value: ty::Region<'tcx>,
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-        if let ty::RegionKind::ReBound(depth, br) = pattern.kind()
+        if let ty::RegionKind::ReBound(ty::BoundVarIndexKind::Bound(depth), br) = pattern.kind()
             && depth == self.pattern_depth
         {
             self.bind(br, value)
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 2b83ea24ac6..e38474f09ff 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -58,6 +58,7 @@ using namespace llvm::object;
 // This opcode is an LLVM detail that could hypothetically change (?), so
 // verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM.
 static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000);
+static_assert(dwarf::DW_OP_stack_value == 0x9f);
 
 // LLVMAtomicOrdering is already an enum - don't create another
 // one.
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 28142382b13..8eb7aa71fcd 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1298,6 +1298,10 @@ pub struct BasicBlockData<'tcx> {
     /// List of statements in this block.
     pub statements: Vec<Statement<'tcx>>,
 
+    /// All debuginfos happen before the statement.
+    /// Put debuginfos here when the last statement is eliminated.
+    pub after_last_stmt_debuginfos: StmtDebugInfos<'tcx>,
+
     /// Terminator for this block.
     ///
     /// N.B., this should generally ONLY be `None` during construction.
@@ -1325,7 +1329,12 @@ impl<'tcx> BasicBlockData<'tcx> {
         terminator: Option<Terminator<'tcx>>,
         is_cleanup: bool,
     ) -> BasicBlockData<'tcx> {
-        BasicBlockData { statements, terminator, is_cleanup }
+        BasicBlockData {
+            statements,
+            after_last_stmt_debuginfos: StmtDebugInfos::default(),
+            terminator,
+            is_cleanup,
+        }
     }
 
     /// Accessor for terminator.
@@ -1360,6 +1369,36 @@ impl<'tcx> BasicBlockData<'tcx> {
             self.terminator().successors()
         }
     }
+
+    pub fn retain_statements<F>(&mut self, mut f: F)
+    where
+        F: FnMut(&Statement<'tcx>) -> bool,
+    {
+        // Place debuginfos into the next retained statement,
+        // this `debuginfos` variable is used to cache debuginfos between two retained statements.
+        let mut debuginfos = StmtDebugInfos::default();
+        self.statements.retain_mut(|stmt| {
+            let retain = f(stmt);
+            if retain {
+                stmt.debuginfos.prepend(&mut debuginfos);
+            } else {
+                debuginfos.append(&mut stmt.debuginfos);
+            }
+            retain
+        });
+        self.after_last_stmt_debuginfos.prepend(&mut debuginfos);
+    }
+
+    pub fn strip_nops(&mut self) {
+        self.retain_statements(|stmt| !matches!(stmt.kind, StatementKind::Nop))
+    }
+
+    pub fn drop_debuginfo(&mut self) {
+        self.after_last_stmt_debuginfos.drop_debuginfo();
+        for stmt in self.statements.iter_mut() {
+            stmt.debuginfos.drop_debuginfo();
+        }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -1664,10 +1703,10 @@ mod size_asserts {
 
     use super::*;
     // tidy-alphabetical-start
-    static_assert_size!(BasicBlockData<'_>, 128);
+    static_assert_size!(BasicBlockData<'_>, 152);
     static_assert_size!(LocalDecl<'_>, 40);
     static_assert_size!(SourceScopeData<'_>, 64);
-    static_assert_size!(Statement<'_>, 32);
+    static_assert_size!(Statement<'_>, 56);
     static_assert_size!(Terminator<'_>, 96);
     static_assert_size!(VarDebugInfo<'_>, 88);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 96148fd5b92..d87e3abe3b2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -719,6 +719,11 @@ impl<'de, 'tcx> MirWriter<'de, 'tcx> {
         let mut current_location = Location { block, statement_index: 0 };
         for statement in &data.statements {
             (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?;
+
+            for debuginfo in statement.debuginfos.iter() {
+                writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?};")?;
+            }
+
             let indented_body = format!("{INDENT}{INDENT}{statement:?};");
             if self.options.include_extra_comments {
                 writeln!(
@@ -749,6 +754,10 @@ impl<'de, 'tcx> MirWriter<'de, 'tcx> {
             current_location.statement_index += 1;
         }
 
+        for debuginfo in data.after_last_stmt_debuginfos.iter() {
+            writeln!(w, "{INDENT}{INDENT}// DBG: {debuginfo:?};")?;
+        }
+
         // Terminator at the bottom.
         (self.extra_data)(PassWhere::BeforeLocation(current_location), w)?;
         if data.terminator.is_some() {
@@ -829,6 +838,19 @@ impl Debug for Statement<'_> {
     }
 }
 
+impl Debug for StmtDebugInfo<'_> {
+    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+        match self {
+            StmtDebugInfo::AssignRef(local, place) => {
+                write!(fmt, "{local:?} = &{place:?}")
+            }
+            StmtDebugInfo::InvalidAssign(local) => {
+                write!(fmt, "{local:?} = &?")
+            }
+        }
+    }
+}
+
 impl Display for NonDivergingIntrinsic<'_> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
@@ -1274,7 +1296,6 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
     for &elem in projection.iter().rev() {
         match elem {
             ProjectionElem::OpaqueCast(_)
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::Downcast(_, _)
             | ProjectionElem::Field(_, _) => {
                 write!(fmt, "(")?;
@@ -1300,9 +1321,6 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
             ProjectionElem::OpaqueCast(ty) => {
                 write!(fmt, " as {ty})")?;
             }
-            ProjectionElem::Subtype(ty) => {
-                write!(fmt, " as subtype {ty})")?;
-            }
             ProjectionElem::Downcast(Some(name), _index) => {
                 write!(fmt, " as {name})")?;
             }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 28294b47e90..f310e1e5762 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -1,5 +1,7 @@
 //! Functionality for statements, operands, places, and things that appear in them.
 
+use std::ops;
+
 use tracing::{debug, instrument};
 
 use super::interpret::GlobalAlloc;
@@ -15,17 +17,28 @@ use crate::ty::CoroutineArgsExt;
 pub struct Statement<'tcx> {
     pub source_info: SourceInfo,
     pub kind: StatementKind<'tcx>,
+    /// Some debuginfos appearing before the primary statement.
+    pub debuginfos: StmtDebugInfos<'tcx>,
 }
 
 impl<'tcx> Statement<'tcx> {
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
     /// invalidating statement indices in `Location`s.
-    pub fn make_nop(&mut self) {
-        self.kind = StatementKind::Nop
+    pub fn make_nop(&mut self, drop_debuginfo: bool) {
+        if matches!(self.kind, StatementKind::Nop) {
+            return;
+        }
+        let replaced_stmt = std::mem::replace(&mut self.kind, StatementKind::Nop);
+        if !drop_debuginfo {
+            let Some(debuginfo) = replaced_stmt.as_debuginfo() else {
+                bug!("debuginfo is not yet supported.")
+            };
+            self.debuginfos.push(debuginfo);
+        }
     }
 
     pub fn new(source_info: SourceInfo, kind: StatementKind<'tcx>) -> Self {
-        Statement { source_info, kind }
+        Statement { source_info, kind, debuginfos: StmtDebugInfos::default() }
     }
 }
 
@@ -63,6 +76,17 @@ impl<'tcx> StatementKind<'tcx> {
             _ => None,
         }
     }
+
+    pub fn as_debuginfo(&self) -> Option<StmtDebugInfo<'tcx>> {
+        match self {
+            StatementKind::Assign(box (place, Rvalue::Ref(_, _, ref_place)))
+                if let Some(local) = place.as_local() =>
+            {
+                Some(StmtDebugInfo::AssignRef(local, *ref_place))
+            }
+            _ => None,
+        }
+    }
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -222,7 +246,6 @@ impl<'tcx> PlaceTy<'tcx> {
                 fty,
             )),
             ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
-            ProjectionElem::Subtype(ty) => PlaceTy::from_ty(handle_opaque_cast_and_subtype(ty)),
 
             // FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
             ProjectionElem::UnwrapUnsafeBinder(ty) => {
@@ -244,7 +267,6 @@ impl<V, T> ProjectionElem<V, T> {
             Self::Field(_, _)
             | Self::Index(_)
             | Self::OpaqueCast(_)
-            | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
             | Self::Downcast(_, _)
@@ -259,7 +281,6 @@ impl<V, T> ProjectionElem<V, T> {
             Self::Deref | Self::Index(_) => false,
             Self::Field(_, _)
             | Self::OpaqueCast(_)
-            | Self::Subtype(_)
             | Self::ConstantIndex { .. }
             | Self::Subslice { .. }
             | Self::Downcast(_, _)
@@ -286,7 +307,6 @@ impl<V, T> ProjectionElem<V, T> {
             | Self::Field(_, _) => true,
             Self::ConstantIndex { from_end: true, .. }
             | Self::Index(_)
-            | Self::Subtype(_)
             | Self::OpaqueCast(_)
             | Self::Subslice { .. } => false,
 
@@ -319,7 +339,6 @@ impl<V, T> ProjectionElem<V, T> {
                 ProjectionElem::Subslice { from, to, from_end }
             }
             ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)),
-            ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)),
             ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)),
             ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?),
         })
@@ -508,6 +527,20 @@ impl<'tcx> PlaceRef<'tcx> {
         })
     }
 
+    /// Return the place accessed locals that include the base local.
+    pub fn accessed_locals(self) -> impl Iterator<Item = Local> {
+        std::iter::once(self.local).chain(self.projection.iter().filter_map(|proj| match proj {
+            ProjectionElem::Index(local) => Some(*local),
+            ProjectionElem::Deref
+            | ProjectionElem::Field(_, _)
+            | ProjectionElem::ConstantIndex { .. }
+            | ProjectionElem::Subslice { .. }
+            | ProjectionElem::Downcast(_, _)
+            | ProjectionElem::OpaqueCast(_)
+            | ProjectionElem::UnwrapUnsafeBinder(_) => None,
+        }))
+    }
+
     /// Generates a new place by appending `more_projections` to the existing ones
     /// and interning the result.
     pub fn project_deeper(
@@ -706,7 +739,8 @@ impl<'tcx> Rvalue<'tcx> {
                 | CastKind::PtrToPtr
                 | CastKind::PointerCoercion(_, _)
                 | CastKind::PointerWithExposedProvenance
-                | CastKind::Transmute,
+                | CastKind::Transmute
+                | CastKind::Subtype,
                 _,
                 _,
             )
@@ -971,3 +1005,71 @@ impl RawPtrKind {
         }
     }
 }
+
+#[derive(Default, Debug, Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct StmtDebugInfos<'tcx>(Vec<StmtDebugInfo<'tcx>>);
+
+impl<'tcx> StmtDebugInfos<'tcx> {
+    pub fn push(&mut self, debuginfo: StmtDebugInfo<'tcx>) {
+        self.0.push(debuginfo);
+    }
+
+    pub fn drop_debuginfo(&mut self) {
+        self.0.clear();
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+
+    pub fn prepend(&mut self, debuginfos: &mut Self) {
+        if debuginfos.is_empty() {
+            return;
+        };
+        debuginfos.0.append(self);
+        std::mem::swap(debuginfos, self);
+    }
+
+    pub fn append(&mut self, debuginfos: &mut Self) {
+        if debuginfos.is_empty() {
+            return;
+        };
+        self.0.append(debuginfos);
+    }
+
+    pub fn extend(&mut self, debuginfos: &Self) {
+        if debuginfos.is_empty() {
+            return;
+        };
+        self.0.extend_from_slice(debuginfos);
+    }
+
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&StmtDebugInfo<'tcx>) -> bool,
+    {
+        self.0.retain(f);
+    }
+}
+
+impl<'tcx> ops::Deref for StmtDebugInfos<'tcx> {
+    type Target = Vec<StmtDebugInfo<'tcx>>;
+
+    #[inline]
+    fn deref(&self) -> &Vec<StmtDebugInfo<'tcx>> {
+        &self.0
+    }
+}
+
+impl<'tcx> ops::DerefMut for StmtDebugInfos<'tcx> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Vec<StmtDebugInfo<'tcx>> {
+        &mut self.0
+    }
+}
+
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub enum StmtDebugInfo<'tcx> {
+    AssignRef(Local, Place<'tcx>),
+    InvalidAssign(Local),
+}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index e6c8512564e..a823c365394 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1275,18 +1275,6 @@ pub enum ProjectionElem<V, T> {
     /// A transmute from an unsafe binder to the type that it wraps. This is a projection
     /// of a place, so it doesn't necessarily constitute a move out of the binder.
     UnwrapUnsafeBinder(T),
-
-    /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
-    /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
-    /// explicit during optimizations and codegen.
-    ///
-    /// This projection doesn't impact the runtime behavior of the program except for potentially changing
-    /// some type metadata of the interpreter or codegen backend.
-    ///
-    /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
-    /// borrowchecker, as we only care about subtyping that can affect trait selection and
-    /// `TypeId`.
-    Subtype(T),
 }
 
 /// Alias for projections as they appear in places, where the base is a place
@@ -1513,6 +1501,18 @@ pub enum CastKind {
     /// MIR is well-formed if the input and output types have different sizes,
     /// but running a transmute between differently-sized types is UB.
     Transmute,
+
+    /// A `Subtype` cast is applied to any `StatementKind::Assign` where
+    /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
+    /// explicit during optimizations and codegen.
+    ///
+    /// This cast doesn't impact the runtime behavior of the program except for potentially changing
+    /// some type metadata of the interpreter or codegen backend.
+    ///
+    /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after
+    /// borrowchecker, as we only care about subtyping that can affect trait selection and
+    /// `TypeId`.
+    Subtype,
 }
 
 /// Represents how a [`CastKind::PointerCoercion`] was constructed.
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index 4034a3a06e9..4249914346c 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -444,6 +444,14 @@ impl<'tcx> Terminator<'tcx> {
         self.kind.successors()
     }
 
+    /// Return `Some` if all successors are identical.
+    #[inline]
+    pub fn identical_successor(&self) -> Option<BasicBlock> {
+        let mut successors = self.successors();
+        let first_succ = successors.next()?;
+        if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None }
+    }
+
     #[inline]
     pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) {
         self.kind.successors_mut(f)
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 81df239dee4..9654e189f2e 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -95,6 +95,14 @@ macro_rules! make_mir_visitor {
                 self.super_source_scope_data(scope_data);
             }
 
+            fn visit_statement_debuginfo(
+                &mut self,
+                stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
+                location: Location
+            ) {
+                self.super_statement_debuginfo(stmt_debuginfo, location);
+            }
+
             fn visit_statement(
                 &mut self,
                 statement: & $($mutability)? Statement<'tcx>,
@@ -301,6 +309,7 @@ macro_rules! make_mir_visitor {
             {
                 let BasicBlockData {
                     statements,
+                    after_last_stmt_debuginfos,
                     terminator,
                     is_cleanup: _
                 } = data;
@@ -312,8 +321,11 @@ macro_rules! make_mir_visitor {
                     index += 1;
                 }
 
+                let location = Location { block, statement_index: index };
+                for debuginfo in after_last_stmt_debuginfos as & $($mutability)? [_] {
+                    self.visit_statement_debuginfo(debuginfo, location);
+                }
                 if let Some(terminator) = terminator {
-                    let location = Location { block, statement_index: index };
                     self.visit_terminator(terminator, location);
                 }
             }
@@ -376,14 +388,45 @@ macro_rules! make_mir_visitor {
                 }
             }
 
+            fn super_statement_debuginfo(
+                &mut self,
+                stmt_debuginfo: & $($mutability)? StmtDebugInfo<'tcx>,
+                location: Location
+            ) {
+                match stmt_debuginfo {
+                    StmtDebugInfo::AssignRef(local, place) => {
+                        self.visit_local(
+                            $(& $mutability)? *local,
+                            PlaceContext::NonUse(NonUseContext::VarDebugInfo),
+                            location
+                        );
+                        self.visit_place(
+                            place,
+                            PlaceContext::NonUse(NonUseContext::VarDebugInfo),
+                            location
+                        );
+                    },
+                    StmtDebugInfo::InvalidAssign(local) => {
+                        self.visit_local(
+                            $(& $mutability)? *local,
+                            PlaceContext::NonUse(NonUseContext::VarDebugInfo),
+                            location
+                        );
+                    }
+                }
+            }
+
             fn super_statement(
                 &mut self,
                 statement: & $($mutability)? Statement<'tcx>,
                 location: Location
             ) {
-                let Statement { source_info, kind } = statement;
+                let Statement { source_info, kind, debuginfos } = statement;
 
                 self.visit_source_info(source_info);
+                for debuginfo in debuginfos as & $($mutability)? [_] {
+                    self.visit_statement_debuginfo(debuginfo, location);
+                }
                 match kind {
                     StatementKind::Assign(box (place, rvalue)) => {
                         self.visit_assign(place, rvalue, location);
@@ -1166,11 +1209,6 @@ macro_rules! visit_place_fns {
                     self.visit_ty(&mut new_ty, TyContext::Location(location));
                     if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
                 }
-                PlaceElem::Subtype(ty) => {
-                    let mut new_ty = ty;
-                    self.visit_ty(&mut new_ty, TyContext::Location(location));
-                    if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
-                }
                 PlaceElem::UnwrapUnsafeBinder(ty) => {
                     let mut new_ty = ty;
                     self.visit_ty(&mut new_ty, TyContext::Location(location));
@@ -1244,7 +1282,6 @@ macro_rules! visit_place_fns {
         ) {
             match elem {
                 ProjectionElem::OpaqueCast(ty)
-                | ProjectionElem::Subtype(ty)
                 | ProjectionElem::Field(_, ty)
                 | ProjectionElem::UnwrapUnsafeBinder(ty) => {
                     self.visit_ty(ty, TyContext::Location(location));
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 614b6471f18..95adb561c70 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -95,7 +95,15 @@ impl<'tcx> Const<'tcx> {
         debruijn: ty::DebruijnIndex,
         bound_const: ty::BoundConst,
     ) -> Const<'tcx> {
-        Const::new(tcx, ty::ConstKind::Bound(debruijn, bound_const))
+        Const::new(tcx, ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const))
+    }
+
+    #[inline]
+    pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Const<'tcx> {
+        Const::new(
+            tcx,
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, ty::BoundConst { var }),
+        )
     }
 
     #[inline]
@@ -180,6 +188,10 @@ impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
         Const::new_bound(tcx, debruijn, ty::BoundConst { var })
     }
 
+    fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
+        Const::new_canonical_bound(tcx, var)
+    }
+
     fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Self {
         Const::new_placeholder(tcx, placeholder)
     }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index fe3fa024cd5..1b89a49cf98 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1110,6 +1110,15 @@ const NUM_PREINTERNED_FRESH_TYS: u32 = 20;
 const NUM_PREINTERNED_FRESH_INT_TYS: u32 = 3;
 const NUM_PREINTERNED_FRESH_FLOAT_TYS: u32 = 3;
 const NUM_PREINTERNED_ANON_BOUND_TYS_I: u32 = 3;
+
+// From general profiling of the *max vars during canonicalization* of a value:
+// - about 90% of the time, there are no canonical vars
+// - about 9% of the time, there is only one canonical var
+// - there are rarely more than 3-5 canonical vars (with exceptions in particularly pathological cases)
+// This may not match the number of bound vars found in `for`s.
+// Given that this is all heap interned, it seems likely that interning fewer
+// vars here won't make an appreciable difference. Though, if we were to inline the data (in an array),
+// we may want to consider reducing the number for canonicalized vars down to 4 or so.
 const NUM_PREINTERNED_ANON_BOUND_TYS_V: u32 = 20;
 
 // This number may seem high, but it is reached in all but the smallest crates.
@@ -1160,9 +1169,14 @@ pub struct CommonTypes<'tcx> {
     pub fresh_float_tys: Vec<Ty<'tcx>>,
 
     /// Pre-interned values of the form:
-    /// `Bound(DebruijnIndex(i), BoundTy { var: v, kind: BoundTyKind::Anon})`
+    /// `Bound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundTy { var: v, kind: BoundTyKind::Anon})`
     /// for small values of `i` and `v`.
     pub anon_bound_tys: Vec<Vec<Ty<'tcx>>>,
+
+    // Pre-interned values of the form:
+    // `Bound(BoundVarIndexKind::Canonical, BoundTy { var: v, kind: BoundTyKind::Anon })`
+    // for small values of `v`.
+    pub anon_canonical_bound_tys: Vec<Ty<'tcx>>,
 }
 
 pub struct CommonLifetimes<'tcx> {
@@ -1176,9 +1190,14 @@ pub struct CommonLifetimes<'tcx> {
     pub re_vars: Vec<Region<'tcx>>,
 
     /// Pre-interned values of the form:
-    /// `ReBound(DebruijnIndex(i), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
+    /// `ReBound(BoundVarIndexKind::Bound(DebruijnIndex(i)), BoundRegion { var: v, kind: BoundRegionKind::Anon })`
     /// for small values of `i` and `v`.
     pub anon_re_bounds: Vec<Vec<Region<'tcx>>>,
+
+    // Pre-interned values of the form:
+    // `ReBound(BoundVarIndexKind::Canonical, BoundRegion { var: v, kind: BoundRegionKind::Anon })`
+    // for small values of `v`.
+    pub anon_re_canonical_bounds: Vec<Region<'tcx>>,
 }
 
 pub struct CommonConsts<'tcx> {
@@ -1211,7 +1230,7 @@ impl<'tcx> CommonTypes<'tcx> {
                 (0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
                     .map(|v| {
                         mk(ty::Bound(
-                            ty::DebruijnIndex::from(i),
+                            ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
                             ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon },
                         ))
                     })
@@ -1219,6 +1238,15 @@ impl<'tcx> CommonTypes<'tcx> {
             })
             .collect();
 
+        let anon_canonical_bound_tys = (0..NUM_PREINTERNED_ANON_BOUND_TYS_V)
+            .map(|v| {
+                mk(ty::Bound(
+                    ty::BoundVarIndexKind::Canonical,
+                    ty::BoundTy { var: ty::BoundVar::from(v), kind: ty::BoundTyKind::Anon },
+                ))
+            })
+            .collect();
+
         CommonTypes {
             unit: mk(Tuple(List::empty())),
             bool: mk(Bool),
@@ -1250,6 +1278,7 @@ impl<'tcx> CommonTypes<'tcx> {
             fresh_int_tys,
             fresh_float_tys,
             anon_bound_tys,
+            anon_canonical_bound_tys,
         }
     }
 }
@@ -1270,7 +1299,7 @@ impl<'tcx> CommonLifetimes<'tcx> {
                 (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
                     .map(|v| {
                         mk(ty::ReBound(
-                            ty::DebruijnIndex::from(i),
+                            ty::BoundVarIndexKind::Bound(ty::DebruijnIndex::from(i)),
                             ty::BoundRegion {
                                 var: ty::BoundVar::from(v),
                                 kind: ty::BoundRegionKind::Anon,
@@ -1281,11 +1310,21 @@ impl<'tcx> CommonLifetimes<'tcx> {
             })
             .collect();
 
+        let anon_re_canonical_bounds = (0..NUM_PREINTERNED_ANON_RE_BOUNDS_V)
+            .map(|v| {
+                mk(ty::ReBound(
+                    ty::BoundVarIndexKind::Canonical,
+                    ty::BoundRegion { var: ty::BoundVar::from(v), kind: ty::BoundRegionKind::Anon },
+                ))
+            })
+            .collect();
+
         CommonLifetimes {
             re_static: mk(ty::ReStatic),
             re_erased: mk(ty::ReErased),
             re_vars,
             anon_re_bounds,
+            anon_re_canonical_bounds,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 7d56ec1635f..ee29afcff63 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -125,7 +125,9 @@ where
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
+                if debruijn == self.current_index =>
+            {
                 let ty = self.delegate.replace_ty(bound_ty);
                 debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST));
                 ty::shift_vars(self.tcx, ty, self.current_index.as_u32())
@@ -146,9 +148,11 @@ where
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         match r.kind() {
-            ty::ReBound(debruijn, br) if debruijn == self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
+                if debruijn == self.current_index =>
+            {
                 let region = self.delegate.replace_region(br);
-                if let ty::ReBound(debruijn1, br) = region.kind() {
+                if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() {
                     // If the callback returns a bound region,
                     // that region should always use the INNERMOST
                     // debruijn index. Then we adjust it to the
@@ -165,7 +169,9 @@ where
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match ct.kind() {
-            ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
+                if debruijn == self.current_index =>
+            {
                 let ct = self.delegate.replace_const(bound_const);
                 debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST));
                 ty::shift_vars(self.tcx, ct, self.current_index.as_u32())
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8f7c8170f7a..4d1fcaeda5e 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2664,7 +2664,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         let name = &mut self.name;
         let region = match r.kind() {
-            ty::ReBound(db, br) if db >= self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(db), br) if db >= self.current_index => {
                 *self.region_map.entry(br).or_insert_with(|| name(Some(db), self.current_index, br))
             }
             ty::RePlaceholder(ty::PlaceholderRegion {
@@ -2687,7 +2687,7 @@ impl<'a, 'tcx> ty::TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> {
             }
             _ => return r,
         };
-        if let ty::ReBound(debruijn1, br) = region.kind() {
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn1), br) = region.kind() {
             assert_eq!(debruijn1, ty::INNERMOST);
             ty::Region::new_bound(self.tcx, self.current_index, br)
         } else {
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 3a7852dea06..f0687f2bc72 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -31,7 +31,7 @@ impl<'tcx> rustc_type_ir::Flags for Region<'tcx> {
 
     fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
         match self.kind() {
-            ty::ReBound(debruijn, _) => debruijn.shifted_in(1),
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
             _ => ty::INNERMOST,
         }
     }
@@ -59,7 +59,20 @@ impl<'tcx> Region<'tcx> {
         {
             re
         } else {
-            tcx.intern_region(ty::ReBound(debruijn, bound_region))
+            tcx.intern_region(ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), bound_region))
+        }
+    }
+
+    #[inline]
+    pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Region<'tcx> {
+        // Use a pre-interned one when possible.
+        if let Some(re) = tcx.lifetimes.anon_re_canonical_bounds.get(var.as_usize()).copied() {
+            re
+        } else {
+            tcx.intern_region(ty::ReBound(
+                ty::BoundVarIndexKind::Canonical,
+                ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
+            ))
         }
     }
 
@@ -122,7 +135,12 @@ impl<'tcx> Region<'tcx> {
     pub fn new_from_kind(tcx: TyCtxt<'tcx>, kind: RegionKind<'tcx>) -> Region<'tcx> {
         match kind {
             ty::ReEarlyParam(region) => Region::new_early_param(tcx, region),
-            ty::ReBound(debruijn, region) => Region::new_bound(tcx, debruijn, region),
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), region) => {
+                Region::new_bound(tcx, debruijn, region)
+            }
+            ty::ReBound(ty::BoundVarIndexKind::Canonical, region) => {
+                Region::new_canonical_bound(tcx, region.var)
+            }
             ty::ReLateParam(ty::LateParamRegion { scope, kind }) => {
                 Region::new_late_param(tcx, scope, kind)
             }
@@ -148,6 +166,10 @@ impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
         Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon })
     }
 
+    fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: rustc_type_ir::BoundVar) -> Self {
+        Region::new_canonical_bound(tcx, var)
+    }
+
     fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderRegion) -> Self {
         Region::new_placeholder(tcx, placeholder)
     }
@@ -223,7 +245,7 @@ impl<'tcx> Region<'tcx> {
     #[inline]
     pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
         match self.kind() {
-            ty::ReBound(debruijn, _) => debruijn >= index,
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) => debruijn >= index,
             _ => false,
         }
     }
@@ -254,7 +276,11 @@ impl<'tcx> Region<'tcx> {
             ty::ReStatic => {
                 flags = flags | TypeFlags::HAS_FREE_REGIONS;
             }
-            ty::ReBound(..) => {
+            ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
+                flags = flags | TypeFlags::HAS_RE_BOUND;
+                flags = flags | TypeFlags::HAS_CANONICAL_BOUND;
+            }
+            ty::ReBound(ty::BoundVarIndexKind::Bound(..), _) => {
                 flags = flags | TypeFlags::HAS_RE_BOUND;
             }
             ty::ReErased => {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index de35e5e847c..a3fdd4e35b6 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -487,7 +487,23 @@ impl<'tcx> Ty<'tcx> {
         {
             ty
         } else {
-            Ty::new(tcx, Bound(index, bound_ty))
+            Ty::new(tcx, Bound(ty::BoundVarIndexKind::Bound(index), bound_ty))
+        }
+    }
+
+    #[inline]
+    pub fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: BoundVar) -> Ty<'tcx> {
+        // Use a pre-interned one when possible.
+        if let Some(ty) = tcx.types.anon_canonical_bound_tys.get(var.as_usize()).copied() {
+            ty
+        } else {
+            Ty::new(
+                tcx,
+                Bound(
+                    ty::BoundVarIndexKind::Canonical,
+                    ty::BoundTy { var, kind: ty::BoundTyKind::Anon },
+                ),
+            )
         }
     }
 
@@ -952,6 +968,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
 
+    fn new_canonical_bound(tcx: TyCtxt<'tcx>, var: ty::BoundVar) -> Self {
+        Ty::new_canonical_bound(tcx, var)
+    }
+
     fn new_alias(
         interner: TyCtxt<'tcx>,
         kind: ty::AliasTyKind,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 944bd9756a9..b276b993ec9 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -798,8 +798,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
                     match arg.kind() {
                         GenericArgKind::Type(ty) => match ty.kind() {
                             ty::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in generic parameters.
-                                assert_eq!(*debruijn, ty::INNERMOST);
+                                // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
+                                assert_eq!(*debruijn, ty::BoundVarIndexKind::Canonical);
                                 cvar == b.var
                             }
                             _ => false,
@@ -807,8 +807,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
 
                         GenericArgKind::Lifetime(r) => match r.kind() {
                             ty::ReBound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in generic parameters.
-                                assert_eq!(debruijn, ty::INNERMOST);
+                                // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
+                                assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical);
                                 cvar == b.var
                             }
                             _ => false,
@@ -816,8 +816,8 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {
 
                         GenericArgKind::Const(ct) => match ct.kind() {
                             ty::ConstKind::Bound(debruijn, b) => {
-                                // We only allow a `ty::INNERMOST` index in generic parameters.
-                                assert_eq!(debruijn, ty::INNERMOST);
+                                // We only allow a `ty::BoundVarIndexKind::Canonical` index in generic parameters.
+                                assert_eq!(debruijn, ty::BoundVarIndexKind::Canonical);
                                 cvar == b.var
                             }
                             _ => false,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index f0c47f257cc..e84ac56b31d 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -78,7 +78,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
                 match r.kind() {
-                    ty::ReBound(debruijn, _) if debruijn < self.outer_index => {
+                    ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
+                        if debruijn < self.outer_index =>
+                    {
                         ControlFlow::Continue(())
                     }
                     _ => {
@@ -205,7 +207,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) {
-        if let ty::ReBound(debruijn, br) = r.kind() {
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) = r.kind() {
             if debruijn == self.current_index {
                 self.regions.insert(br.kind);
             }
diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
index 5a6bd2f413c..5e7a57d51a9 100644
--- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs
@@ -103,7 +103,7 @@ fn convert_to_hir_projections_and_truncate_for_capture(
             }
             ProjectionElem::UnwrapUnsafeBinder(_) => HirProjectionKind::UnwrapUnsafeBinder,
             // These do not affect anything, they just make sure we know the right type.
-            ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
+            ProjectionElem::OpaqueCast(_) => continue,
             ProjectionElem::Index(..)
             | ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Subslice { .. } => {
@@ -802,7 +802,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     ProjectionElem::Field(..)
                     | ProjectionElem::Downcast(..)
                     | ProjectionElem::OpaqueCast(..)
-                    | ProjectionElem::Subtype(..)
                     | ProjectionElem::ConstantIndex { .. }
                     | ProjectionElem::Subslice { .. }
                     | ProjectionElem::UnwrapUnsafeBinder(_) => (),
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 5eba474a60c..f6aaa65ad9f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -210,6 +210,7 @@ impl DefUse {
 /// All of the caveats of `MaybeLiveLocals` apply.
 pub struct MaybeTransitiveLiveLocals<'a> {
     always_live: &'a DenseBitSet<Local>,
+    debuginfo_locals: &'a DenseBitSet<Local>,
 }
 
 impl<'a> MaybeTransitiveLiveLocals<'a> {
@@ -217,8 +218,48 @@ impl<'a> MaybeTransitiveLiveLocals<'a> {
     /// considered live.
     ///
     /// This should include at least all locals that are ever borrowed.
-    pub fn new(always_live: &'a DenseBitSet<Local>) -> Self {
-        MaybeTransitiveLiveLocals { always_live }
+    pub fn new(
+        always_live: &'a DenseBitSet<Local>,
+        debuginfo_locals: &'a DenseBitSet<Local>,
+    ) -> Self {
+        MaybeTransitiveLiveLocals { always_live, debuginfo_locals }
+    }
+
+    pub fn can_be_removed_if_dead<'tcx>(
+        stmt_kind: &StatementKind<'tcx>,
+        always_live: &DenseBitSet<Local>,
+        debuginfo_locals: &'a DenseBitSet<Local>,
+    ) -> Option<Place<'tcx>> {
+        // Compute the place that we are storing to, if any
+        let destination = match stmt_kind {
+            StatementKind::Assign(box (place, rvalue)) => (rvalue.is_safe_to_remove()
+                // FIXME: We are not sure how we should represent this debugging information for some statements,
+                // keep it for now.
+                && (!debuginfo_locals.contains(place.local)
+                    || (place.as_local().is_some() && stmt_kind.as_debuginfo().is_some())))
+            .then_some(*place),
+            StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
+                (!debuginfo_locals.contains(place.local)).then_some(**place)
+            }
+            StatementKind::FakeRead(_)
+            | StatementKind::StorageLive(_)
+            | StatementKind::StorageDead(_)
+            | StatementKind::Retag(..)
+            | StatementKind::AscribeUserType(..)
+            | StatementKind::PlaceMention(..)
+            | StatementKind::Coverage(..)
+            | StatementKind::Intrinsic(..)
+            | StatementKind::ConstEvalCounter
+            | StatementKind::BackwardIncompatibleDropHint { .. }
+            | StatementKind::Nop => None,
+        };
+        if let Some(destination) = destination
+            && !destination.is_indirect()
+            && !always_live.contains(destination.local)
+        {
+            return Some(destination);
+        }
+        None
     }
 }
 
@@ -243,32 +284,12 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         statement: &mir::Statement<'tcx>,
         location: Location,
     ) {
-        // Compute the place that we are storing to, if any
-        let destination = match &statement.kind {
-            StatementKind::Assign(assign) => assign.1.is_safe_to_remove().then_some(assign.0),
-            StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
-                Some(**place)
-            }
-            StatementKind::FakeRead(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::Retag(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::Intrinsic(..)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::BackwardIncompatibleDropHint { .. }
-            | StatementKind::Nop => None,
-        };
-        if let Some(destination) = destination {
-            if !destination.is_indirect()
-                && !state.contains(destination.local)
-                && !self.always_live.contains(destination.local)
-            {
-                // This store is dead
-                return;
-            }
+        if let Some(destination) =
+            Self::can_be_removed_if_dead(&statement.kind, &self.always_live, &self.debuginfo_locals)
+            && !state.contains(destination.local)
+        {
+            // This store is dead
+            return;
         }
         TransferFunction(state).visit_statement(statement, location);
     }
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 72d4cd72c2b..434f106302f 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -227,11 +227,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
                 ProjectionElem::UnwrapUnsafeBinder(_) => {}
                 // `OpaqueCast`:Only transmutes the type, so no moves there.
                 // `Downcast`  :Only changes information about a `Place` without moving.
-                // `Subtype`   :Only transmutes the type, so moves.
                 // So it's safe to skip these.
-                ProjectionElem::OpaqueCast(_)
-                | ProjectionElem::Subtype(_)
-                | ProjectionElem::Downcast(_, _) => (),
+                ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (),
             }
             let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
             if !(self.filter)(elem_ty) {
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index be4f84d64d0..a6a60fddf90 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -40,8 +40,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
                 .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span);
             let new_place = Place::from(temp);
             self.patcher.add_assign(location, new_place, rvalue.clone());
-            let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx);
-            *rvalue = Rvalue::Use(Operand::Move(subtyped));
+            *rvalue = Rvalue::Cast(CastKind::Subtype, Operand::Move(new_place), place_ty);
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 4be67b873f7..b0bf7f484be 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -36,7 +36,9 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
                         CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
                     )
                     | StatementKind::FakeRead(..)
-                    | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(),
+                    | StatementKind::BackwardIncompatibleDropHint { .. } => {
+                        statement.make_nop(true)
+                    }
                     StatementKind::Assign(box (
                         _,
                         Rvalue::Cast(
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index cddeefca681..f0bc286a940 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -138,7 +138,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
         if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind
             && self.storage_to_remove.contains(l)
         {
-            stmt.make_nop();
+            stmt.make_nop(true);
             return;
         }
 
@@ -150,7 +150,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
                 *rhs
             && lhs == rhs
         {
-            stmt.make_nop();
+            stmt.make_nop(true);
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index c5cd06f170c..814eded910d 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -411,7 +411,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
             if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = s.kind
                 && self.remap.contains(l)
             {
-                s.make_nop();
+                s.make_nop(true);
             }
         }
 
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 491e910ff6f..e970f7ff81a 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -440,7 +440,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
                     FlatSet::Top => FlatSet::Top,
                 }
             }
-            Rvalue::Cast(CastKind::Transmute, operand, _) => {
+            Rvalue::Cast(CastKind::Transmute | CastKind::Subtype, operand, _) => {
                 match self.eval_operand(operand, state) {
                     FlatSet::Elem(op) => self.wrap_immediate(*op),
                     FlatSet::Bottom => FlatSet::Bottom,
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index eea2b0990d7..732c3dcd44a 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -22,21 +22,22 @@ use rustc_mir_dataflow::impls::{
     LivenessTransferFunction, MaybeTransitiveLiveLocals, borrowed_locals,
 };
 
+use crate::simplify::UsedInStmtLocals;
 use crate::util::is_within_packed;
 
 /// Performs the optimization on the body
 ///
 /// The `borrowed` set must be a `DenseBitSet` of all the locals that are ever borrowed in this
 /// body. It can be generated via the [`borrowed_locals`] function.
-fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+/// Returns true if any instruction is eliminated.
+fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     let borrowed_locals = borrowed_locals(body);
 
     // If the user requests complete debuginfo, mark the locals that appear in it as live, so
     // we don't remove assignments to them.
-    let mut always_live = debuginfo_locals(body);
-    always_live.union(&borrowed_locals);
+    let debuginfo_locals = debuginfo_locals(body);
 
-    let mut live = MaybeTransitiveLiveLocals::new(&always_live)
+    let mut live = MaybeTransitiveLiveLocals::new(&borrowed_locals, &debuginfo_locals)
         .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
@@ -75,47 +76,36 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
-            let loc = Location { block: bb, statement_index };
-            if let StatementKind::Assign(assign) = &statement.kind {
-                if !assign.1.is_safe_to_remove() {
-                    continue;
-                }
-            }
-            match &statement.kind {
-                StatementKind::Assign(box (place, _))
-                | StatementKind::SetDiscriminant { place: box place, .. }
-                | StatementKind::Deinit(box place) => {
-                    if !place.is_indirect() && !always_live.contains(place.local) {
-                        live.seek_before_primary_effect(loc);
-                        if !live.get().contains(place.local) {
-                            patch.push(loc);
-                        }
-                    }
-                }
-                StatementKind::Retag(_, _)
-                | StatementKind::StorageLive(_)
-                | StatementKind::StorageDead(_)
-                | StatementKind::Coverage(_)
-                | StatementKind::Intrinsic(_)
-                | StatementKind::ConstEvalCounter
-                | StatementKind::PlaceMention(_)
-                | StatementKind::BackwardIncompatibleDropHint { .. }
-                | StatementKind::Nop => {}
-
-                StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
-                    bug!("{:?} not found in this MIR phase!", statement.kind)
+            if let Some(destination) = MaybeTransitiveLiveLocals::can_be_removed_if_dead(
+                &statement.kind,
+                &borrowed_locals,
+                &debuginfo_locals,
+            ) {
+                let loc = Location { block: bb, statement_index };
+                live.seek_before_primary_effect(loc);
+                if !live.get().contains(destination.local) {
+                    let drop_debuginfo = !debuginfo_locals.contains(destination.local);
+                    // When eliminating a dead statement, we need to address
+                    // the debug information for that statement.
+                    assert!(
+                        drop_debuginfo || statement.kind.as_debuginfo().is_some(),
+                        "don't know how to retain the debug information for {:?}",
+                        statement.kind
+                    );
+                    patch.push((loc, drop_debuginfo));
                 }
             }
         }
     }
 
     if patch.is_empty() && call_operands_to_move.is_empty() {
-        return;
+        return false;
     }
+    let eliminated = !patch.is_empty();
 
     let bbs = body.basic_blocks.as_mut_preserves_cfg();
-    for Location { block, statement_index } in patch {
-        bbs[block].statements[statement_index].make_nop();
+    for (Location { block, statement_index }, drop_debuginfo) in patch {
+        bbs[block].statements[statement_index].make_nop(drop_debuginfo);
     }
     for (block, argument_index) in call_operands_to_move {
         let TerminatorKind::Call { ref mut args, .. } = bbs[block].terminator_mut().kind else {
@@ -125,6 +115,8 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let Operand::Copy(place) = *arg else { bug!() };
         *arg = Operand::Move(place);
     }
+
+    eliminated
 }
 
 pub(super) enum DeadStoreElimination {
@@ -145,7 +137,12 @@ impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        eliminate(tcx, body);
+        if eliminate(tcx, body) {
+            UsedInStmtLocals::new(body).remove_unused_storage_annotations(body);
+            for data in body.basic_blocks.as_mut_preserves_cfg() {
+                data.strip_nops();
+            }
+        }
     }
 
     fn is_required(&self) -> bool {
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 74c22ff10c1..1f38433fa5a 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -276,7 +276,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
             StatementKind::StorageDead(local) | StatementKind::StorageLive(local)
                 if self.merged_locals.contains(*local) =>
             {
-                statement.make_nop();
+                statement.make_nop(true);
                 return;
             }
             _ => (),
@@ -291,7 +291,7 @@ impl<'tcx> MutVisitor<'tcx> for Merger<'tcx> {
                         // (this includes the original statement we wanted to eliminate).
                         if dest == place {
                             debug!("{:?} turned into self-assignment, deleting", location);
-                            statement.make_nop();
+                            statement.make_nop(true);
                         }
                     }
                     _ => {}
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 29f6879aacd..3ff8dc6dbb3 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -656,7 +656,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     let res = self.ecx.float_to_float_or_int(&value, ty).discard_err()?;
                     res.into()
                 }
-                CastKind::Transmute => {
+                CastKind::Transmute | CastKind::Subtype => {
                     let value = self.evaluated[value].as_ref()?;
                     // `offset` for immediates generally only supports projections that match the
                     // type of the immediate. However, as a HACK, we exploit that it can also do
@@ -788,7 +788,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 ProjectionElem::Subslice { from, to, from_end }
             }
             ProjectionElem::OpaqueCast(_) => ProjectionElem::OpaqueCast(()),
-            ProjectionElem::Subtype(_) => ProjectionElem::Subtype(()),
             ProjectionElem::UnwrapUnsafeBinder(_) => ProjectionElem::UnwrapUnsafeBinder(()),
         };
 
@@ -1878,7 +1877,7 @@ impl<'tcx> MutVisitor<'tcx> for StorageRemover<'tcx> {
             StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
                 if self.reused_locals.contains(l) =>
             {
-                stmt.make_nop()
+                stmt.make_nop(true)
             }
             _ => self.super_statement(stmt, loc),
         }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 3d49eb4e8ef..8593e25d6aa 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -21,7 +21,7 @@ use tracing::{debug, instrument, trace, trace_span};
 
 use crate::cost_checker::{CostChecker, is_call_like};
 use crate::deref_separator::deref_finder;
-use crate::simplify::simplify_cfg;
+use crate::simplify::{UsedInStmtLocals, simplify_cfg};
 use crate::validate::validate_types;
 use crate::{check_inline, util};
 
@@ -935,7 +935,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
         in_cleanup_block: false,
         return_block,
         tcx,
-        always_live_locals: DenseBitSet::new_filled(callee_body.local_decls.len()),
+        always_live_locals: UsedInStmtLocals::new(&callee_body).locals,
     };
 
     // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
@@ -995,6 +995,10 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
         // people working on rust can build with or without debuginfo while
         // still getting consistent results from the mir-opt tests.
         caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
+    } else {
+        for bb in callee_body.basic_blocks_mut() {
+            bb.drop_debuginfo();
+        }
     }
     caller_body.basic_blocks_mut().append(callee_body.basic_blocks_mut());
 
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 5fffba55f17..93abc0f8860 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -637,7 +637,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?;
                     res.into()
                 }
-                CastKind::Transmute => {
+                CastKind::Transmute | CastKind::Subtype => {
                     let value = self.eval_operand(value)?;
                     let to = self.ecx.layout_of(to).ok()?;
                     // `offset` for immediates only supports scalar/scalar-pair ABIs,
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 1a91d6bd7da..1b90e9158f6 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -156,7 +156,7 @@ impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
                     patch.add_statement(location, stmt);
                 }
 
-                st.make_nop();
+                st.make_nop(true);
             }
         }
 
diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs
index cc8ea76011b..2c535d011a0 100644
--- a/compiler/rustc_mir_transform/src/patch.rs
+++ b/compiler/rustc_mir_transform/src/patch.rs
@@ -270,7 +270,7 @@ impl<'tcx> MirPatch<'tcx> {
         body.local_decls.extend(self.new_locals);
 
         for loc in self.nop_statements {
-            bbs[loc.block].statements[loc.statement_index].make_nop();
+            bbs[loc.block].statements[loc.statement_index].make_nop(true);
         }
 
         let mut new_statements = self.new_statements;
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index a0b0c8c990f..c7dc18a4a13 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -292,7 +292,6 @@ impl<'tcx> Validator<'_, 'tcx> {
         match elem {
             // Recurse directly.
             ProjectionElem::ConstantIndex { .. }
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::UnwrapUnsafeBinder(_) => {}
 
@@ -1050,7 +1049,7 @@ fn promote_candidates<'tcx>(
     // Eliminate assignments to, and drops of promoted temps.
     let promoted = |index: Local| temps[index] == TempState::PromotedOut;
     for block in body.basic_blocks_mut() {
-        block.statements.retain(|statement| match &statement.kind {
+        block.retain_statements(|statement| match &statement.kind {
             StatementKind::Assign(box (place, _)) => {
                 if let Some(index) = place.as_local() {
                     !promoted(index)
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index b9d6e74ecae..deb0a146476 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -435,7 +435,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
             StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
                 if self.storage_to_remove.contains(l) =>
             {
-                stmt.make_nop();
+                stmt.make_nop(true);
             }
             // Do not remove assignments as they may still be useful for debuginfo.
             _ => self.super_statement(stmt, loc),
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index cb598ceb4df..d56b51bb496 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
     fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemovePlaceMention on {:?}", body.source);
         for data in body.basic_blocks.as_mut_preserves_cfg() {
-            data.statements.retain(|statement| match statement.kind {
+            data.retain_statements(|statement| match statement.kind {
                 StatementKind::PlaceMention(..) | StatementKind::Nop => false,
                 _ => true,
             })
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index 1ae33c00968..cb97d2c865a 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -14,7 +14,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveStorageMarkers on {:?}", body.source);
         for data in body.basic_blocks.as_mut_preserves_cfg() {
-            data.statements.retain(|statement| match statement.kind {
+            data.retain_statements(|statement| match statement.kind {
                 StatementKind::StorageLive(..)
                 | StatementKind::StorageDead(..)
                 | StatementKind::Nop => false,
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index c4dc8638b26..90c1b3520b9 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -141,7 +141,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
             && let ty = place_for_ty.ty(self.local_decls, self.tcx).ty
             && self.known_to_be_zst(ty)
         {
-            statement.make_nop();
+            statement.make_nop(true);
         } else {
             self.super_statement(statement, loc);
         }
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 75917d23883..8b5efb74205 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -35,10 +35,12 @@
 //! pre-"runtime" MIR!
 
 use itertools::Itertools as _;
+use rustc_index::bit_set::DenseBitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::debuginfo::debuginfo_locals;
 use rustc_span::DUMMY_SP;
 use smallvec::SmallVec;
 use tracing::{debug, trace};
@@ -142,7 +144,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
         // statements itself to avoid moving the (relatively) large statements twice.
         // We do not push the statements directly into the target block (`bb`) as that is slower
         // due to additional reallocations
-        let mut merged_blocks = Vec::new();
+        let mut merged_blocks: Vec<BasicBlock> = Vec::new();
         let mut outer_changed = false;
         loop {
             let mut changed = false;
@@ -157,8 +159,9 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
                 let mut terminator =
                     self.basic_blocks[bb].terminator.take().expect("invalid terminator state");
 
-                terminator
-                    .successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed));
+                terminator.successors_mut(|successor| {
+                    self.collapse_goto_chain(successor, &mut changed);
+                });
 
                 let mut inner_changed = true;
                 merged_blocks.clear();
@@ -175,10 +178,18 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
                 if statements_to_merge > 0 {
                     let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements);
                     statements.reserve(statements_to_merge);
+                    let mut parent_bb_last_debuginfos =
+                        std::mem::take(&mut self.basic_blocks[bb].after_last_stmt_debuginfos);
                     for &from in &merged_blocks {
+                        if let Some(stmt) = self.basic_blocks[from].statements.first_mut() {
+                            stmt.debuginfos.prepend(&mut parent_bb_last_debuginfos);
+                        }
                         statements.append(&mut self.basic_blocks[from].statements);
+                        parent_bb_last_debuginfos =
+                            std::mem::take(&mut self.basic_blocks[from].after_last_stmt_debuginfos);
                     }
                     self.basic_blocks[bb].statements = statements;
+                    self.basic_blocks[bb].after_last_stmt_debuginfos = parent_bb_last_debuginfos;
                 }
 
                 self.basic_blocks[bb].terminator = Some(terminator);
@@ -218,10 +229,14 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
         // goto chains. We should probably benchmark different sizes.
         let mut terminators: SmallVec<[_; 1]> = Default::default();
         let mut current = *start;
+        // If each successor has only one predecessor, it's a trivial goto chain.
+        // We can move all debuginfos to the last basic block.
+        let mut trivial_goto_chain = true;
         while let Some(terminator) = self.take_terminator_if_simple_goto(current) {
             let Terminator { kind: TerminatorKind::Goto { target }, .. } = terminator else {
                 unreachable!();
             };
+            trivial_goto_chain &= self.pred_count[target] == 1;
             terminators.push((current, terminator));
             current = target;
         }
@@ -233,6 +248,17 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
             else {
                 unreachable!();
             };
+            if trivial_goto_chain {
+                let mut pred_debuginfos =
+                    std::mem::take(&mut self.basic_blocks[current].after_last_stmt_debuginfos);
+                let debuginfos = if let Some(stmt) = self.basic_blocks[last].statements.first_mut()
+                {
+                    &mut stmt.debuginfos
+                } else {
+                    &mut self.basic_blocks[last].after_last_stmt_debuginfos
+                };
+                debuginfos.prepend(&mut pred_debuginfos);
+            }
             *changed |= *target != last;
             *target = last;
             debug!("collapsing goto chain from {:?} to {:?}", current, target);
@@ -303,7 +329,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
 
     fn strip_nops(&mut self) {
         for blk in self.basic_blocks.iter_mut() {
-            blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop))
+            blk.strip_nops();
         }
     }
 }
@@ -476,17 +502,22 @@ fn make_local_map<V>(
 /// Keeps track of used & unused locals.
 struct UsedLocals {
     increment: bool,
-    arg_count: u32,
     use_count: IndexVec<Local, u32>,
+    always_used: DenseBitSet<Local>,
 }
 
 impl UsedLocals {
     /// Determines which locals are used & unused in the given body.
     fn new(body: &Body<'_>) -> Self {
+        let mut always_used = debuginfo_locals(body);
+        always_used.insert(RETURN_PLACE);
+        for arg in body.args_iter() {
+            always_used.insert(arg);
+        }
         let mut this = Self {
             increment: true,
-            arg_count: body.arg_count.try_into().unwrap(),
             use_count: IndexVec::from_elem(0, &body.local_decls),
+            always_used,
         };
         this.visit_body(body);
         this
@@ -494,10 +525,16 @@ impl UsedLocals {
 
     /// Checks if local is used.
     ///
-    /// Return place and arguments are always considered used.
+    /// Return place, arguments, var debuginfo are always considered used.
     fn is_used(&self, local: Local) -> bool {
-        trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]);
-        local.as_u32() <= self.arg_count || self.use_count[local] != 0
+        trace!(
+            "is_used({:?}): use_count: {:?}, always_used: {}",
+            local,
+            self.use_count[local],
+            self.always_used.contains(local)
+        );
+        // To keep things simple, we don't handle debugging information here, these are in DSE.
+        self.always_used.contains(local) || self.use_count[local] != 0
     }
 
     /// Updates the use counts to reflect the removal of given statement.
@@ -539,10 +576,10 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
                 self.super_statement(statement, location);
             }
 
-            StatementKind::ConstEvalCounter | StatementKind::Nop => {}
-
-            StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
-
+            StatementKind::ConstEvalCounter
+            | StatementKind::Nop
+            | StatementKind::StorageLive(..)
+            | StatementKind::StorageDead(..) => {}
             StatementKind::Assign(box (ref place, ref rvalue)) => {
                 if rvalue.is_safe_to_remove() {
                     self.visit_lhs(place, location);
@@ -560,7 +597,10 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
         }
     }
 
-    fn visit_local(&mut self, local: Local, _ctx: PlaceContext, _location: Location) {
+    fn visit_local(&mut self, local: Local, ctx: PlaceContext, _location: Location) {
+        if matches!(ctx, PlaceContext::NonUse(_)) {
+            return;
+        }
         if self.increment {
             self.use_count[local] += 1;
         } else {
@@ -583,28 +623,26 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod
 
         for data in body.basic_blocks.as_mut_preserves_cfg() {
             // Remove unnecessary StorageLive and StorageDead annotations.
-            data.statements.retain(|statement| {
-                let keep = match &statement.kind {
+            for statement in data.statements.iter_mut() {
+                let keep_statement = match &statement.kind {
                     StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
                         used_locals.is_used(*local)
                     }
-                    StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
-
-                    StatementKind::SetDiscriminant { place, .. }
-                    | StatementKind::BackwardIncompatibleDropHint { place, reason: _ }
-                    | StatementKind::Deinit(place) => used_locals.is_used(place.local),
-                    StatementKind::Nop => false,
-                    _ => true,
+                    StatementKind::Assign(box (place, _))
+                    | StatementKind::SetDiscriminant { box place, .. }
+                    | StatementKind::BackwardIncompatibleDropHint { box place, .. }
+                    | StatementKind::Deinit(box place) => used_locals.is_used(place.local),
+                    _ => continue,
                 };
-
-                if !keep {
-                    trace!("removing statement {:?}", statement);
-                    modified = true;
-                    used_locals.statement_removed(statement);
+                if keep_statement {
+                    continue;
                 }
-
-                keep
-            });
+                trace!("removing statement {:?}", statement);
+                modified = true;
+                used_locals.statement_removed(statement);
+                statement.make_nop(true);
+            }
+            data.strip_nops();
         }
     }
 }
@@ -619,7 +657,62 @@ impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
         self.tcx
     }
 
+    fn visit_statement_debuginfo(
+        &mut self,
+        stmt_debuginfo: &mut StmtDebugInfo<'tcx>,
+        location: Location,
+    ) {
+        match stmt_debuginfo {
+            StmtDebugInfo::AssignRef(local, place) => {
+                if place.as_ref().accessed_locals().any(|local| self.map[local].is_none()) {
+                    *stmt_debuginfo = StmtDebugInfo::InvalidAssign(*local);
+                }
+            }
+            StmtDebugInfo::InvalidAssign(_) => {}
+        }
+        self.super_statement_debuginfo(stmt_debuginfo, location);
+    }
+
     fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
         *l = self.map[*l].unwrap();
     }
 }
+
+pub(crate) struct UsedInStmtLocals {
+    pub(crate) locals: DenseBitSet<Local>,
+}
+
+impl UsedInStmtLocals {
+    pub(crate) fn new(body: &Body<'_>) -> Self {
+        let mut this = Self { locals: DenseBitSet::new_empty(body.local_decls.len()) };
+        this.visit_body(body);
+        this
+    }
+
+    pub(crate) fn remove_unused_storage_annotations<'tcx>(&self, body: &mut Body<'tcx>) {
+        for data in body.basic_blocks.as_mut_preserves_cfg() {
+            // Remove unnecessary StorageLive and StorageDead annotations.
+            for statement in data.statements.iter_mut() {
+                let keep_statement = match &statement.kind {
+                    StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
+                        self.locals.contains(*local)
+                    }
+                    _ => continue,
+                };
+                if keep_statement {
+                    continue;
+                }
+                statement.make_nop(true);
+            }
+        }
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for UsedInStmtLocals {
+    fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
+        if matches!(context, PlaceContext::NonUse(_)) {
+            return;
+        }
+        self.locals.insert(local);
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index c60eb566521..4597439e269 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -76,7 +76,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
             // delete comparison statement if it the value being switched on was moved, which means
             // it can not be user later on
             if opt.can_remove_bin_op_stmt {
-                bb.statements[opt.bin_op_stmt_idx].make_nop();
+                bb.statements[opt.bin_op_stmt_idx].make_nop(true);
             } else {
                 // if the integer being compared to a const integral is being moved into the
                 // comparison, e.g `_2 = Eq(move _3, const 'x');`
@@ -136,7 +136,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
         }
 
         for (idx, bb_idx) in storage_deads_to_remove {
-            body.basic_blocks_mut()[bb_idx].statements[idx].make_nop();
+            body.basic_blocks_mut()[bb_idx].statements[idx].make_nop(true);
         }
 
         for (idx, stmt) in storage_deads_to_insert {
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 38769885f36..99f10b8d91d 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -318,7 +318,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
                     for (_, _, fl) in final_locals {
                         self.patch.add_statement(location, StatementKind::StorageLive(fl));
                     }
-                    statement.make_nop();
+                    statement.make_nop(true);
                 }
                 return;
             }
@@ -327,7 +327,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
                     for (_, _, fl) in final_locals {
                         self.patch.add_statement(location, StatementKind::StorageDead(fl));
                     }
-                    statement.make_nop();
+                    statement.make_nop(true);
                 }
                 return;
             }
@@ -337,7 +337,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
                         self.patch
                             .add_statement(location, StatementKind::Deinit(Box::new(fl.into())));
                     }
-                    statement.make_nop();
+                    statement.make_nop(true);
                     return;
                 }
             }
@@ -367,7 +367,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
                             );
                         }
                     }
-                    statement.make_nop();
+                    statement.make_nop(true);
                     return;
                 }
             }
@@ -429,7 +429,7 @@ impl<'tcx, 'll> MutVisitor<'tcx> for ReplacementVisitor<'tcx, 'll> {
                             StatementKind::Assign(Box::new((new_local.into(), rvalue))),
                         );
                     }
-                    statement.make_nop();
+                    statement.make_nop(true);
                     return;
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/strip_debuginfo.rs b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
index 9ede8aa79c4..7fec25ccb52 100644
--- a/compiler/rustc_mir_transform/src/strip_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/strip_debuginfo.rs
@@ -1,5 +1,6 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::debuginfo::debuginfo_locals;
 use rustc_session::config::MirStripDebugInfo;
 
 /// Conditionally remove some of the VarDebugInfo in MIR.
@@ -30,6 +31,22 @@ impl<'tcx> crate::MirPass<'tcx> for StripDebugInfo {
                     if place.local.as_usize() <= body.arg_count && place.local != RETURN_PLACE,
             )
         });
+
+        let debuginfo_locals = debuginfo_locals(body);
+        for data in body.basic_blocks.as_mut_preserves_cfg() {
+            for stmt in data.statements.iter_mut() {
+                stmt.debuginfos.retain(|debuginfo| match debuginfo {
+                    StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => {
+                        debuginfo_locals.contains(*local)
+                    }
+                });
+            }
+            data.after_last_stmt_debuginfos.retain(|debuginfo| match debuginfo {
+                StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => {
+                    debuginfo_locals.contains(*local)
+                }
+            });
+        }
     }
 
     fn is_required(&self) -> bool {
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index c8a9a88dc3f..cbabb982df8 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -814,22 +814,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                     }
                 }
             }
-            ProjectionElem::Subtype(ty) => {
-                if !util::sub_types(
-                    self.tcx,
-                    self.typing_env,
-                    ty,
-                    place_ref.ty(&self.body.local_decls, self.tcx).ty,
-                ) {
-                    self.fail(
-                        location,
-                        format!(
-                            "Failed subtyping {ty} and {}",
-                            place_ref.ty(&self.body.local_decls, self.tcx).ty
-                        ),
-                    )
-                }
-            }
             ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
                 let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx);
                 let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else {
@@ -1331,6 +1315,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                             );
                         }
                     }
+                    CastKind::Subtype => {
+                        if !util::sub_types(self.tcx, self.typing_env, op_ty, *target_type) {
+                            self.fail(
+                                location,
+                                format!("Failed subtyping {op_ty} and {target_type}"),
+                            )
+                        }
+                    }
                 }
             }
             Rvalue::NullaryOp(NullOp::OffsetOf(indices), container) => {
diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
index b25671d676b..9162284422d 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs
@@ -74,12 +74,10 @@ pub(super) struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner
     /// we set the `sub_root` of the second variable to the position of the first.
     /// Otherwise the `sub_root` of each type variable is just its own position.
     sub_root_lookup_table: HashMap<ty::TyVid, usize>,
-    binder_index: ty::DebruijnIndex,
 
-    /// We only use the debruijn index during lookup. We don't need to
-    /// track the `variables` as each generic arg only results in a single
-    /// bound variable regardless of how many times it is encountered.
-    cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>,
+    /// We can simply cache based on the ty itself, because we use
+    /// `ty::BoundVarIndexKind::Canonical`.
+    cache: HashMap<I::Ty, I::Ty>,
 }
 
 impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
@@ -97,7 +95,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             variable_lookup_table: Default::default(),
             sub_root_lookup_table: Default::default(),
             var_kinds: Vec::new(),
-            binder_index: ty::INNERMOST,
 
             cache: Default::default(),
         };
@@ -141,12 +138,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                         variable_lookup_table: Default::default(),
                         sub_root_lookup_table: Default::default(),
                         var_kinds: Vec::new(),
-                        binder_index: ty::INNERMOST,
 
                         cache: Default::default(),
                     };
                     let param_env = param_env.fold_with(&mut env_canonicalizer);
-                    debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
                     debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
                     CanonicalParamEnvCacheEntry {
                         param_env,
@@ -175,12 +170,10 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
                 variable_lookup_table: Default::default(),
                 sub_root_lookup_table: Default::default(),
                 var_kinds: Vec::new(),
-                binder_index: ty::INNERMOST,
 
                 cache: Default::default(),
             };
             let param_env = param_env.fold_with(&mut env_canonicalizer);
-            debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
             debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
             (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds)
         }
@@ -212,7 +205,6 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
             variable_lookup_table,
             sub_root_lookup_table: Default::default(),
             var_kinds,
-            binder_index: ty::INNERMOST,
 
             // We do not reuse the cache as it may contain entries whose canonicalized
             // value contains `'static`. While we could alternatively handle this by
@@ -409,7 +401,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
 
         let var = self.get_or_insert_bound_var(t, kind);
 
-        Ty::new_anon_bound(self.cx(), self.binder_index, var)
+        Ty::new_canonical_bound(self.cx(), var)
     }
 }
 
@@ -418,16 +410,6 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
         self.delegate.cx()
     }
 
-    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
-    where
-        T: TypeFoldable<I>,
-    {
-        self.binder_index.shift_in(1);
-        let t = t.super_fold_with(self);
-        self.binder_index.shift_out(1);
-        t
-    }
-
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         let kind = match r.kind() {
             ty::ReBound(..) => return r,
@@ -491,15 +473,15 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
 
         let var = self.get_or_insert_bound_var(r, kind);
 
-        Region::new_anon_bound(self.cx(), self.binder_index, var)
+        Region::new_canonical_bound(self.cx(), var)
     }
 
     fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
-        if let Some(&ty) = self.cache.get(&(self.binder_index, t)) {
+        if let Some(&ty) = self.cache.get(&t) {
             ty
         } else {
             let res = self.inner_fold_ty(t);
-            let old = self.cache.insert((self.binder_index, t), res);
+            let old = self.cache.insert(t, res);
             assert_eq!(old, None);
             res
         }
@@ -552,7 +534,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
 
         let var = self.get_or_insert_bound_var(c, kind);
 
-        Const::new_anon_bound(self.cx(), self.binder_index, var)
+        Const::new_canonical_bound(self.cx(), var)
     }
 
     fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate {
diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
index b036ee6df7e..b4cea8701d8 100644
--- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs
@@ -165,25 +165,25 @@ where
                 // and only use it for placeholders. We need to handle the
                 // `sub_root` of type inference variables which would make this
                 // more involved. They are also a lot rarer than region variables.
-                if let ty::Bound(debruijn, b) = t.kind()
+                if let ty::Bound(index_kind, b) = t.kind()
                     && !matches!(
                         response.variables.get(b.var().as_usize()).unwrap(),
                         CanonicalVarKind::Ty { .. }
                     )
                 {
-                    assert_eq!(debruijn, ty::INNERMOST);
+                    assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                     opt_values[b.var()] = Some(*original_value);
                 }
             }
             ty::GenericArgKind::Lifetime(r) => {
-                if let ty::ReBound(debruijn, br) = r.kind() {
-                    assert_eq!(debruijn, ty::INNERMOST);
+                if let ty::ReBound(index_kind, br) = r.kind() {
+                    assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                     opt_values[br.var()] = Some(*original_value);
                 }
             }
             ty::GenericArgKind::Const(c) => {
-                if let ty::ConstKind::Bound(debruijn, bv) = c.kind() {
-                    assert_eq!(debruijn, ty::INNERMOST);
+                if let ty::ConstKind::Bound(index_kind, bv) = c.kind() {
+                    assert!(matches!(index_kind, ty::BoundVarIndexKind::Canonical));
                     opt_values[bv.var()] = Some(*original_value);
                 }
             }
diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs
index c88fb8defae..c8016759f23 100644
--- a/compiler/rustc_next_trait_solver/src/placeholder.rs
+++ b/compiler/rustc_next_trait_solver/src/placeholder.rs
@@ -90,7 +90,7 @@ where
 
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         match r.kind() {
-            ty::ReBound(debruijn, _)
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
                 if debruijn.as_usize()
                     >= self.current_index.as_usize() + self.universe_indices.len() =>
             {
@@ -99,7 +99,9 @@ where
                     self.universe_indices
                 );
             }
-            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
+                if debruijn >= self.current_index =>
+            {
                 let universe = self.universe_for(debruijn);
                 let p = PlaceholderLike::new(universe, br);
                 self.mapped_regions.insert(p, br);
@@ -111,7 +113,7 @@ where
 
     fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
         match t.kind() {
-            ty::Bound(debruijn, _)
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
@@ -120,7 +122,9 @@ where
                     self.universe_indices
                 );
             }
-            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
+                if debruijn >= self.current_index =>
+            {
                 let universe = self.universe_for(debruijn);
                 let p = PlaceholderLike::new(universe, bound_ty);
                 self.mapped_types.insert(p, bound_ty);
@@ -133,7 +137,7 @@ where
 
     fn fold_const(&mut self, ct: I::Const) -> I::Const {
         match ct.kind() {
-            ty::ConstKind::Bound(debruijn, _)
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _)
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
@@ -142,7 +146,9 @@ where
                     self.universe_indices
                 );
             }
-            ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_const)
+                if debruijn >= self.current_index =>
+            {
                 let universe = self.universe_for(debruijn);
                 let p = PlaceholderLike::new(universe, bound_const);
                 self.mapped_consts.insert(p, bound_const);
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index a2e6ef6f0fe..d58c264841c 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -473,7 +473,10 @@ where
         // fails to reach a fixpoint but ends up getting an error after
         // running for some additional step.
         //
-        // cc trait-system-refactor-initiative#105
+        // FIXME(@lcnr): While I believe an error here to be possible, we
+        // currently don't have any test which actually triggers it. @lqd
+        // created a minimization for an ICE in typenum, but that one no
+        // longer fails here. cc trait-system-refactor-initiative#105.
         let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
         let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
         self.probe_trait_candidate(source)
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a28af7833c3..8b87e4d9690 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2748,28 +2748,7 @@ impl<'a> Parser<'a> {
         if token::Colon != self.token.kind {
             return first_pat;
         }
-        if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
-            || !self.look_ahead(1, |token| token.is_non_reserved_ident())
-        {
-            let mut snapshot_type = self.create_snapshot_for_diagnostic();
-            snapshot_type.bump(); // `:`
-            match snapshot_type.parse_ty() {
-                Err(inner_err) => {
-                    inner_err.cancel();
-                }
-                Ok(ty) => {
-                    let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
-                        return first_pat;
-                    };
-                    err.span_label(ty.span, "specifying the type of a pattern isn't supported");
-                    self.restore_snapshot(snapshot_type);
-                    let span = first_pat.span.to(ty.span);
-                    first_pat = self.mk_pat(span, PatKind::Wild);
-                    err.emit();
-                }
-            }
-            return first_pat;
-        }
+
         // The pattern looks like it might be a path with a `::` -> `:` typo:
         // `match foo { bar:baz => {} }`
         let colon_span = self.token.span;
@@ -2857,7 +2836,13 @@ impl<'a> Parser<'a> {
                                 Applicability::MaybeIncorrect,
                             );
                         } else {
-                            first_pat = self.mk_pat(new_span, PatKind::Wild);
+                            first_pat = self.mk_pat(
+                                new_span,
+                                PatKind::Err(
+                                    self.dcx()
+                                        .span_delayed_bug(colon_span, "recovered bad path pattern"),
+                                ),
+                            );
                         }
                         self.restore_snapshot(snapshot_pat);
                     }
@@ -2870,7 +2855,14 @@ impl<'a> Parser<'a> {
                         err.span_label(ty.span, "specifying the type of a pattern isn't supported");
                         self.restore_snapshot(snapshot_type);
                         let new_span = first_pat.span.to(ty.span);
-                        first_pat = self.mk_pat(new_span, PatKind::Wild);
+                        first_pat =
+                            self.mk_pat(
+                                new_span,
+                                PatKind::Err(self.dcx().span_delayed_bug(
+                                    colon_span,
+                                    "recovered bad pattern with type",
+                                )),
+                            );
                     }
                 }
                 err.emit();
@@ -2947,26 +2939,24 @@ impl<'a> Parser<'a> {
         }
         let seq_span = lo.to(self.prev_token.span);
         let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
-        if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
-            err.multipart_suggestion(
-                format!(
-                    "try adding parentheses to match on a tuple{}",
-                    if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
-                ),
-                vec![
-                    (seq_span.shrink_to_lo(), "(".to_string()),
-                    (seq_span.shrink_to_hi(), ")".to_string()),
-                ],
+        err.multipart_suggestion(
+            format!(
+                "try adding parentheses to match on a tuple{}",
+                if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
+            ),
+            vec![
+                (seq_span.shrink_to_lo(), "(".to_string()),
+                (seq_span.shrink_to_hi(), ")".to_string()),
+            ],
+            Applicability::MachineApplicable,
+        );
+        if let CommaRecoveryMode::EitherTupleOrPipe = rt {
+            err.span_suggestion(
+                comma_span,
+                "...or a vertical bar to match on alternatives",
+                " |",
                 Applicability::MachineApplicable,
             );
-            if let CommaRecoveryMode::EitherTupleOrPipe = rt {
-                err.span_suggestion(
-                    seq_span,
-                    "...or a vertical bar to match on multiple alternatives",
-                    seq_snippet.replace(',', " |"),
-                    Applicability::MachineApplicable,
-                );
-            }
         }
         Err(err)
     }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 81a5d48d94e..8046abcd70b 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3612,7 +3612,7 @@ impl<'a> Parser<'a> {
         self.token.is_keyword(kw::Async) && self.is_gen_block(kw::Gen, 1)
     }
 
-    fn is_certainly_not_a_block(&self) -> bool {
+    fn is_likely_struct_lit(&self) -> bool {
         // `{ ident, ` and `{ ident: ` cannot start a block.
         self.look_ahead(1, |t| t.is_ident())
             && self.look_ahead(2, |t| t == &token::Comma || t == &token::Colon)
@@ -3624,24 +3624,50 @@ impl<'a> Parser<'a> {
         path: &ast::Path,
     ) -> Option<PResult<'a, Box<Expr>>> {
         let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
-        if struct_allowed || self.is_certainly_not_a_block() {
-            if let Err(err) = self.expect(exp!(OpenBrace)) {
-                return Some(Err(err));
+        match (struct_allowed, self.is_likely_struct_lit()) {
+            // A struct literal isn't expected and one is pretty much assured not to be present. The
+            // only situation that isn't detected is when a struct with a single field was attempted
+            // in a place where a struct literal wasn't expected, but regular parser errors apply.
+            // Happy path.
+            (false, false) => None,
+            (true, _) => {
+                // A struct is accepted here, try to parse it and rely on `parse_expr_struct` for
+                // any kind of recovery. Happy path.
+                if let Err(err) = self.expect(exp!(OpenBrace)) {
+                    return Some(Err(err));
+                }
+                Some(self.parse_expr_struct(qself.clone(), path.clone(), true))
             }
-            let expr = self.parse_expr_struct(qself.clone(), path.clone(), true);
-            if let (Ok(expr), false) = (&expr, struct_allowed) {
-                // This is a struct literal, but we don't can't accept them here.
-                self.dcx().emit_err(errors::StructLiteralNotAllowedHere {
-                    span: expr.span,
-                    sub: errors::StructLiteralNotAllowedHereSugg {
-                        left: path.span.shrink_to_lo(),
-                        right: expr.span.shrink_to_hi(),
-                    },
-                });
+            (false, true) => {
+                // We have something like `match foo { bar,` or `match foo { bar:`, which means the
+                // user might have meant to write a struct literal as part of the `match`
+                // discriminant. This is done purely for error recovery.
+                let snapshot = self.create_snapshot_for_diagnostic();
+                if let Err(err) = self.expect(exp!(OpenBrace)) {
+                    return Some(Err(err));
+                }
+                match self.parse_expr_struct(qself.clone(), path.clone(), false) {
+                    Ok(expr) => {
+                        // This is a struct literal, but we don't accept them here.
+                        self.dcx().emit_err(errors::StructLiteralNotAllowedHere {
+                            span: expr.span,
+                            sub: errors::StructLiteralNotAllowedHereSugg {
+                                left: path.span.shrink_to_lo(),
+                                right: expr.span.shrink_to_hi(),
+                            },
+                        });
+                        Some(Ok(expr))
+                    }
+                    Err(err) => {
+                        // We couldn't parse a valid struct, rollback and let the parser emit an
+                        // error elsewhere.
+                        err.cancel();
+                        self.restore_snapshot(snapshot);
+                        None
+                    }
+                }
             }
-            return Some(expr);
         }
-        None
     }
 
     pub(super) fn parse_struct_fields(
diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs
index 276adacd99e..7bd06fee721 100644
--- a/compiler/rustc_public/src/mir/body.rs
+++ b/compiler/rustc_public/src/mir/body.rs
@@ -836,14 +836,6 @@ pub enum ProjectionElem {
     /// Like an explicit cast from an opaque type to a concrete type, but without
     /// requiring an intermediate variable.
     OpaqueCast(Ty),
-
-    /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
-    /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
-    /// explicit during optimizations and codegen.
-    ///
-    /// This projection doesn't impact the runtime behavior of the program except for potentially changing
-    /// some type metadata of the interpreter or codegen backend.
-    Subtype(Ty),
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@@ -1028,6 +1020,7 @@ pub enum CastKind {
     PtrToPtr,
     FnPtrToPtr,
     Transmute,
+    Subtype,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)]
@@ -1089,7 +1082,7 @@ impl ProjectionElem {
                 Self::subslice_ty(ty, *from, *to, *from_end)
             }
             ProjectionElem::Downcast(_) => Ok(ty),
-            ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => Ok(*ty),
+            ProjectionElem::OpaqueCast(ty) => Ok(*ty),
         }
     }
 
diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs
index 04c4d4d2a82..7563c9ca008 100644
--- a/compiler/rustc_public/src/mir/visit.rs
+++ b/compiler/rustc_public/src/mir/visit.rs
@@ -471,7 +471,6 @@ macro_rules! visit_place_fns {
                 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
                 ProjectionElem::Downcast(_idx) => {}
                 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
-                ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
             }
         }
     };
@@ -512,7 +511,6 @@ macro_rules! visit_place_fns {
                 ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
                 ProjectionElem::Downcast(_idx) => {}
                 ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
-                ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
             }
         }
     };
diff --git a/compiler/rustc_public/src/unstable/convert/internal.rs b/compiler/rustc_public/src/unstable/convert/internal.rs
index dc9abd88614..064fb6c6803 100644
--- a/compiler/rustc_public/src/unstable/convert/internal.rs
+++ b/compiler/rustc_public/src/unstable/convert/internal.rs
@@ -703,9 +703,6 @@ impl RustcInternal for ProjectionElem {
             ProjectionElem::OpaqueCast(ty) => {
                 rustc_middle::mir::PlaceElem::OpaqueCast(ty.internal(tables, tcx))
             }
-            ProjectionElem::Subtype(ty) => {
-                rustc_middle::mir::PlaceElem::Subtype(ty.internal(tables, tcx))
-            }
         }
     }
 }
diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
index b10af6526ea..62ab91d17ba 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs
@@ -356,6 +356,7 @@ impl<'tcx> Stable<'tcx> for mir::CastKind {
             PtrToPtr => crate::mir::CastKind::PtrToPtr,
             FnPtrToPtr => crate::mir::CastKind::FnPtrToPtr,
             Transmute => crate::mir::CastKind::Transmute,
+            Subtype => crate::mir::CastKind::Subtype,
         }
     }
 }
@@ -453,7 +454,6 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
             // found at https://github.com/rust-lang/rust/pull/117517#issuecomment-1811683486
             Downcast(_, idx) => crate::mir::ProjectionElem::Downcast(idx.stable(tables, cx)),
             OpaqueCast(ty) => crate::mir::ProjectionElem::OpaqueCast(ty.stable(tables, cx)),
-            Subtype(ty) => crate::mir::ProjectionElem::Subtype(ty.stable(tables, cx)),
             UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
         }
     }
diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
index 7f14f878d37..59440e5407f 100644
--- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs
+++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs
@@ -453,7 +453,10 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
                 TyKind::Alias(alias_kind.stable(tables, cx), alias_ty.stable(tables, cx))
             }
             ty::Param(param_ty) => TyKind::Param(param_ty.stable(tables, cx)),
-            ty::Bound(debruijn_idx, bound_ty) => {
+            ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
+                unreachable!()
+            }
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn_idx), bound_ty) => {
                 TyKind::Bound(debruijn_idx.as_usize(), bound_ty.stable(tables, cx))
             }
             ty::CoroutineWitness(def_id, args) => TyKind::RigidTy(RigidTy::CoroutineWitness(
@@ -907,7 +910,7 @@ impl<'tcx> Stable<'tcx> for ty::RegionKind<'tcx> {
                 index: early_reg.index,
                 name: early_reg.name.to_string(),
             }),
-            ty::ReBound(db_index, bound_reg) => RegionKind::ReBound(
+            ty::ReBound(ty::BoundVarIndexKind::Bound(db_index), bound_reg) => RegionKind::ReBound(
                 db_index.as_u32(),
                 BoundRegion {
                     var: bound_reg.var.as_u32(),
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index ec7a4a81a71..621cc0fb3ef 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -287,7 +287,7 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>,
     // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
     let mut s = String::new();
     match region.kind() {
-        RegionKind::ReBound(debruijn, r) => {
+        RegionKind::ReBound(ty::BoundVarIndexKind::Bound(debruijn), r) => {
             s.push_str("u6regionI");
             // Debruijn index, which identifies the binder, as region disambiguator
             let num = debruijn.index() as u64;
@@ -303,7 +303,8 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>,
             s.push_str("u6region");
             compress(dict, DictKey::Region(region), &mut s);
         }
-        RegionKind::ReEarlyParam(..)
+        RegionKind::ReBound(ty::BoundVarIndexKind::Canonical, _)
+        | RegionKind::ReEarlyParam(..)
         | RegionKind::ReLateParam(..)
         | RegionKind::ReStatic
         | RegionKind::ReError(_)
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 25b46241c52..172672a80fb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -758,7 +758,8 @@ impl Session {
         //     ELF x86-64 abi, but it can be disabled for some compilation units.
         //
         // Typically when we're compiling with `-C panic=abort` we don't need
-        // `uwtable` because we can't generate any exceptions!
+        // `uwtable` because we can't generate any exceptions! But note that
+        // some targets require unwind tables to generate backtraces.
         // Unwind tables are needed when compiling with `-C panic=unwind`, but
         // LLVM won't omit unwind tables unless the function is also marked as
         // `nounwind`, so users are allowed to disable `uwtable` emission.
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index d24924b424a..aeac40a65bd 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -413,7 +413,10 @@ impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
 
             // Bound lifetimes use indices starting at 1,
             // see `BinderLevel` for more details.
-            ty::ReBound(debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }) => {
+            ty::ReBound(
+                ty::BoundVarIndexKind::Bound(debruijn),
+                ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
+            ) => {
                 let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
                 let depth = binder.lifetime_depths.start + var.as_u32();
 
diff --git a/compiler/rustc_target/src/spec/base/android.rs b/compiler/rustc_target/src/spec/base/android.rs
index 0426ea44c6a..df2757aaabf 100644
--- a/compiler/rustc_target/src/spec/base/android.rs
+++ b/compiler/rustc_target/src/spec/base/android.rs
@@ -8,10 +8,6 @@ pub(crate) fn opts() -> TargetOptions {
     base.tls_model = TlsModel::Emulated;
     base.has_thread_local = false;
     base.supported_sanitizers = SanitizerSet::ADDRESS;
-    // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867
-    // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
-    // was to always emit `uwtable`).
-    base.default_uwtable = true;
     base.crt_static_respected = true;
     base
 }
diff --git a/compiler/rustc_target/src/spec/base/linux.rs b/compiler/rustc_target/src/spec/base/linux.rs
index 9982c254eca..26e4590cf5e 100644
--- a/compiler/rustc_target/src/spec/base/linux.rs
+++ b/compiler/rustc_target/src/spec/base/linux.rs
@@ -12,6 +12,9 @@ pub(crate) fn opts() -> TargetOptions {
         relro_level: RelroLevel::Full,
         has_thread_local: true,
         crt_static_respected: true,
+        // We want backtraces to work by default and they rely on unwind tables
+        // (regardless of `-C panic` strategy).
+        default_uwtable: true,
         supported_split_debuginfo: Cow::Borrowed(&[
             SplitDebuginfo::Packed,
             SplitDebuginfo::Unpacked,
diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
index a3f5389f0aa..0c711d5e71a 100644
--- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs
@@ -19,6 +19,11 @@ pub(crate) fn target() -> Target {
             max_atomic_width: Some(64),
             mcount: "\u{1}__gnu_mcount_nc".into(),
             llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()),
+            // The default on linux is to have `default_uwtable=true`, but on
+            // this target we get an "`__aeabi_unwind_cpp_pr0` not defined"
+            // linker error, so set it to `true` here.
+            // FIXME(#146996): Remove this override once #146996 has been fixed.
+            default_uwtable: false,
             ..base::linux_gnu::opts()
         },
     }
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
index a0eb4a254fc..06e5cfaed92 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs
@@ -6,11 +6,18 @@ use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base};
 pub(crate) fn target() -> Target {
     let mut options = base::linux_wasm::opts();
 
-    options
-        .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]);
+    options.add_pre_link_args(
+        LinkerFlavor::WasmLld(Cc::No),
+        &["--export-memory", "--shared-memory", "--max-memory=1073741824"],
+    );
     options.add_pre_link_args(
         LinkerFlavor::WasmLld(Cc::Yes),
-        &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"],
+        &[
+            "--target=wasm32-wasi-threads",
+            "-Wl,--export-memory,",
+            "-Wl,--shared-memory",
+            "-Wl,--max-memory=1073741824",
+        ],
     );
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
index 44d906a507d..c735c72cb1c 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs
@@ -19,7 +19,7 @@ pub(crate) fn target() -> Target {
 
     options.add_pre_link_args(
         LinkerFlavor::WasmLld(Cc::No),
-        &["--import-memory", "--export-memory", "--shared-memory"],
+        &["--import-memory", "--export-memory", "--shared-memory", "--max-memory=1073741824"],
     );
     options.add_pre_link_args(
         LinkerFlavor::WasmLld(Cc::Yes),
@@ -28,6 +28,7 @@ pub(crate) fn target() -> Target {
             "-Wl,--import-memory",
             "-Wl,--export-memory,",
             "-Wl,--shared-memory",
+            "-Wl,--max-memory=1073741824",
         ],
     );
 
diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs
index 2b33b8ac9f8..debc4fda15a 100644
--- a/compiler/rustc_trait_selection/src/regions.rs
+++ b/compiler/rustc_trait_selection/src/regions.rs
@@ -77,6 +77,8 @@ impl<'tcx> InferCtxt<'tcx> {
     ///
     /// Prefer this method over `resolve_regions_with_normalize`, unless you are
     /// doing something specific for normalization.
+    ///
+    /// This function assumes that all infer variables are already constrained.
     fn resolve_regions(
         &self,
         body_id: LocalDefId,
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 3260dd712b9..6ab92531e4e 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -830,7 +830,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEscapingBoundRegions<'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        if let ty::ReBound(debruijn, _) = r.kind()
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind()
             && debruijn < self.binder
         {
             r
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a54eb80fedc..c6eb0caee1a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -145,7 +145,9 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
     #[inline]
     fn visit_region(&mut self, r: ty::Region<'tcx>) {
         match r.kind() {
-            ty::ReBound(debruijn, _) if debruijn > self.outer_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
+                if debruijn > self.outer_index =>
+            {
                 self.escaping =
                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
             }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index e91e5055e90..bb25a14ef74 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -235,7 +235,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
             // bounds of the RPITIT. Shift these binders back out when
             // constructing the top-level projection predicate.
             let shifted_alias_ty = fold_regions(self.tcx, unshifted_alias_ty, |re, depth| {
-                if let ty::ReBound(index, bv) = re.kind() {
+                if let ty::ReBound(ty::BoundVarIndexKind::Bound(index), bv) = re.kind() {
                     if depth != ty::INNERMOST {
                         return ty::Region::new_error_with_message(
                             self.tcx,
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 6591d3148cb..94b950357e1 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -4,6 +4,7 @@ use std::ops::{ControlFlow, Deref};
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::instrument;
 
 use crate::data_structures::SsoHashSet;
@@ -11,7 +12,7 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldabl
 use crate::inherent::*;
 use crate::lift::Lift;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use crate::{self as ty, Interner};
+use crate::{self as ty, DebruijnIndex, Interner};
 
 /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the
 /// compiler's representation for things like `for<'a> Fn(&'a isize)`
@@ -299,7 +300,9 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
             return ControlFlow::Break(());
         }
         match t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ty)
+                if debruijn == self.binder_index =>
+            {
                 let idx = bound_ty.var().as_usize();
                 if self.bound_vars.len() <= idx {
                     panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
@@ -317,7 +320,9 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
             return ControlFlow::Break(());
         }
         match c.kind() {
-            ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.binder_index => {
+            ty::ConstKind::Bound(debruijn, bound_const)
+                if debruijn == ty::BoundVarIndexKind::Bound(self.binder_index) =>
+            {
                 let idx = bound_const.var().as_usize();
                 if self.bound_vars.len() <= idx {
                     panic!("Not enough bound vars: {:?} not found in {:?}", c, self.bound_vars);
@@ -332,7 +337,7 @@ impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
 
     fn visit_region(&mut self, r: I::Region) -> Self::Result {
         match r.kind() {
-            ty::ReBound(index, br) if index == self.binder_index => {
+            ty::ReBound(index, br) if index == ty::BoundVarIndexKind::Bound(self.binder_index) => {
                 let idx = br.var().as_usize();
                 if self.bound_vars.len() <= idx {
                     panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars);
@@ -913,3 +918,33 @@ impl<'a, I: Interner> ArgFolder<'a, I> {
         }
     }
 }
+
+/// Okay, we do something fun for `Bound` types/regions/consts:
+/// Specifically, we distinguish between *canonically* bound things and
+/// `for<>` bound things. And, really, it comes down to caching during
+/// canonicalization and instantiation.
+///
+/// To understand why we do this, imagine we have a type `(T, for<> fn(T))`.
+/// If we just tracked canonically bound types with a `DebruijnIndex` (as we
+/// used to), then the canonicalized type would be something like
+/// `for<0> (^0.0, for<> fn(^1.0))` and so we can't cache `T -> ^0.0`,
+/// we have to also factor in binder level. (Of course, we don't cache that
+/// exactly, but rather the entire enclosing type, but the point stands.)
+///
+/// Of course, this is okay because we don't ever nest canonicalization, so
+/// `BoundVarIndexKind::Canonical` is unambiguous. We, alternatively, could
+/// have some sentinel `DebruijinIndex`, but that just seems too scary.
+///
+/// This doesn't seem to have a huge perf swing either way, but in the next
+/// solver, canonicalization is hot and there are some pathological cases where
+/// this is needed (`post-mono-higher-ranked-hang`).
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(
+    feature = "nightly",
+    derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub enum BoundVarIndexKind {
+    Bound(DebruijnIndex),
+    Canonical,
+}
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index ecf3ae4f8b2..7b4b953b2cf 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -230,13 +230,13 @@ impl<I: Interner> CanonicalVarValues<I> {
     pub fn is_identity(&self) -> bool {
         self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() {
             ty::GenericArgKind::Lifetime(r) => {
-                matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
+                matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if br.var().as_usize() == bv)
             }
             ty::GenericArgKind::Type(ty) => {
-                matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
+                matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if bt.var().as_usize() == bv)
             }
             ty::GenericArgKind::Const(ct) => {
-                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
+                matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if bc.var().as_usize() == bv)
             }
         })
     }
@@ -246,21 +246,23 @@ impl<I: Interner> CanonicalVarValues<I> {
         for arg in self.var_values.iter() {
             match arg.kind() {
                 ty::GenericArgKind::Lifetime(r) => {
-                    if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
+                    if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Canonical, br) if var == br.var())
+                    {
                         var = var + 1;
                     } else {
                         // It's ok if this region var isn't an identity variable
                     }
                 }
                 ty::GenericArgKind::Type(ty) => {
-                    if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
+                    if matches!(ty.kind(), ty::Bound(ty::BoundVarIndexKind::Canonical, bt) if var == bt.var())
+                    {
                         var = var + 1;
                     } else {
                         return false;
                     }
                 }
                 ty::GenericArgKind::Const(ct) => {
-                    if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
+                    if matches!(ct.kind(), ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, bc) if var == bc.var())
                     {
                         var = var + 1;
                     } else {
@@ -284,16 +286,13 @@ impl<I: Interner> CanonicalVarValues<I> {
                         | CanonicalVarKind::Int
                         | CanonicalVarKind::Float
                         | CanonicalVarKind::PlaceholderTy(_) => {
-                            Ty::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
-                                .into()
+                            Ty::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
                         }
                         CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
-                            Region::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
-                                .into()
+                            Region::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
                         }
                         CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => {
-                            Const::new_anon_bound(cx, ty::INNERMOST, ty::BoundVar::from_usize(i))
-                                .into()
+                            Const::new_canonical_bound(cx, ty::BoundVar::from_usize(i)).into()
                         }
                     }
                 },
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index 6de41b47bde..273b6096008 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
-use crate::{self as ty, DebruijnIndex, Interner};
+use crate::{self as ty, BoundVarIndexKind, Interner};
 
 /// Represents a constant in Rust.
 #[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)]
@@ -23,7 +23,7 @@ pub enum ConstKind<I: Interner> {
     Infer(InferConst),
 
     /// Bound const variable, used only when preparing a trait query.
-    Bound(DebruijnIndex, I::BoundConst),
+    Bound(BoundVarIndexKind, I::BoundConst),
 
     /// A placeholder const - universally quantified higher-ranked const.
     Placeholder(I::PlaceholderConst),
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 24704c5bb53..34b030ee768 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -133,6 +133,9 @@ bitflags::bitflags! {
 
         /// Does this type have any coroutines in it?
         const HAS_TY_CORO                 = 1 << 24;
+
+        /// Does this have have a `Bound(BoundVarIndexKind::Canonical, _)`?
+        const HAS_CANONICAL_BOUND      = 1 << 25;
     }
 }
 
@@ -254,7 +257,12 @@ impl<I: Interner> FlagComputation<I> {
                 self.add_args(args.as_slice());
             }
 
-            ty::Bound(debruijn, _) => {
+            ty::Bound(ty::BoundVarIndexKind::Canonical, _) => {
+                self.add_flags(TypeFlags::HAS_TY_BOUND);
+                self.add_flags(TypeFlags::HAS_CANONICAL_BOUND);
+            }
+
+            ty::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => {
                 self.add_bound_var(debruijn);
                 self.add_flags(TypeFlags::HAS_TY_BOUND);
             }
@@ -347,6 +355,7 @@ impl<I: Interner> FlagComputation<I> {
 
     fn add_ty_pat(&mut self, pat: <I as Interner>::Pat) {
         self.add_flags(pat.flags());
+        self.add_exclusive_binder(pat.outer_exclusive_binder());
     }
 
     fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) {
@@ -434,7 +443,7 @@ impl<I: Interner> FlagComputation<I> {
 
     fn add_region(&mut self, r: I::Region) {
         self.add_flags(r.flags());
-        if let ty::ReBound(debruijn, _) = r.kind() {
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() {
             self.add_bound_var(debruijn);
         }
     }
@@ -454,10 +463,14 @@ impl<I: Interner> FlagComputation<I> {
                 ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
                 ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
             },
-            ty::ConstKind::Bound(debruijn, _) => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), _) => {
                 self.add_bound_var(debruijn);
                 self.add_flags(TypeFlags::HAS_CT_BOUND);
             }
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Canonical, _) => {
+                self.add_flags(TypeFlags::HAS_CT_BOUND);
+                self.add_flags(TypeFlags::HAS_CANONICAL_BOUND);
+            }
             ty::ConstKind::Param(_) => {
                 self.add_flags(TypeFlags::HAS_CT_PARAM);
             }
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index a5eb8699e5f..d1a50599e8b 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -55,7 +55,7 @@ use tracing::{debug, instrument};
 
 use crate::inherent::*;
 use crate::visit::{TypeVisitable, TypeVisitableExt as _};
-use crate::{self as ty, Interner, TypeFlags};
+use crate::{self as ty, BoundVarIndexKind, Interner, TypeFlags};
 
 /// This trait is implemented for every type that can be folded,
 /// providing the skeleton of the traversal.
@@ -398,7 +398,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> {
 
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         match r.kind() {
-            ty::ReBound(debruijn, br) if debruijn >= self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br)
+                if debruijn >= self.current_index =>
+            {
                 let debruijn = debruijn.shifted_in(self.amount);
                 Region::new_bound(self.cx, debruijn, br)
             }
@@ -408,7 +410,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> {
 
     fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
         match ty.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn >= self.current_index => {
+            ty::Bound(BoundVarIndexKind::Bound(debruijn), bound_ty)
+                if debruijn >= self.current_index =>
+            {
                 let debruijn = debruijn.shifted_in(self.amount);
                 Ty::new_bound(self.cx, debruijn, bound_ty)
             }
@@ -420,7 +424,9 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> {
 
     fn fold_const(&mut self, ct: I::Const) -> I::Const {
         match ct.kind() {
-            ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => {
+            ty::ConstKind::Bound(ty::BoundVarIndexKind::Bound(debruijn), bound_ct)
+                if debruijn >= self.current_index =>
+            {
                 let debruijn = debruijn.shifted_in(self.amount);
                 Const::new_bound(self.cx, debruijn, bound_ct)
             }
@@ -435,7 +441,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> {
 
 pub fn shift_region<I: Interner>(cx: I, region: I::Region, amount: u32) -> I::Region {
     match region.kind() {
-        ty::ReBound(debruijn, br) if amount > 0 => {
+        ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) if amount > 0 => {
             Region::new_bound(cx, debruijn.shifted_in(amount), br)
         }
         _ => region,
@@ -515,7 +521,13 @@ where
     #[instrument(skip(self), level = "debug", ret)]
     fn fold_region(&mut self, r: I::Region) -> I::Region {
         match r.kind() {
-            ty::ReBound(debruijn, _) if debruijn < self.current_index => {
+            ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
+                if debruijn < self.current_index =>
+            {
+                debug!(?self.current_index, "skipped bound region");
+                r
+            }
+            ty::ReBound(ty::BoundVarIndexKind::Canonical, _) => {
                 debug!(?self.current_index, "skipped bound region");
                 r
             }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index b5b552dbaec..75ba0231d98 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -48,6 +48,8 @@ pub trait Ty<I: Interner<Ty = Self>>:
 
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
+    fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self;
+
     fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
 
     fn new_projection_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self {
@@ -230,6 +232,8 @@ pub trait Region<I: Interner<Region = Self>>:
 
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
+    fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self;
+
     fn new_static(interner: I) -> Self;
 
     fn new_placeholder(interner: I, var: I::PlaceholderRegion) -> Self;
@@ -260,6 +264,8 @@ pub trait Const<I: Interner<Const = Self>>:
 
     fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
 
+    fn new_canonical_bound(interner: I, var: ty::BoundVar) -> Self;
+
     fn new_placeholder(interner: I, param: I::PlaceholderConst) -> Self;
 
     fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self;
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 61e0b67b163..c1e30196126 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -196,13 +196,20 @@ impl DebruijnIndex {
 
 pub fn debug_bound_var<T: std::fmt::Write>(
     fmt: &mut T,
-    debruijn: DebruijnIndex,
+    bound_index: BoundVarIndexKind,
     var: impl std::fmt::Debug,
 ) -> Result<(), std::fmt::Error> {
-    if debruijn == INNERMOST {
-        write!(fmt, "^{var:?}")
-    } else {
-        write!(fmt, "^{}_{:?}", debruijn.index(), var)
+    match bound_index {
+        BoundVarIndexKind::Bound(debruijn) => {
+            if debruijn == INNERMOST {
+                write!(fmt, "^{var:?}")
+            } else {
+                write!(fmt, "^{}_{:?}", debruijn.index(), var)
+            }
+        }
+        BoundVarIndexKind::Canonical => {
+            write!(fmt, "^c_{:?}", var)
+        }
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 06048af0436..1e8585cf52c 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 
 use self::RegionKind::*;
-use crate::{DebruijnIndex, Interner};
+use crate::{BoundVarIndexKind, Interner};
 
 rustc_index::newtype_index! {
     /// A **region** **v**ariable **ID**.
@@ -147,7 +147,7 @@ pub enum RegionKind<I: Interner> {
     /// Bound regions inside of types **must not** be erased, as they impact trait
     /// selection and the `TypeId` of that type. `for<'a> fn(&'a ())` and
     /// `fn(&'static ())` are different types and have to be treated as such.
-    ReBound(DebruijnIndex, I::BoundRegion),
+    ReBound(BoundVarIndexKind, I::BoundRegion),
 
     /// Late-bound function parameters are represented using a `ReBound`. When
     /// inside of a function, we convert these bound variables to placeholder
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index dda59283677..bb80e2cf46d 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -15,7 +15,7 @@ pub use self::closure::*;
 use crate::inherent::*;
 #[cfg(feature = "nightly")]
 use crate::visit::TypeVisitable;
-use crate::{self as ty, DebruijnIndex, FloatTy, IntTy, Interner, UintTy};
+use crate::{self as ty, BoundVarIndexKind, FloatTy, IntTy, Interner, UintTy};
 
 mod closure;
 
@@ -229,7 +229,7 @@ pub enum TyKind<I: Interner> {
     ///
     /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
     /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
-    Bound(DebruijnIndex, I::BoundTy),
+    Bound(BoundVarIndexKind, I::BoundTy),
 
     /// A placeholder type, used during higher ranked subtyping to instantiate
     /// bound variables.
diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs
index 3a6d1acfa8d..4d9fd6040d8 100644
--- a/compiler/rustc_type_ir/src/ty_kind/closure.rs
+++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs
@@ -344,7 +344,8 @@ impl<I: Interner> TypeVisitor<I> for HasRegionsBoundAt {
     }
 
     fn visit_region(&mut self, r: I::Region) -> Self::Result {
-        if matches!(r.kind(), ty::ReBound(binder, _) if self.binder == binder) {
+        if matches!(r.kind(), ty::ReBound(ty::BoundVarIndexKind::Bound(binder), _) if self.binder == binder)
+        {
             ControlFlow::Break(())
         } else {
             ControlFlow::Continue(())
@@ -531,7 +532,7 @@ impl<I: Interner> TypeFolder<I> for FoldEscapingRegions<I> {
     }
 
     fn fold_region(&mut self, r: <I as Interner>::Region) -> <I as Interner>::Region {
-        if let ty::ReBound(debruijn, _) = r.kind() {
+        if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _) = r.kind() {
             assert!(
                 debruijn <= self.debruijn,
                 "cannot instantiate binder with escaping bound vars"
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 5a63d90b95f..49ff768bed1 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -619,6 +619,37 @@ impl<T, A: Allocator> Box<T, A> {
     pub fn into_inner(boxed: Self) -> T {
         *boxed
     }
+
+    /// Consumes the `Box` without consuming its allocation, returning the wrapped value and a `Box`
+    /// to the uninitialized memory where the wrapped value used to live.
+    ///
+    /// This can be used together with [`write`](Box::write) to reuse the allocation for multiple
+    /// boxed values.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(box_take)]
+    ///
+    /// let c = Box::new(5);
+    ///
+    /// // take the value out of the box
+    /// let (value, uninit) = Box::take(c);
+    /// assert_eq!(value, 5);
+    ///
+    /// // reuse the box for a second value
+    /// let c = Box::write(uninit, 6);
+    /// assert_eq!(*c, 6);
+    /// ```
+    #[unstable(feature = "box_take", issue = "147212")]
+    pub fn take(boxed: Self) -> (T, Box<mem::MaybeUninit<T>, A>) {
+        unsafe {
+            let (raw, alloc) = Box::into_raw_with_allocator(boxed);
+            let value = raw.read();
+            let uninit = Box::from_raw_in(raw.cast::<mem::MaybeUninit<T>>(), alloc);
+            (value, uninit)
+        }
+    }
 }
 
 impl<T> Box<[T]> {
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index ae910e05252..7053ae86e73 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -2203,16 +2203,13 @@ unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {}
 #[unstable(feature = "array_windows", issue = "75027")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub struct ArrayWindows<'a, T: 'a, const N: usize> {
-    slice_head: *const T,
-    num: usize,
-    marker: PhantomData<&'a [T; N]>,
+    v: &'a [T],
 }
 
 impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> {
     #[inline]
     pub(super) const fn new(slice: &'a [T]) -> Self {
-        let num_windows = slice.len().saturating_sub(N - 1);
-        Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData }
+        Self { v: slice }
     }
 }
 
@@ -2222,49 +2219,34 @@ impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> {
 
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
-        if self.num == 0 {
-            return None;
+        let ret = self.v.first_chunk();
+        if ret.is_some() {
+            self.v = &self.v[1..];
         }
-        // SAFETY:
-        // This is safe because it's indexing into a slice guaranteed to be length > N.
-        let ret = unsafe { &*self.slice_head.cast::<[T; N]>() };
-        // SAFETY: Guaranteed that there are at least 1 item remaining otherwise
-        // earlier branch would've been hit
-        self.slice_head = unsafe { self.slice_head.add(1) };
-
-        self.num -= 1;
-        Some(ret)
+        ret
     }
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.num, Some(self.num))
+        let size = self.v.len().saturating_sub(N - 1);
+        (size, Some(size))
     }
 
     #[inline]
     fn count(self) -> usize {
-        self.num
+        self.len()
     }
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        if self.num <= n {
-            self.num = 0;
-            return None;
-        }
-        // SAFETY:
-        // This is safe because it's indexing into a slice guaranteed to be length > N.
-        let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() };
-        // SAFETY: Guaranteed that there are at least n items remaining
-        self.slice_head = unsafe { self.slice_head.add(n + 1) };
-
-        self.num -= n + 1;
-        Some(ret)
+        let idx = n.min(self.v.len());
+        self.v = &self.v[idx..];
+        self.next()
     }
 
     #[inline]
-    fn last(mut self) -> Option<Self::Item> {
-        self.nth(self.num.checked_sub(1)?)
+    fn last(self) -> Option<Self::Item> {
+        self.v.last_chunk()
     }
 }
 
@@ -2272,32 +2254,25 @@ impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> {
 impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a [T; N]> {
-        if self.num == 0 {
-            return None;
+        let ret = self.v.last_chunk();
+        if ret.is_some() {
+            self.v = &self.v[..self.v.len() - 1];
         }
-        // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
-        let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() };
-        self.num -= 1;
-        Some(ret)
+        ret
     }
 
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> {
-        if self.num <= n {
-            self.num = 0;
-            return None;
-        }
-        // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
-        let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() };
-        self.num -= n + 1;
-        Some(ret)
+        let idx = self.v.len().saturating_sub(n);
+        self.v = &self.v[..idx];
+        self.next_back()
     }
 }
 
 #[unstable(feature = "array_windows", issue = "75027")]
 impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> {
     fn is_empty(&self) -> bool {
-        self.num == 0
+        self.v.len() < N
     }
 }
 
diff --git a/library/coretests/tests/iter/sources.rs b/library/coretests/tests/iter/sources.rs
index 506febaa056..5a391cb6775 100644
--- a/library/coretests/tests/iter/sources.rs
+++ b/library/coretests/tests/iter/sources.rs
@@ -31,6 +31,17 @@ fn test_repeat_take_collect() {
 }
 
 #[test]
+#[should_panic = "iterator is infinite"]
+fn test_repeat_count() {
+    repeat(42).count();
+}
+
+#[test]
+fn test_repeat_last() {
+    assert_eq!(repeat(42).last(), Some(42));
+}
+
+#[test]
 fn test_repeat_with() {
     #[derive(PartialEq, Debug)]
     struct NotClone(usize);
diff --git a/library/std/src/sys/net/hostname/mod.rs b/library/std/src/sys/net/hostname/mod.rs
index a4b5b76059d..8ffe4894d71 100644
--- a/library/std/src/sys/net/hostname/mod.rs
+++ b/library/std/src/sys/net/hostname/mod.rs
@@ -1,5 +1,5 @@
 cfg_select! {
-    target_family = "unix" => {
+    all(target_family = "unix", not(target_os = "espidf")) => {
         mod unix;
         pub use unix::hostname;
     }
diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs
index d5c795093cf..f7f051b1add 100644
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
@@ -42,7 +42,7 @@ cfg_select! {
     }
     _ => {
         mod os;
-        pub use os::{Storage, thread_local_inner};
+        pub use os::{Storage, thread_local_inner, value_align};
         pub(crate) use os::{LocalPointer, local_pointer};
     }
 }
diff --git a/library/std/src/sys/thread_local/native/eager.rs b/library/std/src/sys/thread_local/native/eager.rs
index fd48c4f7202..23abad645c1 100644
--- a/library/std/src/sys/thread_local/native/eager.rs
+++ b/library/std/src/sys/thread_local/native/eager.rs
@@ -10,9 +10,11 @@ enum State {
 }
 
 #[allow(missing_debug_implementations)]
+#[repr(C)]
 pub struct Storage<T> {
-    state: Cell<State>,
+    // This field must be first, for correctness of `#[rustc_align_static]`
     val: UnsafeCell<T>,
+    state: Cell<State>,
 }
 
 impl<T> Storage<T> {
diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs
index b556dd9aa25..02939a74fc0 100644
--- a/library/std/src/sys/thread_local/native/lazy.rs
+++ b/library/std/src/sys/thread_local/native/lazy.rs
@@ -27,9 +27,11 @@ enum State<D> {
 }
 
 #[allow(missing_debug_implementations)]
+#[repr(C)]
 pub struct Storage<T, D> {
-    state: Cell<State<D>>,
+    // This field must be first, for correctness of `#[rustc_align_static]`
     value: UnsafeCell<MaybeUninit<T>>,
+    state: Cell<State<D>>,
 }
 
 impl<T, D> Storage<T, D>
diff --git a/library/std/src/sys/thread_local/native/mod.rs b/library/std/src/sys/thread_local/native/mod.rs
index a5dffe3c458..5dc14240804 100644
--- a/library/std/src/sys/thread_local/native/mod.rs
+++ b/library/std/src/sys/thread_local/native/mod.rs
@@ -54,7 +54,7 @@ pub macro thread_local_inner {
     // test in `tests/thread.rs` if these types are renamed.
 
     // Used to generate the `LocalKey` value for const-initialized thread locals.
-    (@key $t:ty, const $init:expr) => {{
+    (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
         const __INIT: $t = $init;
 
         unsafe {
@@ -62,6 +62,7 @@ pub macro thread_local_inner {
                 if $crate::mem::needs_drop::<$t>() {
                     |_| {
                         #[thread_local]
+                        $(#[$align_attr])*
                         static VAL: $crate::thread::local_impl::EagerStorage<$t>
                             = $crate::thread::local_impl::EagerStorage::new(__INIT);
                         VAL.get()
@@ -69,6 +70,7 @@ pub macro thread_local_inner {
                 } else {
                     |_| {
                         #[thread_local]
+                        $(#[$align_attr])*
                         static VAL: $t = __INIT;
                         &VAL
                     }
@@ -78,7 +80,7 @@ pub macro thread_local_inner {
     }},
 
     // used to generate the `LocalKey` value for `thread_local!`
-    (@key $t:ty, $init:expr) => {{
+    (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
         #[inline]
         fn __init() -> $t {
             $init
@@ -89,6 +91,7 @@ pub macro thread_local_inner {
                 if $crate::mem::needs_drop::<$t>() {
                     |init| {
                         #[thread_local]
+                        $(#[$align_attr])*
                         static VAL: $crate::thread::local_impl::LazyStorage<$t, ()>
                             = $crate::thread::local_impl::LazyStorage::new();
                         VAL.get_or_init(init, __init)
@@ -96,6 +99,7 @@ pub macro thread_local_inner {
                 } else {
                     |init| {
                         #[thread_local]
+                        $(#[$align_attr])*
                         static VAL: $crate::thread::local_impl::LazyStorage<$t, !>
                             = $crate::thread::local_impl::LazyStorage::new();
                         VAL.get_or_init(init, __init)
@@ -104,10 +108,6 @@ pub macro thread_local_inner {
             })
         }
     }},
-    ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
-        $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
-            $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
-    },
 }
 
 #[rustc_macro_transparency = "semitransparent"]
diff --git a/library/std/src/sys/thread_local/no_threads.rs b/library/std/src/sys/thread_local/no_threads.rs
index 4da01a84acf..409dfb19518 100644
--- a/library/std/src/sys/thread_local/no_threads.rs
+++ b/library/std/src/sys/thread_local/no_threads.rs
@@ -2,6 +2,7 @@
 //! thread locals and we can instead just use plain statics!
 
 use crate::cell::{Cell, UnsafeCell};
+use crate::mem::MaybeUninit;
 use crate::ptr;
 
 #[doc(hidden)]
@@ -11,12 +12,13 @@ use crate::ptr;
 #[rustc_macro_transparency = "semitransparent"]
 pub macro thread_local_inner {
     // used to generate the `LocalKey` value for const-initialized thread locals
-    (@key $t:ty, const $init:expr) => {{
+    (@key $t:ty, $(#[$align_attr:meta])*, const $init:expr) => {{
         const __INIT: $t = $init;
 
         // NOTE: Please update the shadowing test in `tests/thread.rs` if these types are renamed.
         unsafe {
             $crate::thread::LocalKey::new(|_| {
+                $(#[$align_attr])*
                 static VAL: $crate::thread::local_impl::EagerStorage<$t> =
                     $crate::thread::local_impl::EagerStorage { value: __INIT };
                 &VAL.value
@@ -25,27 +27,22 @@ pub macro thread_local_inner {
     }},
 
     // used to generate the `LocalKey` value for `thread_local!`
-    (@key $t:ty, $init:expr) => {{
+    (@key $t:ty, $(#[$align_attr:meta])*, $init:expr) => {{
         #[inline]
         fn __init() -> $t { $init }
 
         unsafe {
-            use $crate::thread::LocalKey;
-            use $crate::thread::local_impl::LazyStorage;
-
-            LocalKey::new(|init| {
-                static VAL: LazyStorage<$t> = LazyStorage::new();
+            $crate::thread::LocalKey::new(|init| {
+                $(#[$align_attr])*
+                static VAL: $crate::thread::local_impl::LazyStorage<$t> = $crate::thread::local_impl::LazyStorage::new();
                 VAL.get(init, __init)
             })
         }
     }},
-    ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
-        $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
-            $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
-    },
 }
 
 #[allow(missing_debug_implementations)]
+#[repr(transparent)] // Required for correctness of `#[rustc_align_static]`
 pub struct EagerStorage<T> {
     pub value: T,
 }
@@ -53,14 +50,27 @@ pub struct EagerStorage<T> {
 // SAFETY: the target doesn't have threads.
 unsafe impl<T> Sync for EagerStorage<T> {}
 
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum State {
+    Initial,
+    Alive,
+    Destroying,
+}
+
 #[allow(missing_debug_implementations)]
+#[repr(C)]
 pub struct LazyStorage<T> {
-    value: UnsafeCell<Option<T>>,
+    // This field must be first, for correctness of `#[rustc_align_static]`
+    value: UnsafeCell<MaybeUninit<T>>,
+    state: Cell<State>,
 }
 
 impl<T> LazyStorage<T> {
     pub const fn new() -> LazyStorage<T> {
-        LazyStorage { value: UnsafeCell::new(None) }
+        LazyStorage {
+            value: UnsafeCell::new(MaybeUninit::uninit()),
+            state: Cell::new(State::Initial),
+        }
     }
 
     /// Gets a pointer to the TLS value, potentially initializing it with the
@@ -70,24 +80,39 @@ impl<T> LazyStorage<T> {
     /// has occurred.
     #[inline]
     pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
-        let value = unsafe { &*self.value.get() };
-        match value {
-            Some(v) => v,
-            None => self.initialize(i, f),
+        if self.state.get() == State::Alive {
+            self.value.get() as *const T
+        } else {
+            self.initialize(i, f)
         }
     }
 
     #[cold]
     fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T {
         let value = i.and_then(Option::take).unwrap_or_else(f);
-        // Destroy the old value, after updating the TLS variable as the
-        // destructor might reference it.
+
+        // Destroy the old value if it is initialized
         // FIXME(#110897): maybe panic on recursive initialization.
+        if self.state.get() == State::Alive {
+            self.state.set(State::Destroying);
+            // Safety: we check for no initialization during drop below
+            unsafe {
+                ptr::drop_in_place(self.value.get() as *mut T);
+            }
+            self.state.set(State::Initial);
+        }
+
+        // Guard against initialization during drop
+        if self.state.get() == State::Destroying {
+            panic!("Attempted to initialize thread-local while it is being dropped");
+        }
+
         unsafe {
-            self.value.get().replace(Some(value));
+            self.value.get().write(MaybeUninit::new(value));
         }
-        // SAFETY: we just set this to `Some`.
-        unsafe { (*self.value.get()).as_ref().unwrap_unchecked() }
+        self.state.set(State::Alive);
+
+        self.value.get() as *const T
     }
 }
 
diff --git a/library/std/src/sys/thread_local/os.rs b/library/std/src/sys/thread_local/os.rs
index fe6af27db3a..88bb5ae7c65 100644
--- a/library/std/src/sys/thread_local/os.rs
+++ b/library/std/src/sys/thread_local/os.rs
@@ -1,8 +1,12 @@
 use super::key::{Key, LazyKey, get, set};
 use super::{abort_on_dtor_unwind, guard};
+use crate::alloc::{self, Layout};
 use crate::cell::Cell;
 use crate::marker::PhantomData;
-use crate::ptr;
+use crate::mem::ManuallyDrop;
+use crate::ops::Deref;
+use crate::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
+use crate::ptr::{self, NonNull};
 
 #[doc(hidden)]
 #[allow_internal_unstable(thread_local_internals)]
@@ -10,17 +14,12 @@ use crate::ptr;
 #[unstable(feature = "thread_local_internals", issue = "none")]
 #[rustc_macro_transparency = "semitransparent"]
 pub macro thread_local_inner {
-    // used to generate the `LocalKey` value for const-initialized thread locals
-    (@key $t:ty, const $init:expr) => {
-        $crate::thread::local_impl::thread_local_inner!(@key $t, { const INIT_EXPR: $t = $init; INIT_EXPR })
-    },
-
     // NOTE: we cannot import `Storage` or `LocalKey` with a `use` because that can shadow user
     // provided type or type alias with a matching name. Please update the shadowing test in
     // `tests/thread.rs` if these types are renamed.
 
     // used to generate the `LocalKey` value for `thread_local!`.
-    (@key $t:ty, $init:expr) => {{
+    (@key $t:ty, $($(#[$($align_attr:tt)*])+)?, $init:expr) => {{
         #[inline]
         fn __init() -> $t { $init }
 
@@ -29,37 +28,148 @@ pub macro thread_local_inner {
         // in `tests/thread.rs` if these types are renamed.
         unsafe {
             $crate::thread::LocalKey::new(|init| {
-                static VAL: $crate::thread::local_impl::Storage<$t>
+                static VAL: $crate::thread::local_impl::Storage<$t, {
+                    $({
+                        // Ensure that attributes have valid syntax
+                        // and that the proper feature gate is enabled
+                        $(#[$($align_attr)*])+
+                        #[allow(unused)]
+                        static DUMMY: () = ();
+                    })?
+
+                    #[allow(unused_mut)]
+                    let mut final_align = $crate::thread::local_impl::value_align::<$t>();
+                    $($($crate::thread::local_impl::thread_local_inner!(@align final_align, $($align_attr)*);)+)?
+                    final_align
+                }>
                     = $crate::thread::local_impl::Storage::new();
                 VAL.get(init, __init)
             })
         }
     }},
-    ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => {
-        $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> =
-            $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*);
+
+    // process a single `rustc_align_static` attribute
+    (@align $final_align:ident, rustc_align_static($($align:tt)*) $(, $($attr_rest:tt)+)?) => {
+        let new_align: $crate::primitive::usize = $($align)*;
+        if new_align > $final_align {
+            $final_align = new_align;
+        }
+
+        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
+    },
+
+    // process a single `cfg_attr` attribute
+    // by translating it into a `cfg`ed block and recursing.
+    // https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate
+
+    (@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
+        #[cfg(true)]
+        {
+            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
+        }
+
+        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
+    },
+
+    (@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
+        #[cfg(false)]
+        {
+            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
+        }
+
+        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
+    },
+
+    (@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
+        #[cfg($cfg_pred)]
+        {
+            $crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
+        }
+
+        $($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
     },
 }
 
 /// Use a regular global static to store this key; the state provided will then be
 /// thread-local.
+/// INVARIANT: ALIGN must be a valid alignment, and no less than `value_align::<T>`.
 #[allow(missing_debug_implementations)]
-pub struct Storage<T> {
+pub struct Storage<T, const ALIGN: usize> {
     key: LazyKey,
     marker: PhantomData<Cell<T>>,
 }
 
-unsafe impl<T> Sync for Storage<T> {}
+unsafe impl<T, const ALIGN: usize> Sync for Storage<T, ALIGN> {}
 
+#[repr(C)]
 struct Value<T: 'static> {
+    // This field must be first, for correctness of `#[rustc_align_static]`
     value: T,
     // INVARIANT: if this value is stored under a TLS key, `key` must be that `key`.
     key: Key,
 }
 
-impl<T: 'static> Storage<T> {
-    pub const fn new() -> Storage<T> {
-        Storage { key: LazyKey::new(Some(destroy_value::<T>)), marker: PhantomData }
+pub const fn value_align<T: 'static>() -> usize {
+    crate::mem::align_of::<Value<T>>()
+}
+
+/// Equivalent to `Box<Value<T>>`, but potentially over-aligned.
+struct AlignedBox<T: 'static, const ALIGN: usize> {
+    ptr: NonNull<Value<T>>,
+}
+
+impl<T: 'static, const ALIGN: usize> AlignedBox<T, ALIGN> {
+    #[inline]
+    fn new(v: Value<T>) -> Self {
+        let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
+
+        let ptr: *mut Value<T> = (unsafe { alloc::alloc(layout) }).cast();
+        let Some(ptr) = NonNull::new(ptr) else {
+            alloc::handle_alloc_error(layout);
+        };
+        unsafe { ptr.write(v) };
+        Self { ptr }
+    }
+
+    #[inline]
+    fn into_raw(b: Self) -> *mut Value<T> {
+        let md = ManuallyDrop::new(b);
+        md.ptr.as_ptr()
+    }
+
+    #[inline]
+    unsafe fn from_raw(ptr: *mut Value<T>) -> Self {
+        Self { ptr: unsafe { NonNull::new_unchecked(ptr) } }
+    }
+}
+
+impl<T: 'static, const ALIGN: usize> Deref for AlignedBox<T, ALIGN> {
+    type Target = Value<T>;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        unsafe { &*(self.ptr.as_ptr()) }
+    }
+}
+
+impl<T: 'static, const ALIGN: usize> Drop for AlignedBox<T, ALIGN> {
+    #[inline]
+    fn drop(&mut self) {
+        let layout = Layout::new::<Value<T>>().align_to(ALIGN).unwrap();
+
+        unsafe {
+            let unwind_result = catch_unwind(AssertUnwindSafe(|| self.ptr.drop_in_place()));
+            alloc::dealloc(self.ptr.as_ptr().cast(), layout);
+            if let Err(payload) = unwind_result {
+                resume_unwind(payload);
+            }
+        }
+    }
+}
+
+impl<T: 'static, const ALIGN: usize> Storage<T, ALIGN> {
+    pub const fn new() -> Storage<T, ALIGN> {
+        Storage { key: LazyKey::new(Some(destroy_value::<T, ALIGN>)), marker: PhantomData }
     }
 
     /// Gets a pointer to the TLS value, potentially initializing it with the
@@ -95,8 +205,11 @@ impl<T: 'static> Storage<T> {
             return ptr::null();
         }
 
-        let value = Box::new(Value { value: i.and_then(Option::take).unwrap_or_else(f), key });
-        let ptr = Box::into_raw(value);
+        let value = AlignedBox::<T, ALIGN>::new(Value {
+            value: i.and_then(Option::take).unwrap_or_else(f),
+            key,
+        });
+        let ptr = AlignedBox::into_raw(value);
 
         // SAFETY:
         // * key came from a `LazyKey` and is thus correct.
@@ -114,7 +227,7 @@ impl<T: 'static> Storage<T> {
             // initializer has already returned and the next scope only starts
             // after we return the pointer. Therefore, there can be no references
             // to the old value.
-            drop(unsafe { Box::from_raw(old) });
+            drop(unsafe { AlignedBox::<T, ALIGN>::from_raw(old) });
         }
 
         // SAFETY: We just created this value above.
@@ -122,7 +235,7 @@ impl<T: 'static> Storage<T> {
     }
 }
 
-unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
+unsafe extern "C" fn destroy_value<T: 'static, const ALIGN: usize>(ptr: *mut u8) {
     // SAFETY:
     //
     // The OS TLS ensures that this key contains a null value when this
@@ -133,7 +246,7 @@ unsafe extern "C" fn destroy_value<T: 'static>(ptr: *mut u8) {
     // Note that to prevent an infinite loop we reset it back to null right
     // before we return from the destructor ourselves.
     abort_on_dtor_unwind(|| {
-        let ptr = unsafe { Box::from_raw(ptr as *mut Value<T>) };
+        let ptr = unsafe { AlignedBox::<T, ALIGN>::from_raw(ptr as *mut Value<T>) };
         let key = ptr.key;
         // SAFETY: `key` is the TLS key `ptr` was stored under.
         unsafe { set(key, ptr::without_provenance_mut(1)) };
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 0a6f2e5d508..4259a4d1f3b 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -132,6 +132,216 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
     }
 }
 
+#[doc(hidden)]
+#[allow_internal_unstable(thread_local_internals)]
+#[unstable(feature = "thread_local_internals", issue = "none")]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro thread_local_process_attrs {
+
+    // Parse `cfg_attr` to figure out whether it's a `rustc_align_static`.
+    // Each `cfg_attr` can have zero or more attributes on the RHS, and can be nested.
+
+    // finished parsing the `cfg_attr`, it had no `rustc_align_static`
+    (
+        [] [$(#[$($prev_other_attrs:tt)*])*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] };
+        [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*];
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs_ret)*] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),*)]];
+            $($rest)*
+        );
+    ),
+
+    // finished parsing the `cfg_attr`, it had nothing but `rustc_align_static`
+    (
+        [$(#[$($prev_align_attrs:tt)*])+] [];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] };
+        [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*];
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs_ret)*  #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)*];
+            $($rest)*
+        );
+    ),
+
+    // finished parsing the `cfg_attr`, it had a mix of `rustc_align_static` and other attrs
+    (
+        [$(#[$($prev_align_attrs:tt)*])+] [$(#[$($prev_other_attrs:tt)*])+];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [] };
+        [$($prev_align_attrs_ret:tt)*] [$($prev_other_attrs_ret:tt)*];
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs_ret)*  #[cfg_attr($($predicate)*, $($($prev_align_attrs)*),+)]] [$($prev_other_attrs_ret)* #[cfg_attr($($predicate)*, $($($prev_other_attrs)*),+)]];
+            $($rest)*
+        );
+    ),
+
+    // it's a `rustc_align_static`
+    (
+        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [rustc_align_static($($align_static_args:tt)*) $(, $($attr_rhs:tt)*)?] };
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)* #[rustc_align_static($($align_static_args)*)]] [$($prev_other_attrs)*];
+            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
+            $($rest)*
+        );
+    ),
+
+    // it's a nested `cfg_attr(true, ...)`; recurse into RHS
+    (
+        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
+            $($rest)*
+        );
+    ),
+
+    // it's a nested `cfg_attr(false, ...)`; recurse into RHS
+    (
+        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
+            $($rest)*
+        );
+    ),
+
+
+    // it's a nested `cfg_attr(..., ...)`; recurse into RHS
+    (
+        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: ($cfg_lhs), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
+            $($rest)*
+        );
+    ),
+
+    // it's some other attribute
+    (
+        [$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+        @processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [$meta:meta $(, $($attr_rhs:tt)*)?] };
+        $($rest:tt)*
+    ) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$meta]];
+            @processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
+            $($rest)*
+        );
+    ),
+
+
+    // Separate attributes into `rustc_align_static` and everything else:
+
+    // `rustc_align_static` attribute
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[rustc_align_static $($attr_rest:tt)*] $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)* #[rustc_align_static $($attr_rest)*]] [$($prev_other_attrs)*];
+            $($rest)*
+        );
+    ),
+
+    // `cfg_attr(true, ...)` attribute; parse it
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            $($rest)*
+        );
+    ),
+
+    // `cfg_attr(false, ...)` attribute; parse it
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            $($rest)*
+        );
+    ),
+
+    // `cfg_attr(..., ...)` attribute; parse it
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [] [];
+            @processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] };
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*];
+            $($rest)*
+        );
+    ),
+
+    // doc comment not followed by any other attributes; process it all at once to avoid blowing recursion limit
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; $(#[doc $($doc_rhs:tt)*])+ $vis:vis static $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)*] [$($prev_other_attrs)* $(#[doc $($doc_rhs)*])+];
+            $vis static $($rest)*
+        );
+    ),
+
+    // 8 lines of doc comment; process them all at once to avoid blowing recursion limit
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
+     #[doc $($doc_rhs_1:tt)*] #[doc $($doc_rhs_2:tt)*] #[doc $($doc_rhs_3:tt)*] #[doc $($doc_rhs_4:tt)*]
+     #[doc $($doc_rhs_5:tt)*] #[doc $($doc_rhs_6:tt)*] #[doc $($doc_rhs_7:tt)*] #[doc $($doc_rhs_8:tt)*]
+     $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)*] [$($prev_other_attrs)*
+            #[doc $($doc_rhs_1)*] #[doc $($doc_rhs_2)*] #[doc $($doc_rhs_3)*] #[doc $($doc_rhs_4)*]
+            #[doc $($doc_rhs_5)*] #[doc $($doc_rhs_6)*] #[doc $($doc_rhs_7)*] #[doc $($doc_rhs_8)*]];
+            $($rest)*
+        );
+    ),
+
+    // other attribute
+    ([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[$($attr:tt)*] $($rest:tt)*) => (
+        $crate::thread::local_impl::thread_local_process_attrs!(
+            [$($prev_align_attrs)*] [$($prev_other_attrs)* #[$($attr)*]];
+            $($rest)*
+        );
+    ),
+
+
+    // Delegate to `thread_local_inner` once attributes are fully categorized:
+
+    // process `const` declaration and recurse
+    ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = const $init:block $(; $($($rest:tt)+)?)?) => (
+        $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> =
+            $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, const $init);
+
+        $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)?
+    ),
+
+    // process non-`const` declaration and recurse
+    ([$($align_attrs:tt)*] [$($other_attrs:tt)*]; $vis:vis static $name:ident: $t:ty = $init:expr $(; $($($rest:tt)+)?)?) => (
+        $($other_attrs)* $vis const $name: $crate::thread::LocalKey<$t> =
+            $crate::thread::local_impl::thread_local_inner!(@key $t, $($align_attrs)*, $init);
+
+        $($($crate::thread::local_impl::thread_local_process_attrs!([] []; $($rest)+);)?)?
+    ),
+}
+
 /// Declare a new thread local storage key of type [`std::thread::LocalKey`].
 ///
 /// # Syntax
@@ -182,28 +392,11 @@ impl<T: 'static> fmt::Debug for LocalKey<T> {
 #[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
 #[allow_internal_unstable(thread_local_internals)]
 macro_rules! thread_local {
-    // empty (base case for the recursion)
     () => {};
 
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block; $($rest:tt)*) => (
-        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
-        $crate::thread_local!($($rest)*);
-    );
-
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = const $init:block) => (
-        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, const $init);
-    );
-
-    // process multiple declarations
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => (
-        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
-        $crate::thread_local!($($rest)*);
-    );
-
-    // handle a single declaration
-    ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => (
-        $crate::thread::local_impl::thread_local_inner!($(#[$attr])* $vis $name, $t, $init);
-    );
+    ($($tt:tt)+) => {
+        $crate::thread::local_impl::thread_local_process_attrs!([] []; $($tt)+);
+    };
 }
 
 /// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 1768369792a..fd7cce3f97d 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -207,6 +207,7 @@ pub use self::local::{AccessError, LocalKey};
 #[doc(hidden)]
 #[unstable(feature = "thread_local_internals", issue = "none")]
 pub mod local_impl {
+    pub use super::local::thread_local_process_attrs;
     pub use crate::sys::thread_local::*;
 }
 
diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs
index 29f220d8a70..dc8eadd7514 100644
--- a/library/std/tests/thread.rs
+++ b/library/std/tests/thread.rs
@@ -66,6 +66,8 @@ fn thread_local_hygeiene() {
     type Storage = ();
     type LazyStorage = ();
     type EagerStorage = ();
+    #[allow(non_camel_case_types)]
+    type usize = ();
     thread_local! {
         static A: LocalKey = const { () };
         static B: Storage = const { () };
diff --git a/src/bootstrap/defaults/bootstrap.dist.toml b/src/bootstrap/defaults/bootstrap.dist.toml
index b111a20f8d8..bb0592ce947 100644
--- a/src/bootstrap/defaults/bootstrap.dist.toml
+++ b/src/bootstrap/defaults/bootstrap.dist.toml
@@ -7,8 +7,6 @@ test-stage = 2
 doc-stage = 2
 # When compiling from source, you usually want all tools.
 extended = true
-# Use libtest built from the source tree instead of the precompiled one from stage 0.
-compiletest-use-stage0-libtest = false
 
 # Most users installing from source want to build all parts of the project from source.
 [llvm]
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 9f9af1d9abe..4b0080f1c80 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -587,6 +587,7 @@ Select which editor you would like to set up [default: None]: ";
                 "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
                 "080955765db84bb6cbf178879f489c4e2369397626a6ecb3debedb94a9d0b3ce",
                 "f501475c6654187091c924ae26187fa5791d74d4a8ab3fb61fbbe4c0275aade1",
+                "e260553b71e4773c30a63c4b23b42b279fc73e72f95b775c47b7b7c511c51595",
             ],
             EditorKind::Helix => &[
                 "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
@@ -594,6 +595,7 @@ Select which editor you would like to set up [default: None]: ";
                 "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5",
                 "198c195ed0c070d15907b279b8b4ea96198ca71b939f5376454f3d636ab54da5",
                 "1c43ead340b20792b91d02b08494ee68708e7e09f56b6766629b4b72079208f1",
+                "eec09a09452682060afd23dd5d3536ccac5615b3cdbf427366446901215fb9f6",
             ],
             EditorKind::Vim | EditorKind::VsCode => &[
                 "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
@@ -610,6 +612,7 @@ Select which editor you would like to set up [default: None]: ";
                 "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
                 "701b73751efd7abd6487f2c79348dab698af7ac4427b79fa3d2087c867144b12",
                 "a61df796c0c007cb6512127330564e49e57d558dec715703916a928b072a1054",
+                "02a49ac2d31f00ef6e4531c44e00dac51cea895112e480553f1ba060b3942a47",
             ],
             EditorKind::Zed => &[
                 "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
@@ -617,6 +620,7 @@ Select which editor you would like to set up [default: None]: ";
                 "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
                 "4fadd4c87389a601a27db0d3d74a142fa3a2e656ae78982e934dbe24bee32ad6",
                 "f0bb3d23ab1a49175ab0ef5c4071af95bb03d01d460776cdb716d91333443382",
+                "5ef83292111d9a8bb63b6afc3abf42d0bc78fe24985f0d2e039e73258b5dab8f",
             ],
         }
     }
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 006dea4b98d..fc06db8f80b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1145,7 +1145,7 @@ impl<'a> Builder<'a> {
                 test::RunMakeCargo,
             ),
             Kind::Miri => describe!(test::Crate),
-            Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
+            Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc),
             Kind::Doc => describe!(
                 doc::UnstableBook,
                 doc::UnstableBookGen,
diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml
index f61243a4d71..078b877e44b 100644
--- a/src/ci/citool/Cargo.toml
+++ b/src/ci/citool/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "citool"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 anyhow = "1"
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index fe1b36673a1..255d39846da 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -24,7 +24,7 @@ use crate::github::JobInfoResolver;
 use crate::jobs::RunType;
 use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
 use crate::test_dashboard::generate_test_dashboard;
-use crate::utils::{load_env_var, output_details};
+use crate::utils::{init_submodule_if_needed, load_env_var, output_details};
 
 const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
 pub const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
@@ -121,6 +121,8 @@ fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> any
         (key.clone(), value)
     }));
 
+    init_submodule_if_needed("src/llvm-project/")?;
+
     let mut cmd = Command::new(Path::new(DOCKER_DIRECTORY).join("run.sh"));
     cmd.arg(job.image());
     cmd.envs(custom_env);
diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs
index 3176cb62f60..43b220255dc 100644
--- a/src/ci/citool/src/utils.rs
+++ b/src/ci/citool/src/utils.rs
@@ -1,5 +1,7 @@
 use std::borrow::Cow;
+use std::convert::AsRef;
 use std::path::Path;
+use std::process::Command;
 
 use anyhow::Context;
 
@@ -34,3 +36,19 @@ where
 pub fn normalize_path_delimiters(name: &str) -> Cow<'_, str> {
     if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() }
 }
+
+pub fn init_submodule_if_needed<P: AsRef<Path>>(path_to_submodule: P) -> anyhow::Result<()> {
+    let path_to_submodule = path_to_submodule.as_ref();
+
+    if let Ok(mut iter) = path_to_submodule.read_dir()
+        && iter.any(|entry| entry.is_ok())
+    {
+        // Seems like the submodule is already initialized, nothing to be done here.
+        return Ok(());
+    }
+    let mut child = Command::new("git")
+        .args(&["submodule", "update", "--init"])
+        .arg(path_to_submodule)
+        .spawn()?;
+    if !child.wait()?.success() { Err(anyhow::anyhow!("git command failed")) } else { Ok(()) }
+}
diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml
index d82b3e7648e..512c8062857 100644
--- a/src/ci/citool/tests/test-jobs.yml
+++ b/src/ci/citool/tests/test-jobs.yml
@@ -27,7 +27,7 @@ runners:
     <<: *base-job
 envs:
   env-x86_64-apple-tests: &env-x86_64-apple-tests
-    SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
+    SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
     RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
     RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
     # Ensure that host tooling is tested on our minimum supported macOS version.
diff --git a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
index 04ac0f33daf..776bbb12e44 100644
--- a/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-1/Dockerfile
@@ -43,7 +43,6 @@ ENV SCRIPT \
   python3 ../x.py check bootstrap && \
   /scripts/check-default-config-profiles.sh && \
   python3 ../x.py build src/tools/build-manifest && \
-  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
   python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
   /scripts/validate-toolstate.sh && \
diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
index d6470e4deb8..0a95f428f5b 100644
--- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
@@ -32,7 +32,7 @@ ENV SCRIPT \
         python3 ../x.py clippy ci --stage 2 && \
         python3 ../x.py test --stage 1 core alloc std test proc_macro && \
         python3 ../x.py test --stage 1 src/tools/compiletest && \
-        python3 ../x.py doc bootstrap && \
+        python3 ../x.py doc bootstrap --stage 1 && \
         # Build both public and internal documentation.
         RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 1 && \
         RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 1 && \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index 95357d22937..278e40eb71f 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -90,5 +90,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
 COPY scripts/shared.sh /scripts/
 
 ENV SCRIPT /tmp/checktools.sh ../x.py && \
-  python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
   python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
diff --git a/src/doc/book b/src/doc/book
-Subproject 33f1af40cc44dde7e3e892f7a508e6f427d2cbc
+Subproject 1d7c3e6abec2d5a9bfac798b29b7855b9502542
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject aa6ce337c0adf7a63e33960d184270f2a45ab9e
+Subproject e2ed891f00361efc26616d82590b1c85d7a8920
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject f17a018b9989430967d1c58e9a12c51169abc74
+Subproject 23fc2682f8fcb887f77d0eaabba708809f834c1
diff --git a/src/doc/reference b/src/doc/reference
-Subproject cc7247d8dfaef4c39000bb12c55c32ba5b5ba97
+Subproject e11adf6016a362766eea5a3f9832e193994dd0c
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 4be78fac4ec..3b6c8917464 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -262,6 +262,20 @@ Consider writing the test as a proper incremental test instead.
 
 </div>
 
+#### The edition directive
+
+The `//@ edition` directive can take an exact edition, a bounded half-open range of editions or a left-bounded half-open range of editions, this affects which edition is used by `./x test` to run the test. For example:
+
+- A test with the `//@ edition: 2018` directive will only run under the 2018 edition.
+- A test with the `//@ edition: 2015..2021` directive can be run under both the 2015 and 2018 editions. However, CI will only run the test with the lowest edition possible (2015 in this case).
+- A test with the `//@ edition: 2018..` directive will run under any edition greater or equal than 2018. However, CI will only run the test with the lowest edition possible (2018 in this case).
+
+You can also force `./x test` to use a specific edition by passing the `-- --edition=` argument. However, tests with the `//@ edition` directive will clamp the value passed to the argument. For example, if we run `./x test -- --edition=2015`:
+
+- A test with the `//@ edition: 2018` will run with the 2018 edition. 
+- A test with the `//@ edition: 2015..2021` will be run with the 2015 edition. 
+- A test with the `//@ edition: 2018..` will run with the 2018 edition. 
+
 ### Rustdoc
 
 | Directive   | Explanation                                                  | Supported test suites                   | Possible values           |
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 67882bb3813..a9ce738a013 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -47,6 +47,7 @@
     - [\*-apple-watchos](platform-support/apple-watchos.md)
     - [\*-apple-visionos](platform-support/apple-visionos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
+    - [aarch64-unknown-linux-gnu](platform-support/aarch64-unknown-linux-gnu.md)
     - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
     - [aarch64-unknown-none*](platform-support/aarch64-unknown-none.md)
     - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
@@ -67,6 +68,7 @@
     - [arm\*-unknown-linux-\*](./platform-support/arm-linux.md)
         - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
         - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md)
+        - [armv7-unknown-linux-gnueabi](platform-support/armv7-unknown-linux-gnueabi.md)
         - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
         - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md)
diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md
index 5b002b435a5..09b55da741d 100644
--- a/src/doc/rustc/src/lints/levels.md
+++ b/src/doc/rustc/src/lints/levels.md
@@ -38,7 +38,7 @@ talk about later in this section.
 
 Sometimes, it can be helpful to suppress lints, but at the same time ensure that
 the code in question still emits them. The 'expect' level does exactly this. If
-the lint in question is not emitted, the `unfulfilled_lint_expectation` lint
+the lint in question is not emitted, the `unfulfilled_lint_expectations` lint
 triggers on the `expect` attribute, notifying you that the expectation is no
 longer fulfilled.
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index d0b6ed51bc1..263ea1ddb42 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,7 +34,7 @@ target | notes
 -------|-------
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 [`aarch64-pc-windows-msvc`](platform-support/windows-msvc.md) | ARM64 Windows MSVC
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
+[`aarch64-unknown-linux-gnu`](platform-support/aarch64-unknown-linux-gnu.md) | ARM64 Linux (kernel 4.1+, glibc 2.17+)
 [`i686-pc-windows-msvc`](platform-support/windows-msvc.md) | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-pc-windows-gnu`](platform-support/windows-gnu.md) | 64-bit MinGW (Windows 10+, Windows Server 2016+)
@@ -93,7 +93,7 @@ target | notes
 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
 `arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17)
-`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
+[`armv7-unknown-linux-gnueabihf`](platform-support/armv7-unknown-linux-gnueabi.md) | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
 [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
 [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36), LSX required
 [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5), LSX required
@@ -159,7 +159,7 @@ target | std | notes
 [`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
-`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
+[`armv7-unknown-linux-gnueabi`](platform-support/armv7-unknown-linux-gnueabi.md) | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
 `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3
 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat
 [`armv7a-none-eabi`](platform-support/armv7a-none-eabi.md) | * | Bare Armv7-A
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md
new file mode 100644
index 00000000000..2003a3cb9ea
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/aarch64-unknown-linux-gnu.md
@@ -0,0 +1,50 @@
+# `aarch64-unknown-linux-gnu`
+
+**Tier: 1 (with Host Tools)**
+
+Target for 64-bit little endian ARMv8-A Linux 4.1+ programs using glibc 2.17+.
+
+## Target maintainers
+
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
+
+## Requirements
+
+Building the target itself requires a 64-bit little endian ARMv8-A compiler that is supported by
+`cc-rs`.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+target = ["aarch64-unknown-linux-gnu"]
+```
+
+If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the
+`bootstrap.toml`:
+
+```toml
+[target.aarch64-unknown-linux-musl]
+cc = "aarch64-linux-gnu-gcc"
+cxx = "aarch64-linux-gnu-g++"
+ar = "aarch64-linux-gnu-ar"
+linker = "aarch64-linux-gnu-gcc"
+```
+
+## Building Rust programs
+
+This target is distributed through `rustup`, and otherwise requires no special configuration.
+
+## Cross-compilation
+
+This target can be cross-compiled from any host.
+
+## Testing
+
+This target can be tested as normal with `x.py` on a 64-bit little endian ARMv8-A host or via QEMU
+emulation.
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md
index 7e18e8c157f..3d776677d23 100644
--- a/src/doc/rustc/src/platform-support/aarch64-unknown-none.md
+++ b/src/doc/rustc/src/platform-support/aarch64-unknown-none.md
@@ -14,9 +14,12 @@ Processors in this family include the [Arm Cortex-A35, 53, 76, etc][aarch64-cpus
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team]
+- [Rust Embedded Devices Working Group Arm Team]
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
 
 [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/arm-linux.md b/src/doc/rustc/src/platform-support/arm-linux.md
index 5f40743f3d0..c461a1a3403 100644
--- a/src/doc/rustc/src/platform-support/arm-linux.md
+++ b/src/doc/rustc/src/platform-support/arm-linux.md
@@ -14,8 +14,8 @@ Linux (but not Android). Those targets are:
 * [`armv5te-unknown-linux-gnueabi`](armv5te-unknown-linux-gnueabi.md)
 * `armv5te-unknown-linux-musleabi`
 * `armv5te-unknown-linux-uclibceabi`
-* `armv7-unknown-linux-gnueabi`
-* `armv7-unknown-linux-gnueabihf`
+* [`armv7-unknown-linux-gnueabi`](armv7-unknown-linux-gnueabi.md)
+* [`armv7-unknown-linux-gnueabihf`](armv7-unknown-linux-gnueabi.md)
 * `armv7-unknown-linux-musleabi`
 * `armv7-unknown-linux-musleabihf`
 * `armv7-unknown-linux-ohos`
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md
new file mode 100644
index 00000000000..c2fe63a4908
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-gnueabi.md
@@ -0,0 +1,51 @@
+# `armv7-unknown-linux-gnueabi` and `armv7-unknown-linux-gnueabihf`
+
+* **Tier: 2 (with Host Tools)** for `armv7-unknown-linux-gnueabihf`
+* **Tier: 2** for `armv7-unknown-linux-gnueabi`
+
+Target for 32-bit little endian ARMv7-A Linux 3.2+ programs using glibc 2.17+.
+
+## Target maintainers
+
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
+
+## Requirements
+
+Building the targets themselves requires a 32-bit little endian ARMv7-A compiler that is supported
+by `cc-rs`.
+
+## Building the target
+
+These targets can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+target = ["armv7-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabi"]
+```
+
+If cross-compiling, make sure your C compiler is included in `$PATH`, then add it to the
+`bootstrap.toml`:
+
+```toml
+[target.aarch64-unknown-linux-musl]
+cc = "arm-linux-gnu-gcc"
+cxx = "arm-linux-gnu-g++"
+ar = "arm-linux-gnu-ar"
+linker = "arm-linux-gnu-gcc"
+```
+
+## Building Rust programs
+
+These targets is distributed through `rustup`, and otherwise requires no special configuration.
+
+## Cross-compilation
+
+These targets can be cross-compiled from any host.
+
+## Testing
+
+These targets can be tested as normal with `x.py` on a 32-bit little endian ARMv7-A host or via
+QEMU emulation.
diff --git a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md
index 3dadda86a5f..22278a0a7dc 100644
--- a/src/doc/rustc/src/platform-support/armv7a-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv7a-none-eabi.md
@@ -19,9 +19,12 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team]
+- [Rust Embedded Devices Working Group Arm Team]
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
 
 [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
index c1252b4a4bf..9429eb6ab8a 100644
--- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
@@ -15,10 +15,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-[@chrisnc](https://github.com/chrisnc)
-[Rust Embedded Devices Working Group Arm Team]
+- [@chrisnc](https://github.com/chrisnc)
+- [Rust Embedded Devices Working Group Arm Team]
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
 
 [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
index 0d5a36c3ee2..e465eb79f49 100644
--- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
+++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
@@ -17,10 +17,13 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-[@chrisnc](https://github.com/chrisnc)
-[Rust Embedded Devices Working Group Arm Team]
+- [@chrisnc](https://github.com/chrisnc)
+- [Rust Embedded Devices Working Group Arm Team]
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
 
 [Rust Embedded Devices Working Group Arm Team]: https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
index 98dcf9bd396..192e013d3a4 100644
--- a/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv7em-none-eabi.md
@@ -22,7 +22,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
index d8f3970c8bf..b04cb7bfacf 100644
--- a/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv7m-none-eabi.md
@@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv7-M].
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
index b16d450275d..104520854b4 100644
--- a/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv8m.base-none-eabi.md
@@ -23,7 +23,11 @@ only option because there is no FPU support in [Armv8-M] Baseline.
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
index a2d515d07ea..5cc535ce376 100644
--- a/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/thumbv8m.main-none-eabi.md
@@ -26,7 +26,11 @@ See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all
 
 ## Target maintainers
 
-[Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [Rust Embedded Devices Working Group Arm Team](https://github.com/rust-embedded/wg?tab=readme-ov-file#the-arm-team)
+- [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Target CPU and Target Feature options
 
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index 9587590d12d..e8989616b84 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -13,8 +13,12 @@ Available targets:
 
 ## Target maintainers
 
-[@dvdhrm](https://github.com/dvdhrm)
-[@nicholasbishop](https://github.com/nicholasbishop)
+- [@dvdhrm](https://github.com/dvdhrm)
+- [@nicholasbishop](https://github.com/nicholasbishop)
+- (for `aarch64-unknown-uefi` only) [@rust-lang/arm-maintainers][arm_maintainers] ([rust@arm.com][arm_email])
+
+[arm_maintainers]: https://github.com/rust-lang/team/blob/master/teams/arm-maintainers.toml
+[arm_email]: mailto:rust@arm.com
 
 ## Requirements
 
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index 65f18baa937..3eb964d2fba 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -761,7 +761,8 @@ class MSVCTupleSyntheticProvider:
 
     def get_child_at_index(self, index: int) -> SBValue:
         child: SBValue = self.valobj.GetChildAtIndex(index)
-        return child.CreateChildAtOffset(str(index), 0, child.GetType())
+        offset = self.valobj.GetType().GetFieldAtIndex(index).byte_offset
+        return self.valobj.CreateChildAtOffset(str(index), offset, child.GetType())
 
     def update(self):
         pass
@@ -772,7 +773,7 @@ class MSVCTupleSyntheticProvider:
     def get_type_name(self) -> str:
         name = self.valobj.GetTypeName()
         # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+
-        name = name[7:-1]
+        name = name[7:-1].strip()
         return "(" + name + ")"
 
 
diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el
index 3151cb1a6e7..e5abf67235a 100644
--- a/src/etc/rust_analyzer_eglot.el
+++ b/src/etc/rust_analyzer_eglot.el
@@ -6,6 +6,8 @@
                                        :overrideCommand ["python3"
                                                          "x.py"
                                                          "check"
+                                                         "--build-dir"
+                                                         "build-rust-analyzer"
                                                          "--json-output"])
                  :linkedProjects ["Cargo.toml"
                                   "compiler/rustc_codegen_cranelift/Cargo.toml"
@@ -13,9 +15,9 @@
                                   "library/Cargo.toml"
                                   "src/bootstrap/Cargo.toml"
                                   "src/tools/rust-analyzer/Cargo.toml"]
-                 :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
+                 :rustfmt ( :overrideCommand ["build-rust-analyzer/host/rustfmt/bin/rustfmt"
                                               "--edition=2024"])
-                 :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+                 :procMacro ( :server "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
                                       :enable t)
                  :cargo ( :buildScripts ( :enable t
                                                   :invocationLocation "root"
@@ -23,6 +25,8 @@
                                                   :overrideCommand ["python3"
                                                                     "x.py"
                                                                     "check"
+                                                                    "--build-dir"
+                                                                    "build-rust-analyzer"
                                                                     "--json-output"
                                                                     "--compile-time-deps"])]
                                         :sysrootSrc "./library"
diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml
index 8c1782a1abc..e2de2a374cb 100644
--- a/src/etc/rust_analyzer_helix.toml
+++ b/src/etc/rust_analyzer_helix.toml
@@ -1,10 +1,10 @@
 # This config uses a separate build directory for rust-analyzer,
 # so that r-a's checks don't block user `x` commands and vice-verse.
-# R-a's build directory is located in `build/rust-analyzer`.
+# R-a's build directory is located in `build-rust-analyzer`.
 #
 # To build rustfmt and proc macro server for r-a run the following command:
 # ```
-# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build/rust-analyzer
+# x b proc-macro-srv-cli rustfmt --stage 0 --build-dir build-rust-analyzer
 # ```
 
 [language-server.rust-analyzer.config]
@@ -26,17 +26,17 @@ overrideCommand = [
     "check",
     "--json-output",
     "--build-dir",
-    "build/rust-analyzer",
+    "build-rust-analyzer",
 ]
 
 [language-server.rust-analyzer.config.rustfmt]
 overrideCommand = [
-    "build/rust-analyzer/host/rustfmt/bin/rustfmt",
+    "build-rust-analyzer/host/rustfmt/bin/rustfmt",
     "--edition=2024"
 ]
 
 [language-server.rust-analyzer.config.procMacro]
-server = "build/rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
 enable = true
 
 [language-server.rust-analyzer.config.rustc]
@@ -58,6 +58,6 @@ overrideCommand = [
     "check",
     "--json-output",
     "--build-dir",
-    "build/rust-analyzer",
-    "--compile-time-deps"
+    "build-rust-analyzer",
+    "--compile-time-deps",
 ]
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index b31169857c5..f89e8a2df18 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -5,6 +5,8 @@
         "python3",
         "x.py",
         "check",
+        "--build-dir",
+        "build-rust-analyzer",
         "--json-output"
     ],
     "rust-analyzer.linkedProjects": [
@@ -16,10 +18,10 @@
         "src/tools/rust-analyzer/Cargo.toml"
     ],
     "rust-analyzer.rustfmt.overrideCommand": [
-        "${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
+        "${workspaceFolder}/build-rust-analyzer/host/rustfmt/bin/rustfmt",
         "--edition=2024"
     ],
-    "rust-analyzer.procMacro.server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv",
+    "rust-analyzer.procMacro.server": "${workspaceFolder}/build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv",
     "rust-analyzer.procMacro.enable": true,
     "rust-analyzer.cargo.buildScripts.enable": true,
     "rust-analyzer.cargo.buildScripts.invocationStrategy": "once",
@@ -27,6 +29,8 @@
         "python3",
         "x.py",
         "check",
+        "--build-dir",
+        "build-rust-analyzer",
         "--json-output",
         "--compile-time-deps"
     ],
diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json
index 7eace92500e..d98a082a9b8 100644
--- a/src/etc/rust_analyzer_zed.json
+++ b/src/etc/rust_analyzer_zed.json
@@ -7,7 +7,15 @@
             "enable": true,
             "invocationLocation": "root",
             "invocationStrategy": "once",
-            "overrideCommand": ["python3", "x.py", "check", "--json-output", "--compile-time-deps"]
+            "overrideCommand": [
+              "python3",
+              "x.py",
+              "check",
+              "--build-dir",
+              "build-rust-analyzer",
+              "--compile-time-deps",
+              "--json-output"
+            ]
           },
           "extraEnv": {
             "RUSTC_BOOTSTRAP": "1"
@@ -17,7 +25,14 @@
         "check": {
           "invocationLocation": "root",
           "invocationStrategy": "once",
-          "overrideCommand": ["python3", "x.py", "check", "--json-output"]
+          "overrideCommand": [
+            "python3",
+            "x.py",
+            "check",
+            "--json-output",
+            "--build-dir",
+            "build-rust-analyzer"
+          ]
         },
         "linkedProjects": [
           "Cargo.toml",
@@ -29,14 +44,14 @@
         ],
         "procMacro": {
           "enable": true,
-          "server": "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+          "server": "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv"
         },
         "rustc": {
           "source": "./Cargo.toml"
         },
         "rustfmt": {
           "overrideCommand": [
-            "build/host/rustfmt/bin/rustfmt",
+            "build-rust-analyzer/host/rustfmt/bin/rustfmt",
             "--edition=2024"
           ]
         },
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index aa614b73dea..881a81b22f0 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -3,14 +3,18 @@
 // FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
 // switch to use those structures instead.
 
+use std::sync::Arc;
 use std::{fmt, mem, ops};
 
 use itertools::Either;
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::attrs::AttributeKind;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::ParseSess;
 use rustc_span::Span;
 use rustc_span::symbol::{Symbol, sym};
+use {rustc_ast as ast, rustc_hir as hir};
 
 use crate::display::{Joined as _, MaybeDisplay, Wrapped};
 use crate::html::escape::Escape;
@@ -600,3 +604,264 @@ impl fmt::Display for Display<'_> {
         }
     }
 }
+
+/// This type keeps track of (doc) cfg information as we go down the item tree.
+#[derive(Clone, Debug)]
+pub(crate) struct CfgInfo {
+    /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
+    /// `doc(auto_cfg(show(...)))` cfgs.
+    hidden_cfg: FxHashSet<Cfg>,
+    /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
+    /// taking into account the `hidden_cfg` information.
+    current_cfg: Cfg,
+    /// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
+    auto_cfg_active: bool,
+    /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
+    /// instead we will concatenate with it. However, if it's not the case, we need to overwrite
+    /// `current_cfg`.
+    parent_is_doc_cfg: bool,
+}
+
+impl Default for CfgInfo {
+    fn default() -> Self {
+        Self {
+            hidden_cfg: FxHashSet::from_iter([
+                Cfg::Cfg(sym::test, None),
+                Cfg::Cfg(sym::doc, None),
+                Cfg::Cfg(sym::doctest, None),
+            ]),
+            current_cfg: Cfg::True,
+            auto_cfg_active: true,
+            parent_is_doc_cfg: false,
+        }
+    }
+}
+
+fn show_hide_show_conflict_error(
+    tcx: TyCtxt<'_>,
+    item_span: rustc_span::Span,
+    previous: rustc_span::Span,
+) {
+    let mut diag = tcx.sess.dcx().struct_span_err(
+        item_span,
+        format!(
+            "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
+        ),
+    );
+    diag.span_note(previous, "first change was here");
+    diag.emit();
+}
+
+/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
+///
+/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
+/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
+///
+/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
+/// and in `new_hide_attrs` arguments.
+fn handle_auto_cfg_hide_show(
+    tcx: TyCtxt<'_>,
+    cfg_info: &mut CfgInfo,
+    sub_attr: &MetaItemInner,
+    is_show: bool,
+    new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+    new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
+) {
+    if let MetaItemInner::MetaItem(item) = sub_attr
+        && let MetaItemKind::List(items) = &item.kind
+    {
+        for item in items {
+            // FIXME: Report in case `Cfg::parse` reports an error?
+            if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
+                if is_show {
+                    if let Some(span) = new_hide_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
+                    } else {
+                        new_show_attrs.insert((key, value), item.span());
+                    }
+                    cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
+                } else {
+                    if let Some(span) = new_show_attrs.get(&(key, value)) {
+                        show_hide_show_conflict_error(tcx, item.span(), *span);
+                    } else {
+                        new_hide_attrs.insert((key, value), item.span());
+                    }
+                    cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
+                }
+            }
+        }
+    }
+}
+
+pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
+    attrs: I,
+    tcx: TyCtxt<'_>,
+    cfg_info: &mut CfgInfo,
+) -> Option<Arc<Cfg>> {
+    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
+        let mut iter = it.into_iter();
+        let item = iter.next()?;
+        if iter.next().is_some() {
+            return None;
+        }
+        Some(item)
+    }
+
+    fn check_changed_auto_active_status(
+        changed_auto_active_status: &mut Option<rustc_span::Span>,
+        attr: &ast::MetaItem,
+        cfg_info: &mut CfgInfo,
+        tcx: TyCtxt<'_>,
+        new_value: bool,
+    ) -> bool {
+        if let Some(first_change) = changed_auto_active_status {
+            if cfg_info.auto_cfg_active != new_value {
+                tcx.sess
+                    .dcx()
+                    .struct_span_err(
+                        vec![*first_change, attr.span],
+                        "`auto_cfg` was disabled and enabled more than once on the same item",
+                    )
+                    .emit();
+                return true;
+            }
+        } else {
+            *changed_auto_active_status = Some(attr.span);
+        }
+        cfg_info.auto_cfg_active = new_value;
+        false
+    }
+
+    let mut new_show_attrs = FxHashMap::default();
+    let mut new_hide_attrs = FxHashMap::default();
+
+    let mut doc_cfg = attrs
+        .clone()
+        .filter(|attr| attr.has_name(sym::doc))
+        .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
+        .filter(|attr| attr.has_name(sym::cfg))
+        .peekable();
+    // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
+    if doc_cfg.peek().is_some() {
+        let sess = tcx.sess;
+        // We overwrite existing `cfg`.
+        if !cfg_info.parent_is_doc_cfg {
+            cfg_info.current_cfg = Cfg::True;
+            cfg_info.parent_is_doc_cfg = true;
+        }
+        for attr in doc_cfg {
+            if let Some(cfg_mi) =
+                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
+            {
+                match Cfg::parse(cfg_mi) {
+                    Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
+                    Err(e) => {
+                        sess.dcx().span_err(e.span, e.msg);
+                    }
+                }
+            }
+        }
+    } else {
+        cfg_info.parent_is_doc_cfg = false;
+    }
+
+    let mut changed_auto_active_status = None;
+
+    // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
+    for attr in attrs {
+        if let Some(ident) = attr.ident()
+            && ident.name == sym::doc
+            && let Some(attrs) = attr.meta_item_list()
+        {
+            for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
+                let MetaItemInner::MetaItem(attr) = attr else {
+                    continue;
+                };
+                match &attr.kind {
+                    MetaItemKind::Word => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                    }
+                    MetaItemKind::NameValue(lit) => {
+                        if let LitKind::Bool(value) = lit.kind {
+                            if check_changed_auto_active_status(
+                                &mut changed_auto_active_status,
+                                attr,
+                                cfg_info,
+                                tcx,
+                                value,
+                            ) {
+                                return None;
+                            }
+                        }
+                    }
+                    MetaItemKind::List(sub_attrs) => {
+                        if check_changed_auto_active_status(
+                            &mut changed_auto_active_status,
+                            attr,
+                            cfg_info,
+                            tcx,
+                            true,
+                        ) {
+                            return None;
+                        }
+                        for sub_attr in sub_attrs.iter() {
+                            if let Some(ident) = sub_attr.ident()
+                                && (ident.name == sym::show || ident.name == sym::hide)
+                            {
+                                handle_auto_cfg_hide_show(
+                                    tcx,
+                                    cfg_info,
+                                    &sub_attr,
+                                    ident.name == sym::show,
+                                    &mut new_show_attrs,
+                                    &mut new_hide_attrs,
+                                );
+                            }
+                        }
+                    }
+                }
+            }
+        } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
+            // Treat `#[target_feature(enable = "feat")]` attributes as if they were
+            // `#[doc(cfg(target_feature = "feat"))]` attributes as well.
+            for (feature, _) in features {
+                cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
+            }
+            continue;
+        } else if !cfg_info.parent_is_doc_cfg
+            && let Some(ident) = attr.ident()
+            && matches!(ident.name, sym::cfg | sym::cfg_trace)
+            && let Some(attr) = single(attr.meta_item_list()?)
+            && let Ok(new_cfg) = Cfg::parse(&attr)
+        {
+            cfg_info.current_cfg &= new_cfg;
+        }
+    }
+
+    // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
+    // to be done here.
+    if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
+        None
+    } else if cfg_info.parent_is_doc_cfg {
+        if cfg_info.current_cfg == Cfg::True {
+            None
+        } else {
+            Some(Arc::new(cfg_info.current_cfg.clone()))
+        }
+    } else {
+        // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
+        // hidden ones afterward.
+        match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
+            None | Some(Cfg::True) => None,
+            Some(cfg) => Some(Arc::new(cfg)),
+        }
+    }
+}
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c6339dd4755..4fd8d245089 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -58,6 +58,7 @@ use tracing::{debug, instrument};
 use utils::*;
 use {rustc_ast as ast, rustc_hir as hir};
 
+pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs};
 pub(crate) use self::types::*;
 pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
 use crate::core::DocContext;
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6e3dfa0ac22..f3662a67bbe 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -6,8 +6,7 @@ use std::{fmt, iter};
 use arrayvec::ArrayVec;
 use itertools::Either;
 use rustc_abi::{ExternAbi, VariantIdx};
-use rustc_ast::ast::{LitKind, MetaItemInner, MetaItemKind};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -922,267 +921,6 @@ pub(crate) fn hir_attr_lists<'a, I: IntoIterator<Item = &'a hir::Attribute>>(
         .flatten()
 }
 
-/// This type keeps track of (doc) cfg information as we go down the item tree.
-#[derive(Clone, Debug)]
-pub(crate) struct CfgInfo {
-    /// List of currently active `doc(auto_cfg(hide(...)))` cfgs, minus currently active
-    /// `doc(auto_cfg(show(...)))` cfgs.
-    hidden_cfg: FxHashSet<Cfg>,
-    /// Current computed `cfg`. Each time we enter a new item, this field is updated as well while
-    /// taking into account the `hidden_cfg` information.
-    current_cfg: Cfg,
-    /// Whether the `doc(auto_cfg())` feature is enabled or not at this point.
-    auto_cfg_active: bool,
-    /// If the parent item used `doc(cfg(...))`, then we don't want to overwrite `current_cfg`,
-    /// instead we will concatenate with it. However, if it's not the case, we need to overwrite
-    /// `current_cfg`.
-    parent_is_doc_cfg: bool,
-}
-
-impl Default for CfgInfo {
-    fn default() -> Self {
-        Self {
-            hidden_cfg: FxHashSet::from_iter([
-                Cfg::Cfg(sym::test, None),
-                Cfg::Cfg(sym::doc, None),
-                Cfg::Cfg(sym::doctest, None),
-            ]),
-            current_cfg: Cfg::True,
-            auto_cfg_active: true,
-            parent_is_doc_cfg: false,
-        }
-    }
-}
-
-fn show_hide_show_conflict_error(
-    tcx: TyCtxt<'_>,
-    item_span: rustc_span::Span,
-    previous: rustc_span::Span,
-) {
-    let mut diag = tcx.sess.dcx().struct_span_err(
-        item_span,
-        format!(
-            "same `cfg` was in `auto_cfg(hide(...))` and `auto_cfg(show(...))` on the same item"
-        ),
-    );
-    diag.span_note(previous, "first change was here");
-    diag.emit();
-}
-
-/// This functions updates the `hidden_cfg` field of the provided `cfg_info` argument.
-///
-/// It also checks if a same `cfg` is present in both `auto_cfg(hide(...))` and
-/// `auto_cfg(show(...))` on the same item and emits an error if it's the case.
-///
-/// Because we go through a list of `cfg`s, we keep track of the `cfg`s we saw in `new_show_attrs`
-/// and in `new_hide_attrs` arguments.
-fn handle_auto_cfg_hide_show(
-    tcx: TyCtxt<'_>,
-    cfg_info: &mut CfgInfo,
-    sub_attr: &MetaItemInner,
-    is_show: bool,
-    new_show_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
-    new_hide_attrs: &mut FxHashMap<(Symbol, Option<Symbol>), rustc_span::Span>,
-) {
-    if let MetaItemInner::MetaItem(item) = sub_attr
-        && let MetaItemKind::List(items) = &item.kind
-    {
-        for item in items {
-            // FIXME: Report in case `Cfg::parse` reports an error?
-            if let Ok(Cfg::Cfg(key, value)) = Cfg::parse(item) {
-                if is_show {
-                    if let Some(span) = new_hide_attrs.get(&(key, value)) {
-                        show_hide_show_conflict_error(tcx, item.span(), *span);
-                    } else {
-                        new_show_attrs.insert((key, value), item.span());
-                    }
-                    cfg_info.hidden_cfg.remove(&Cfg::Cfg(key, value));
-                } else {
-                    if let Some(span) = new_show_attrs.get(&(key, value)) {
-                        show_hide_show_conflict_error(tcx, item.span(), *span);
-                    } else {
-                        new_hide_attrs.insert((key, value), item.span());
-                    }
-                    cfg_info.hidden_cfg.insert(Cfg::Cfg(key, value));
-                }
-            }
-        }
-    }
-}
-
-pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> + Clone>(
-    attrs: I,
-    tcx: TyCtxt<'_>,
-    cfg_info: &mut CfgInfo,
-) -> Option<Arc<Cfg>> {
-    fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
-        let mut iter = it.into_iter();
-        let item = iter.next()?;
-        if iter.next().is_some() {
-            return None;
-        }
-        Some(item)
-    }
-
-    fn check_changed_auto_active_status(
-        changed_auto_active_status: &mut Option<rustc_span::Span>,
-        attr: &ast::MetaItem,
-        cfg_info: &mut CfgInfo,
-        tcx: TyCtxt<'_>,
-        new_value: bool,
-    ) -> bool {
-        if let Some(first_change) = changed_auto_active_status {
-            if cfg_info.auto_cfg_active != new_value {
-                tcx.sess
-                    .dcx()
-                    .struct_span_err(
-                        vec![*first_change, attr.span],
-                        "`auto_cfg` was disabled and enabled more than once on the same item",
-                    )
-                    .emit();
-                return true;
-            }
-        } else {
-            *changed_auto_active_status = Some(attr.span);
-        }
-        cfg_info.auto_cfg_active = new_value;
-        false
-    }
-
-    let mut new_show_attrs = FxHashMap::default();
-    let mut new_hide_attrs = FxHashMap::default();
-
-    let mut doc_cfg = attrs
-        .clone()
-        .filter(|attr| attr.has_name(sym::doc))
-        .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
-        .filter(|attr| attr.has_name(sym::cfg))
-        .peekable();
-    // If the item uses `doc(cfg(...))`, then we ignore the other `cfg(...)` attributes.
-    if doc_cfg.peek().is_some() {
-        let sess = tcx.sess;
-        // We overwrite existing `cfg`.
-        if !cfg_info.parent_is_doc_cfg {
-            cfg_info.current_cfg = Cfg::True;
-            cfg_info.parent_is_doc_cfg = true;
-        }
-        for attr in doc_cfg {
-            if let Some(cfg_mi) =
-                attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess))
-            {
-                match Cfg::parse(cfg_mi) {
-                    Ok(new_cfg) => cfg_info.current_cfg &= new_cfg,
-                    Err(e) => {
-                        sess.dcx().span_err(e.span, e.msg);
-                    }
-                }
-            }
-        }
-    } else {
-        cfg_info.parent_is_doc_cfg = false;
-    }
-
-    let mut changed_auto_active_status = None;
-
-    // We get all `doc(auto_cfg)`, `cfg` and `target_feature` attributes.
-    for attr in attrs {
-        if let Some(ident) = attr.ident()
-            && ident.name == sym::doc
-            && let Some(attrs) = attr.meta_item_list()
-        {
-            for attr in attrs.iter().filter(|attr| attr.has_name(sym::auto_cfg)) {
-                let MetaItemInner::MetaItem(attr) = attr else {
-                    continue;
-                };
-                match &attr.kind {
-                    MetaItemKind::Word => {
-                        if check_changed_auto_active_status(
-                            &mut changed_auto_active_status,
-                            attr,
-                            cfg_info,
-                            tcx,
-                            true,
-                        ) {
-                            return None;
-                        }
-                    }
-                    MetaItemKind::NameValue(lit) => {
-                        if let LitKind::Bool(value) = lit.kind {
-                            if check_changed_auto_active_status(
-                                &mut changed_auto_active_status,
-                                attr,
-                                cfg_info,
-                                tcx,
-                                value,
-                            ) {
-                                return None;
-                            }
-                        }
-                    }
-                    MetaItemKind::List(sub_attrs) => {
-                        if check_changed_auto_active_status(
-                            &mut changed_auto_active_status,
-                            attr,
-                            cfg_info,
-                            tcx,
-                            true,
-                        ) {
-                            return None;
-                        }
-                        for sub_attr in sub_attrs.iter() {
-                            if let Some(ident) = sub_attr.ident()
-                                && (ident.name == sym::show || ident.name == sym::hide)
-                            {
-                                handle_auto_cfg_hide_show(
-                                    tcx,
-                                    cfg_info,
-                                    &sub_attr,
-                                    ident.name == sym::show,
-                                    &mut new_show_attrs,
-                                    &mut new_hide_attrs,
-                                );
-                            }
-                        }
-                    }
-                }
-            }
-        } else if let hir::Attribute::Parsed(AttributeKind::TargetFeature { features, .. }) = attr {
-            // Treat `#[target_feature(enable = "feat")]` attributes as if they were
-            // `#[doc(cfg(target_feature = "feat"))]` attributes as well.
-            for (feature, _) in features {
-                cfg_info.current_cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
-            }
-            continue;
-        } else if !cfg_info.parent_is_doc_cfg
-            && let Some(ident) = attr.ident()
-            && matches!(ident.name, sym::cfg | sym::cfg_trace)
-            && let Some(attr) = single(attr.meta_item_list()?)
-            && let Ok(new_cfg) = Cfg::parse(&attr)
-        {
-            cfg_info.current_cfg &= new_cfg;
-        }
-    }
-
-    // If `doc(auto_cfg)` feature is disabled and `doc(cfg())` wasn't used, there is nothing
-    // to be done here.
-    if !cfg_info.auto_cfg_active && !cfg_info.parent_is_doc_cfg {
-        None
-    } else if cfg_info.parent_is_doc_cfg {
-        if cfg_info.current_cfg == Cfg::True {
-            None
-        } else {
-            Some(Arc::new(cfg_info.current_cfg.clone()))
-        }
-    } else {
-        // If `doc(auto_cfg)` feature is enabled, we want to collect all `cfg` items, we remove the
-        // hidden ones afterward.
-        match cfg_info.current_cfg.strip_hidden(&cfg_info.hidden_cfg) {
-            None | Some(Cfg::True) => None,
-            Some(cfg) => Some(Arc::new(cfg)),
-        }
-    }
-}
-
 pub(crate) trait NestedAttributesExt {
     /// Returns `true` if the attribute list contains a specific `word`
     fn has_word(self, word: Symbol) -> bool
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index a19d254ea95..5e5592269af 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -146,6 +146,14 @@ impl Cache {
         Cache { document_private, document_hidden, ..Cache::default() }
     }
 
+    fn parent_stack_last_impl_and_trait_id(&self) -> (Option<DefId>, Option<DefId>) {
+        if let Some(ParentStackItem::Impl { item_id, trait_, .. }) = self.parent_stack.last() {
+            (item_id.as_def_id(), trait_.as_ref().map(|tr| tr.def_id()))
+        } else {
+            (None, None)
+        }
+    }
+
     /// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
     /// in `krate` due to the data being moved into the `Cache`.
     pub(crate) fn populate(cx: &mut DocContext<'_>, mut krate: clean::Crate) -> clean::Crate {
@@ -572,11 +580,7 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
         clean::ItemKind::ImportItem(import) => import.source.did.unwrap_or(item_def_id),
         _ => item_def_id,
     };
-    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
-        item_id.as_def_id()
-    } else {
-        None
-    };
+    let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id();
     let search_type = get_function_type_for_search(
         item,
         tcx,
@@ -594,12 +598,15 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
         desc,
         parent: parent_did,
         parent_idx: None,
+        trait_parent,
+        trait_parent_idx: None,
         exact_module_path: None,
         impl_id,
         search_type,
         aliases,
         deprecation,
     };
+
     cache.search_index.push(index_item);
 }
 
@@ -608,19 +615,21 @@ fn add_item_to_search_index(tcx: TyCtxt<'_>, cache: &mut Cache, item: &clean::It
 /// See [`Cache::orphan_impl_items`].
 fn handle_orphan_impl_child(cache: &mut Cache, item: &clean::Item, parent_did: DefId) {
     let impl_generics = clean_impl_generics(cache.parent_stack.last());
-    let impl_id = if let Some(ParentStackItem::Impl { item_id, .. }) = cache.parent_stack.last() {
-        item_id.as_def_id()
-    } else {
-        None
+    let (impl_id, trait_parent) = cache.parent_stack_last_impl_and_trait_id();
+    let orphan_item = OrphanImplItem {
+        parent: parent_did,
+        trait_parent,
+        item: item.clone(),
+        impl_generics,
+        impl_id,
     };
-    let orphan_item =
-        OrphanImplItem { parent: parent_did, item: item.clone(), impl_generics, impl_id };
     cache.orphan_impl_items.push(orphan_item);
 }
 
 pub(crate) struct OrphanImplItem {
     pub(crate) parent: DefId,
     pub(crate) impl_id: Option<DefId>,
+    pub(crate) trait_parent: Option<DefId>,
     pub(crate) item: clean::Item,
     pub(crate) impl_generics: Option<(clean::Type, clean::Generics)>,
 }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index fad15573cde..1dcb4dcc3ff 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -12,15 +12,16 @@ use std::iter;
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
+use rustc_span::BytePos;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, DUMMY_SP, Span};
 
 use super::format;
 use crate::clean::PrimitiveType;
 use crate::display::Joined as _;
 use crate::html::escape::EscapeBodyText;
 use crate::html::macro_expansion::ExpandedCode;
+use crate::html::render::span_map::{DUMMY_SP, Span};
 use crate::html::render::{Context, LinkFromSrc};
 
 /// This type is needed in case we want to render links on items to allow to go to their definition.
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 2603e887bea..4d1bee9b3a1 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -1,6 +1,7 @@
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::create_default_session_globals_then;
+use test::Bencher;
 
 use super::{DecorationInfo, write_code};
 
@@ -81,3 +82,16 @@ let a = 4;";
         expect_file!["fixtures/decorations.html"].assert_eq(&html);
     });
 }
+
+#[bench]
+fn bench_html_highlighting(b: &mut Bencher) {
+    let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs");
+
+    create_default_session_globals_then(|| {
+        b.iter(|| {
+            let mut out = String::new();
+            write_code(&mut out, src, None, None, None);
+            out
+        });
+    });
+}
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 5f92ab2fada..4c06d0da470 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -30,6 +30,7 @@ use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::macro_expansion::ExpandedCode;
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
+use crate::html::render::span_map::Span;
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
 use crate::html::{layout, sources, static_files};
@@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> {
 
     /// Correspondence map used to link types used in the source code pages to allow to click on
     /// links to jump to the type's definition.
-    pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
+    pub(crate) span_correspondence_map: FxHashMap<Span, LinkFromSrc>,
     pub(crate) expanded_codes: FxHashMap<BytePos, Vec<ExpandedCode>>,
     /// The [`Cache`] used during rendering.
     pub(crate) cache: Cache,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 97dcaf57cdf..84d684e0c95 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -36,7 +36,7 @@ mod ordered_json;
 mod print_item;
 pub(crate) mod sidebar;
 mod sorted_template;
-mod span_map;
+pub(crate) mod span_map;
 mod type_layout;
 mod write_shared;
 
@@ -134,6 +134,8 @@ pub(crate) struct IndexItem {
     pub(crate) desc: String,
     pub(crate) parent: Option<DefId>,
     pub(crate) parent_idx: Option<usize>,
+    pub(crate) trait_parent: Option<DefId>,
+    pub(crate) trait_parent_idx: Option<usize>,
     pub(crate) exact_module_path: Option<Vec<Symbol>>,
     pub(crate) impl_id: Option<DefId>,
     pub(crate) search_type: Option<IndexItemFunctionType>,
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 7b21c68d2e9..253d9029468 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -610,6 +610,7 @@ impl SerializedSearchIndex {
                          module_path,
                          exact_module_path,
                          parent,
+                         trait_parent,
                          deprecated,
                          associated_item_disambiguator,
                      }| EntryData {
@@ -619,6 +620,7 @@ impl SerializedSearchIndex {
                         exact_module_path: exact_module_path
                             .and_then(|path_id| map.get(&path_id).copied()),
                         parent: parent.and_then(|path_id| map.get(&path_id).copied()),
+                        trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()),
                         deprecated: *deprecated,
                         associated_item_disambiguator: associated_item_disambiguator.clone(),
                     },
@@ -900,6 +902,7 @@ struct EntryData {
     module_path: Option<usize>,
     exact_module_path: Option<usize>,
     parent: Option<usize>,
+    trait_parent: Option<usize>,
     deprecated: bool,
     associated_item_disambiguator: Option<String>,
 }
@@ -915,6 +918,7 @@ impl Serialize for EntryData {
         seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?;
         seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?;
         seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
+        seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?;
         seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
         if let Some(disambig) = &self.associated_item_disambiguator {
             seq.serialize_element(&disambig)?;
@@ -946,6 +950,9 @@ impl<'de> Deserialize<'de> for EntryData {
                     .ok_or_else(|| A::Error::missing_field("exact_module_path"))?;
                 let parent: SerializedOptional32 =
                     v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?;
+                let trait_parent: SerializedOptional32 =
+                    v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?;
+
                 let deprecated: u32 = v.next_element()?.unwrap_or(0);
                 let associated_item_disambiguator: Option<String> = v.next_element()?;
                 Ok(EntryData {
@@ -955,6 +962,7 @@ impl<'de> Deserialize<'de> for EntryData {
                     exact_module_path: Option::<i32>::from(exact_module_path)
                         .map(|path| path as usize),
                     parent: Option::<i32>::from(parent).map(|path| path as usize),
+                    trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize),
                     deprecated: deprecated != 0,
                     associated_item_disambiguator,
                 })
@@ -1305,7 +1313,8 @@ pub(crate) fn build_index(
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
-    for &OrphanImplItem { impl_id, parent, ref item, ref impl_generics } in &cache.orphan_impl_items
+    for &OrphanImplItem { impl_id, parent, trait_parent, ref item, ref impl_generics } in
+        &cache.orphan_impl_items
     {
         if let Some((fqp, _)) = cache.paths.get(&parent) {
             let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
@@ -1317,6 +1326,8 @@ pub(crate) fn build_index(
                 desc,
                 parent: Some(parent),
                 parent_idx: None,
+                trait_parent,
+                trait_parent_idx: None,
                 exact_module_path: None,
                 impl_id,
                 search_type: get_function_type_for_search(
@@ -1421,6 +1432,7 @@ pub(crate) fn build_index(
                         module_path: None,
                         exact_module_path: None,
                         parent: None,
+                        trait_parent: None,
                         deprecated: false,
                         associated_item_disambiguator: None,
                     }),
@@ -1434,39 +1446,46 @@ pub(crate) fn build_index(
         }
     };
 
-    // First, populate associated item parents
+    // First, populate associated item parents and trait parents
     let crate_items: Vec<&mut IndexItem> = search_index
         .iter_mut()
         .map(|item| {
-            item.parent_idx = item.parent.and_then(|defid| {
-                cache.paths.get(&defid).map(|&(ref fqp, ty)| {
-                    let pathid = serialized_index.names.len();
-                    match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
-                        Entry::Occupied(entry) => *entry.get(),
-                        Entry::Vacant(entry) => {
-                            entry.insert(pathid);
-                            let (name, path) = fqp.split_last().unwrap();
-                            serialized_index.push_path(
-                                name.as_str().to_string(),
-                                PathData {
-                                    ty,
-                                    module_path: path.to_vec(),
-                                    exact_module_path: if let Some(exact_path) =
-                                        cache.exact_paths.get(&defid)
-                                        && let Some((name2, exact_path)) = exact_path.split_last()
-                                        && name == name2
-                                    {
-                                        Some(exact_path.to_vec())
-                                    } else {
-                                        None
+            let mut defid_to_rowid = |defid, check_external: bool| {
+                cache
+                    .paths
+                    .get(&defid)
+                    .or_else(|| check_external.then(|| cache.external_paths.get(&defid)).flatten())
+                    .map(|&(ref fqp, ty)| {
+                        let pathid = serialized_index.names.len();
+                        match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
+                            Entry::Occupied(entry) => *entry.get(),
+                            Entry::Vacant(entry) => {
+                                entry.insert(pathid);
+                                let (name, path) = fqp.split_last().unwrap();
+                                serialized_index.push_path(
+                                    name.as_str().to_string(),
+                                    PathData {
+                                        ty,
+                                        module_path: path.to_vec(),
+                                        exact_module_path: if let Some(exact_path) =
+                                            cache.exact_paths.get(&defid)
+                                            && let Some((name2, exact_path)) =
+                                                exact_path.split_last()
+                                            && name == name2
+                                        {
+                                            Some(exact_path.to_vec())
+                                        } else {
+                                            None
+                                        },
                                     },
-                                },
-                            );
-                            usize::try_from(pathid).unwrap()
+                                );
+                                usize::try_from(pathid).unwrap()
+                            }
                         }
-                    }
-                })
-            });
+                    })
+            };
+            item.parent_idx = item.parent.and_then(|p| defid_to_rowid(p, false));
+            item.trait_parent_idx = item.trait_parent.and_then(|p| defid_to_rowid(p, true));
 
             if let Some(defid) = item.defid
                 && item.parent_idx.is_none()
@@ -1549,6 +1568,7 @@ pub(crate) fn build_index(
             EntryData {
                 ty: item.ty,
                 parent: item.parent_idx,
+                trait_parent: item.trait_parent_idx,
                 module_path,
                 exact_module_path,
                 deprecated: item.deprecation.is_some(),
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index ef7ce33298d..bc9417b1bb1 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -8,11 +8,48 @@ use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, QPath};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::{BytePos, ExpnKind, Span};
+use rustc_span::{BytePos, ExpnKind};
 
 use crate::clean::{self, PrimitiveType, rustc_span};
 use crate::html::sources;
 
+/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span.
+///
+/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we
+/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this
+/// one, which is much cheaper to construct.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub(crate) struct Span {
+    lo: BytePos,
+    hi: BytePos,
+}
+
+impl From<rustc_span::Span> for Span {
+    fn from(value: rustc_span::Span) -> Self {
+        Self { lo: value.lo(), hi: value.hi() }
+    }
+}
+
+impl Span {
+    pub(crate) fn lo(self) -> BytePos {
+        self.lo
+    }
+
+    pub(crate) fn hi(self) -> BytePos {
+        self.hi
+    }
+
+    pub(crate) fn with_lo(self, lo: BytePos) -> Self {
+        Self { lo, hi: self.hi() }
+    }
+
+    pub(crate) fn with_hi(self, hi: BytePos) -> Self {
+        Self { lo: self.lo(), hi }
+    }
+}
+
+pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) };
+
 /// This enum allows us to store two different kinds of information:
 ///
 /// In case the `span` definition comes from the same crate, we can simply get the `span` and use
@@ -96,7 +133,7 @@ impl SpanMapVisitor<'_> {
                         })
                         .unwrap_or(path.span)
                 };
-                self.matches.insert(span, link);
+                self.matches.insert(span.into(), link);
             }
             Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
                 let path_span = if only_use_last_segment
@@ -106,11 +143,12 @@ impl SpanMapVisitor<'_> {
                 } else {
                     path.span
                 };
-                self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span)));
+                self.matches.insert(path_span.into(), LinkFromSrc::Local(clean::Span::new(span)));
             }
             Res::PrimTy(p) => {
                 // FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
-                self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
+                self.matches
+                    .insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p)));
             }
             Res::Err => {}
             _ => {}
@@ -127,7 +165,7 @@ impl SpanMapVisitor<'_> {
             if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
                 return;
             }
-            self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
+            self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id()));
         }
     }
 
@@ -138,7 +176,7 @@ impl SpanMapVisitor<'_> {
     /// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
     /// Finally, we get the information about the macro itself (`span` if "local", `DefId`
     /// otherwise) and store it inside the span map.
-    fn handle_macro(&mut self, span: Span) -> bool {
+    fn handle_macro(&mut self, span: rustc_span::Span) -> bool {
         if !span.from_expansion() {
             return false;
         }
@@ -176,7 +214,7 @@ impl SpanMapVisitor<'_> {
         // The "call_site" includes the whole macro with its "arguments". We only want
         // the macro name.
         let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
-        self.matches.insert(new_span, link_from_src);
+        self.matches.insert(new_span.into(), link_from_src);
         true
     }
 
@@ -233,7 +271,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         intravisit::walk_path(self, path);
     }
 
-    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
+    fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: rustc_span::Span) {
         match *qpath {
             QPath::TypeRelative(qself, path) => {
                 if matches!(path.res, Res::Err) {
@@ -249,7 +287,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
                         self.handle_path(&path, false);
                     }
                 } else {
-                    self.infer_id(path.hir_id, Some(id), path.ident.span);
+                    self.infer_id(path.hir_id, Some(id), path.ident.span.into());
                 }
 
                 rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself));
@@ -267,7 +305,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         }
     }
 
-    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
+    fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) {
         // To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
         // file, we want to link to it. Otherwise no need to create a link.
         if !span.overlaps(m.spans.inner_span) {
@@ -275,8 +313,10 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             // name only and not all the "mod foo;".
             if let Node::Item(item) = self.tcx.hir_node(id) {
                 let (ident, _) = item.expect_mod();
-                self.matches
-                    .insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
+                self.matches.insert(
+                    ident.span.into(),
+                    LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
+                );
             }
         } else {
             // If it's a "mod foo {}", we want to look to its documentation page.
@@ -288,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
         match expr.kind {
             ExprKind::MethodCall(segment, ..) => {
-                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span)
+                self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into())
             }
-            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span),
+            ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()),
             _ => {
                 if self.handle_macro(expr.span) {
                     // We don't want to go deeper into the macro.
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 9c5518a780e..c79f63fbc20 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -348,7 +348,12 @@ pub(crate) fn print_src(
         highlight::write_code(
             fmt,
             s,
-            Some(highlight::HrefContext { context, file_span, root_path, current_href }),
+            Some(highlight::HrefContext {
+                context,
+                file_span: file_span.into(),
+                root_path,
+                current_href,
+            }),
             Some(decoration_info),
             Some(line_info),
         );
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 951eb2291b8..e206d6633e6 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -241,6 +241,7 @@ declare namespace rustdoc {
         modulePath: number?,
         exactModulePath: number?,
         parent: number?,
+        traitParent: number?,
         deprecated: boolean,
         associatedItemDisambiguator: string?,
     }
@@ -291,9 +292,12 @@ declare namespace rustdoc {
         path: PathData?,
         functionData: FunctionData?,
         deprecated: boolean,
-        parent: { path: PathData, name: string}?,
+        parent: RowParent,
+        traitParent: RowParent,
     }
 
+    type RowParent = { path: PathData, name: string } | null;
+
     type ItemType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
         11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
         21 | 22 | 23 | 24 | 25 | 26;
@@ -316,7 +320,23 @@ declare namespace rustdoc {
     interface ResultObject {
         desc: Promise<string|null>,
         displayPath: string,
+        /**
+         * path to where the item was defined (not inlined),
+         * then `|`, then the `ItemType` of the item.
+         *
+         * This is often a private path, so it should not be displayed,
+         * but this allows us to use it to reliably deduplicate reexported and inlined items
+         */
         fullPath: string,
+        /**
+         * The `fullPath` of the corresponding item within a trait.
+         * For example, for `File::read`, this would be `std::io::Read::read|12`
+         *
+         * This is used to hide items from trait impls when the trait itself is in the search results.
+         *
+         * `null` if the item is not from a trait impl block.
+         */
+        traitPath: string | null,
         href: string,
         id: number,
         dist: number,
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 482134933a6..9a6d4c710ff 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1077,6 +1077,34 @@ function isPathSeparator(c) {
 }
 
 /**
+ * Given an array and an ascending list of indices,
+ * efficiently removes each index in the array.
+ *
+ * @template T
+ * @param {Array<T>} a
+ * @param {Array<number>} idxList
+ */
+function removeIdxListAsc(a, idxList) {
+    if (idxList.length === 0) {
+        return;
+    }
+    let removed = 0;
+    let i = idxList[0];
+    let nextToRemove = idxList[0];
+    while (i < a.length - idxList.length) {
+        while (i === nextToRemove && removed < idxList.length) {
+            removed++;
+            i++;
+            nextToRemove = idxList[removed];
+        }
+        a[i] = a[i + removed];
+        i++;
+    }
+    // truncate array
+    a.length -= idxList.length;
+}
+
+/**
  * @template T
  */
 class VlqHexDecoder {
@@ -1598,6 +1626,7 @@ class DocSearch {
          * module_path,
          * exact_module_path,
          * parent,
+         * trait_parent,
          * deprecated,
          * associated_item_disambiguator
          * @type {rustdoc.ArrayWithOptionals<[
@@ -1607,6 +1636,7 @@ class DocSearch {
          *     number,
          *     number,
          *     number,
+         *     number,
          * ], [string]>}
          */
         const raw = JSON.parse(encoded);
@@ -1616,8 +1646,9 @@ class DocSearch {
             modulePath: raw[2] === 0 ? null : raw[2] - 1,
             exactModulePath: raw[3] === 0 ? null : raw[3] - 1,
             parent: raw[4] === 0 ? null : raw[4] - 1,
-            deprecated: raw[5] === 1 ? true : false,
-            associatedItemDisambiguator: raw.length === 6 ? null : raw[6],
+            traitParent: raw[5] === 0 ? null : raw[5] - 1,
+            deprecated: raw[6] === 1 ? true : false,
+            associatedItemDisambiguator: raw.length === 7 ? null : raw[7],
         };
     }
 
@@ -1853,14 +1884,25 @@ class DocSearch {
         if (!entry && !path) {
             return null;
         }
+        /** @type {function("parent" | "traitParent"): Promise<rustdoc.RowParent>} */
+        const buildParentLike = async field => {
+            const [name, path] = entry !== null && entry[field] !== null ?
+                await Promise.all([this.getName(entry[field]), this.getPathData(entry[field])]) :
+                [null, null];
+            if (name !== null && path !== null) {
+                return { name, path };
+            }
+            return null;
+        };
+
         const [
             moduleName,
             modulePathData,
             exactModuleName,
             exactModulePathData,
-            parentName,
-            parentPath,
-            crate,
+            parent,
+            traitParent,
+            crateOrNull,
         ] = await Promise.all([
             entry && entry.modulePath !== null ? this.getName(entry.modulePath) : null,
             entry && entry.modulePath !== null ? this.getPathData(entry.modulePath) : null,
@@ -1870,14 +1912,11 @@ class DocSearch {
             entry && entry.exactModulePath !== null ?
                 this.getPathData(entry.exactModulePath) :
                 null,
-            entry && entry.parent !== null ?
-                this.getName(entry.parent) :
-                null,
-            entry && entry.parent !== null ?
-                this.getPathData(entry.parent) :
-                null,
-            entry ? nonnull(await this.getName(entry.krate)) : "",
+            buildParentLike("parent"),
+            buildParentLike("traitParent"),
+            entry ? this.getName(entry.krate) : "",
         ]);
+        const crate = crateOrNull === null ? "" : crateOrNull;
         const name = name_ === null ? "" : name_;
         const normalizedName = (name.indexOf("_") === -1 ?
             name :
@@ -1886,6 +1925,7 @@ class DocSearch {
             (modulePathData.modulePath === "" ?
                 moduleName :
                 `${modulePathData.modulePath}::${moduleName}`);
+
         return {
             id,
             crate,
@@ -1901,9 +1941,8 @@ class DocSearch {
             path,
             functionData,
             deprecated: entry ? entry.deprecated : false,
-            parent: parentName !== null && parentPath !== null ?
-                { name: parentName, path: parentPath } :
-                null,
+            parent,
+            traitParent,
         };
     }
 
@@ -2101,11 +2140,12 @@ class DocSearch {
 
         /**
          * @param {rustdoc.Row} item
-         * @returns {[string, string, string]}
+         * @returns {[string, string, string, string|null]}
          */
         const buildHrefAndPath = item => {
             let displayPath;
             let href;
+            let traitPath = null;
             const type = itemTypes[item.ty];
             const name = item.name;
             let path = item.modulePath;
@@ -2163,7 +2203,11 @@ class DocSearch {
                 href = this.rootPath + item.modulePath.replace(/::/g, "/") +
                     "/" + type + "." + name + ".html";
             }
-            return [displayPath, href, `${exactPath}::${name}`];
+            if (item.traitParent) {
+                const tparent = item.traitParent;
+                traitPath = `${tparent.path.exactModulePath}::${tparent.name}::${name}`;
+            }
+            return [displayPath, href, `${exactPath}::${name}`, traitPath];
         };
 
         /**
@@ -2598,8 +2642,14 @@ class DocSearch {
          * @returns {rustdoc.ResultObject[]}
          */
         const transformResults = (results, typeInfo, duplicates) => {
+            /** @type {rustdoc.ResultObject[]} */
             const out = [];
 
+            // if we match a trait-associated item, we want to go back and
+            // remove all the items that are their equivalent but in an impl block.
+            /** @type {Map<string, number[]>} */
+            const traitImplIdxMap = new Map();
+
             for (const result of results) {
                 const item = result.item;
                 if (item.id !== -1) {
@@ -2630,17 +2680,35 @@ class DocSearch {
                         item,
                         displayPath: pathSplitter(res[0]),
                         fullPath: "",
+                        traitPath: null,
                         href: "",
                         displayTypeSignature: null,
                     }, result);
 
+                    // unlike other items, methods have a different ty when they are
+                    // in an impl block vs a trait.  want to normalize this away.
+                    let ty = obj.item.ty;
+                    if (ty === TY_TYMETHOD) {
+                        ty = TY_METHOD;
+                    }
                     // To be sure than it some items aren't considered as duplicate.
-                    obj.fullPath = res[2] + "|" + obj.item.ty;
+                    obj.fullPath = res[2] + "|" + ty;
+                    if (res[3]) {
+                        // "tymethod" is never used on impl blocks
+                        // (this is the reason we need to normalize tymethod away).
+                        obj.traitPath = res[3] + "|" + obj.item.ty;
+                    }
 
                     if (duplicates.has(obj.fullPath)) {
                         continue;
                     }
 
+                    // If we're showing something like `Iterator::next`,
+                    // we don't want to also show a bunch of `<SomeType as Iterator>::next`
+                    if (obj.traitPath && duplicates.has(obj.traitPath)) {
+                        continue;
+                    }
+
                     // Exports are specifically not shown if the items they point at
                     // are already in the results.
                     if (obj.item.ty === TY_IMPORT && duplicates.has(res[2])) {
@@ -2661,14 +2729,29 @@ class DocSearch {
                         );
                     }
 
+                    // FIXME: if the trait item matches but is cut off due to MAX_RESULTS,
+                    // this deduplication will not happen.
                     obj.href = res[1];
+                    if (obj.traitPath) {
+                        let list = traitImplIdxMap.get(obj.traitPath);
+                        if (list === undefined) {
+                            list = [];
+                        }
+                        list.push(out.length);
+                        traitImplIdxMap.set(obj.traitPath, list);
+                    } else {
+                        const toRemoveList = traitImplIdxMap.get(obj.fullPath);
+                        if (toRemoveList) {
+                            removeIdxListAsc(out, toRemoveList);
+                        }
+                        traitImplIdxMap.delete(obj.fullPath);
+                    }
                     out.push(obj);
                     if (out.length >= MAX_RESULTS) {
                         break;
                     }
                 }
             }
-
             return out;
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 1b1e77bbea8..6e9142b22e0 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -14,7 +14,7 @@ use rustc_hir::{BindingMode, Body, FnDecl, Impl, ItemKind, MutTy, Mutability, No
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, PointerCoercion};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, RegionKind, TyCtxt};
+use rustc_middle::ty::{self, BoundVarIndexKind, RegionKind, TyCtxt};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, sym};
@@ -151,7 +151,7 @@ impl PassByRefOrValue {
             match *ty.skip_binder().kind() {
                 ty::Ref(lt, ty, Mutability::Not) => {
                     match lt.kind() {
-                        RegionKind::ReBound(index, region)
+                        RegionKind::ReBound(BoundVarIndexKind::Bound(index), region)
                             if index.as_u32() == 0 && output_regions.contains(&region) =>
                         {
                             continue;
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 2bda6d50373..cc98fac45c7 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -141,7 +141,8 @@ fn check_rvalue<'tcx>(
             | CastKind::FloatToFloat
             | CastKind::FnPtrToPtr
             | CastKind::PtrToPtr
-            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _),
+            | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _)
+            | CastKind::Subtype,
             operand,
             _,
         ) => check_operand(cx, operand, span, body, msrv),
@@ -312,7 +313,6 @@ fn check_place<'tcx>(
             | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
-            | ProjectionElem::Subtype(_)
             | ProjectionElem::Index(_)
             | ProjectionElem::UnwrapUnsafeBinder(_) => {},
         }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index e4bc3b76829..c03469c2b88 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -21,7 +21,7 @@ use rustc_middle::traits::EvaluationResult;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
-    self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+    self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, BoundVarIndexKind, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
     GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
     TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
 };
@@ -826,7 +826,7 @@ pub fn for_each_top_level_late_bound_region<B>(
     impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<TyCtxt<'tcx>> for V<F> {
         type Result = ControlFlow<B>;
         fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result {
-            if let RegionKind::ReBound(idx, bound) = r.kind()
+            if let RegionKind::ReBound(BoundVarIndexKind::Bound(idx), bound) = r.kind()
                 && idx.as_u32() == self.index
             {
                 (self.f)(bound)
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 6d959948918..65db816ad1a 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -7,6 +7,7 @@ use build_helper::git::GitConfig;
 use camino::{Utf8Path, Utf8PathBuf};
 use semver::Version;
 
+use crate::edition::Edition;
 use crate::executor::ColorConfig;
 use crate::fatal;
 use crate::util::{Utf8PathBufExt, add_dylib_path, string_enum};
@@ -612,10 +613,7 @@ pub struct Config {
     pub git_hash: bool,
 
     /// The default Rust edition.
-    ///
-    /// FIXME: perform stronger validation for this. There are editions that *definitely* exists,
-    /// but there might also be "future" edition.
-    pub edition: Option<String>,
+    pub edition: Option<Edition>,
 
     // Configuration for various run-make tests frobbing things like C compilers or querying about
     // various LLVM component information.
diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs
index e84a2278766..a79978d036c 100644
--- a/src/tools/compiletest/src/directives.rs
+++ b/src/tools/compiletest/src/directives.rs
@@ -16,10 +16,11 @@ use crate::directives::directive_names::{
     KNOWN_DIRECTIVE_NAMES, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES,
 };
 use crate::directives::needs::CachedNeedsConditions;
+use crate::edition::{Edition, parse_edition};
 use crate::errors::ErrorKind;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
-use crate::help;
 use crate::util::static_regex;
+use crate::{fatal, help};
 
 pub(crate) mod auxiliary;
 mod cfg;
@@ -63,9 +64,10 @@ impl EarlyProps {
             &mut poisoned,
             testfile,
             rdr,
-            &mut |DirectiveLine { line_number, raw_directive: ln, .. }| {
-                parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux);
-                config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions);
+            // (dummy comment to force args into vertical layout)
+            &mut |ref ln: DirectiveLine<'_>| {
+                parse_and_update_aux(config, ln, testfile, &mut props.aux);
+                config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
             },
         );
 
@@ -367,8 +369,8 @@ impl TestProps {
                 &mut poisoned,
                 testfile,
                 file,
-                &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
-                    if !directive.applies_to_test_revision(test_revision) {
+                &mut |ref ln: DirectiveLine<'_>| {
+                    if !ln.applies_to_test_revision(test_revision) {
                         return;
                     }
 
@@ -378,7 +380,6 @@ impl TestProps {
                         ln,
                         ERROR_PATTERN,
                         testfile,
-                        line_number,
                         &mut self.error_patterns,
                         |r| r,
                     );
@@ -386,7 +387,6 @@ impl TestProps {
                         ln,
                         REGEX_ERROR_PATTERN,
                         testfile,
-                        line_number,
                         &mut self.regex_error_patterns,
                         |r| r,
                     );
@@ -395,7 +395,6 @@ impl TestProps {
                         ln,
                         DOC_FLAGS,
                         testfile,
-                        line_number,
                         &mut self.doc_flags,
                         |r| r,
                     );
@@ -414,50 +413,50 @@ impl TestProps {
                     }
 
                     if let Some(flags) =
-                        config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number)
+                        config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile)
                     {
                         let flags = split_flags(&flags);
-                        for flag in &flags {
+                        for (i, flag) in flags.iter().enumerate() {
                             if flag == "--edition" || flag.starts_with("--edition=") {
                                 panic!("you must use `//@ edition` to configure the edition");
                             }
+                            if (flag == "-C"
+                                && flags.get(i + 1).is_some_and(|v| v.starts_with("incremental=")))
+                                || flag.starts_with("-Cincremental=")
+                            {
+                                panic!(
+                                    "you must use `//@ incremental` to enable incremental compilation"
+                                );
+                            }
                         }
                         self.compile_flags.extend(flags);
                     }
                     if config
-                        .parse_name_value_directive(
-                            ln,
-                            INCORRECT_COMPILER_FLAGS,
-                            testfile,
-                            line_number,
-                        )
+                        .parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS, testfile)
                         .is_some()
                     {
                         panic!("`compiler-flags` directive should be spelled `compile-flags`");
                     }
 
-                    if let Some(edition) = config.parse_edition(ln, testfile, line_number) {
+                    if let Some(range) = parse_edition_range(config, ln, testfile) {
                         // The edition is added at the start, since flags from //@compile-flags must
                         // be passed to rustc last.
-                        self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
+                        self.compile_flags.insert(
+                            0,
+                            format!("--edition={}", range.edition_to_test(config.edition)),
+                        );
                         has_edition = true;
                     }
 
-                    config.parse_and_update_revisions(
-                        testfile,
-                        line_number,
-                        ln,
-                        &mut self.revisions,
-                    );
+                    config.parse_and_update_revisions(testfile, ln, &mut self.revisions);
 
-                    if let Some(flags) =
-                        config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number)
+                    if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS, testfile)
                     {
                         self.run_flags.extend(split_flags(&flags));
                     }
 
                     if self.pp_exact.is_none() {
-                        self.pp_exact = config.parse_pp_exact(ln, testfile, line_number);
+                        self.pp_exact = config.parse_pp_exact(ln, testfile);
                     }
 
                     config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
@@ -479,9 +478,7 @@ impl TestProps {
                     );
                     config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
 
-                    if let Some(m) =
-                        config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number)
-                    {
+                    if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE, testfile) {
                         self.pretty_mode = m;
                     }
 
@@ -492,13 +489,12 @@ impl TestProps {
                     );
 
                     // Call a helper method to deal with aux-related directives.
-                    parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux);
+                    parse_and_update_aux(config, ln, testfile, &mut self.aux);
 
                     config.push_name_value_directive(
                         ln,
                         EXEC_ENV,
                         testfile,
-                        line_number,
                         &mut self.exec_env,
                         Config::parse_env,
                     );
@@ -506,7 +502,6 @@ impl TestProps {
                         ln,
                         UNSET_EXEC_ENV,
                         testfile,
-                        line_number,
                         &mut self.unset_exec_env,
                         |r| r.trim().to_owned(),
                     );
@@ -514,7 +509,6 @@ impl TestProps {
                         ln,
                         RUSTC_ENV,
                         testfile,
-                        line_number,
                         &mut self.rustc_env,
                         Config::parse_env,
                     );
@@ -522,7 +516,6 @@ impl TestProps {
                         ln,
                         UNSET_RUSTC_ENV,
                         testfile,
-                        line_number,
                         &mut self.unset_rustc_env,
                         |r| r.trim().to_owned(),
                     );
@@ -530,7 +523,6 @@ impl TestProps {
                         ln,
                         FORBID_OUTPUT,
                         testfile,
-                        line_number,
                         &mut self.forbid_output,
                         |r| r,
                     );
@@ -566,7 +558,7 @@ impl TestProps {
                     }
 
                     if let Some(code) = config
-                        .parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number)
+                        .parse_name_value_directive(ln, FAILURE_STATUS, testfile)
                         .and_then(|code| code.trim().parse::<i32>().ok())
                     {
                         self.failure_status = Some(code);
@@ -588,7 +580,6 @@ impl TestProps {
                         ln,
                         ASSEMBLY_OUTPUT,
                         testfile,
-                        line_number,
                         &mut self.assembly_output,
                         |r| r.trim().to_string(),
                     );
@@ -602,7 +593,7 @@ impl TestProps {
                     // Unlike the other `name_value_directive`s this needs to be handled manually,
                     // because it sets a `bool` flag.
                     if let Some(known_bug) =
-                        config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number)
+                        config.parse_name_value_directive(ln, KNOWN_BUG, testfile)
                     {
                         let known_bug = known_bug.trim();
                         if known_bug == "unknown"
@@ -632,24 +623,20 @@ impl TestProps {
                         ln,
                         TEST_MIR_PASS,
                         testfile,
-                        line_number,
                         &mut self.mir_unit_test,
                         |s| s.trim().to_string(),
                     );
                     config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
 
                     if let Some(flags) =
-                        config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number)
+                        config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile)
                     {
                         self.llvm_cov_flags.extend(split_flags(&flags));
                     }
 
-                    if let Some(flags) = config.parse_name_value_directive(
-                        ln,
-                        FILECHECK_FLAGS,
-                        testfile,
-                        line_number,
-                    ) {
+                    if let Some(flags) =
+                        config.parse_name_value_directive(ln, FILECHECK_FLAGS, testfile)
+                    {
                         self.filecheck_flags.extend(split_flags(&flags));
                     }
 
@@ -661,7 +648,6 @@ impl TestProps {
                         ln,
                         directives::CORE_STUBS_COMPILE_FLAGS,
                         testfile,
-                        line_number,
                     ) {
                         let flags = split_flags(&flags);
                         for flag in &flags {
@@ -672,12 +658,9 @@ impl TestProps {
                         self.core_stubs_compile_flags.extend(flags);
                     }
 
-                    if let Some(err_kind) = config.parse_name_value_directive(
-                        ln,
-                        DONT_REQUIRE_ANNOTATIONS,
-                        testfile,
-                        line_number,
-                    ) {
+                    if let Some(err_kind) =
+                        config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS, testfile)
+                    {
                         self.dont_require_annotations
                             .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
                     }
@@ -734,7 +717,7 @@ impl TestProps {
         }
     }
 
-    fn update_fail_mode(&mut self, ln: &str, config: &Config) {
+    fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
         let check_ui = |mode: &str| {
             // Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
             if config.mode != TestMode::Ui && config.mode != TestMode::Crashes {
@@ -769,7 +752,12 @@ impl TestProps {
         }
     }
 
-    fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
+    fn update_pass_mode(
+        &mut self,
+        ln: &DirectiveLine<'_>,
+        revision: Option<&str>,
+        config: &Config,
+    ) {
         let check_no_run = |s| match (config.mode, s) {
             (TestMode::Ui, _) => (),
             (TestMode::Crashes, _) => (),
@@ -814,7 +802,7 @@ impl TestProps {
         self.pass_mode
     }
 
-    pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) {
+    fn update_add_core_stubs(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
         let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS);
         if add_core_stubs {
             if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) {
@@ -905,10 +893,12 @@ pub(crate) struct CheckDirectiveResult<'ln> {
     trailing_directive: Option<&'ln str>,
 }
 
-pub(crate) fn check_directive<'a>(
-    directive_ln: &'a str,
+fn check_directive<'a>(
+    directive_ln: &DirectiveLine<'a>,
     mode: TestMode,
 ) -> CheckDirectiveResult<'a> {
+    let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln;
+
     let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
 
     let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
@@ -980,7 +970,7 @@ fn iter_directives(
         // Perform unknown directive check on Rust files.
         if testfile.extension() == Some("rs") {
             let CheckDirectiveResult { is_known_directive, trailing_directive } =
-                check_directive(directive_line.raw_directive, mode);
+                check_directive(&directive_line, mode);
 
             if !is_known_directive {
                 *poisoned = true;
@@ -1014,8 +1004,7 @@ impl Config {
     fn parse_and_update_revisions(
         &self,
         testfile: &Utf8Path,
-        line_number: usize,
-        line: &str,
+        line: &DirectiveLine<'_>,
         existing: &mut Vec<String>,
     ) {
         const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
@@ -1028,8 +1017,7 @@ impl Config {
         const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
             ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
 
-        if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
-        {
+        if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile) {
             if self.mode == TestMode::RunMake {
                 panic!("`run-make` mode tests do not support revisions: {}", testfile);
             }
@@ -1074,13 +1062,8 @@ impl Config {
         (name.to_owned(), value.to_owned())
     }
 
-    fn parse_pp_exact(
-        &self,
-        line: &str,
-        testfile: &Utf8Path,
-        line_number: usize,
-    ) -> Option<Utf8PathBuf> {
-        if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) {
+    fn parse_pp_exact(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
+        if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile) {
             Some(Utf8PathBuf::from(&s))
         } else if self.parse_name_directive(line, "pp-exact") {
             testfile.file_name().map(Utf8PathBuf::from)
@@ -1089,7 +1072,9 @@ impl Config {
         }
     }
 
-    fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRule> {
+    fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option<NormalizeRule> {
+        let &DirectiveLine { raw_directive, .. } = line;
+
         // FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
         // instead of doing it here.
         let (directive_name, raw_value) = raw_directive.split_once(':')?;
@@ -1110,24 +1095,23 @@ impl Config {
         Some(NormalizeRule { kind, regex, replacement })
     }
 
-    fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
+    fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool {
+        let &DirectiveLine { raw_directive: line, .. } = line;
+
         // Ensure the directive is a whole word. Do not match "ignore-x86" when
         // the line says "ignore-x86_64".
         line.starts_with(directive)
             && matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':'))
     }
 
-    fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool {
-        line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
-    }
-
-    pub fn parse_name_value_directive(
+    fn parse_name_value_directive(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
     ) -> Option<String> {
+        let &DirectiveLine { line_number, raw_directive: line, .. } = line;
+
         let colon = directive.len();
         if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
             let value = line[(colon + 1)..].to_owned();
@@ -1144,52 +1128,33 @@ impl Config {
         }
     }
 
-    fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> {
-        self.parse_name_value_directive(line, "edition", testfile, line_number)
-    }
-
-    fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
-        match value {
-            true => {
-                if self.parse_negative_name_directive(line, directive) {
-                    *value = false;
-                }
-            }
-            false => {
-                if self.parse_name_directive(line, directive) {
-                    *value = true;
-                }
-            }
-        }
+    fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) {
+        // If the flag is already true, don't bother looking at the directive.
+        *value = *value || self.parse_name_directive(line, directive);
     }
 
     fn set_name_value_directive<T>(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
         value: &mut Option<T>,
         parse: impl FnOnce(String) -> T,
     ) {
         if value.is_none() {
-            *value =
-                self.parse_name_value_directive(line, directive, testfile, line_number).map(parse);
+            *value = self.parse_name_value_directive(line, directive, testfile).map(parse);
         }
     }
 
     fn push_name_value_directive<T>(
         &self,
-        line: &str,
+        line: &DirectiveLine<'_>,
         directive: &str,
         testfile: &Utf8Path,
-        line_number: usize,
         values: &mut Vec<T>,
         parse: impl FnOnce(String) -> T,
     ) {
-        if let Some(value) =
-            self.parse_name_value_directive(line, directive, testfile, line_number).map(parse)
-        {
+        if let Some(value) = self.parse_name_value_directive(line, directive, testfile).map(parse) {
             values.push(value);
         }
     }
@@ -1482,8 +1447,8 @@ pub(crate) fn make_test_description<R: Read>(
         &mut local_poisoned,
         path,
         src,
-        &mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
-            if !directive.applies_to_test_revision(test_revision) {
+        &mut |ref ln @ DirectiveLine { line_number, .. }| {
+            if !ln.applies_to_test_revision(test_revision) {
                 return;
             }
 
@@ -1507,9 +1472,9 @@ pub(crate) fn make_test_description<R: Read>(
             decision!(cfg::handle_ignore(config, ln));
             decision!(cfg::handle_only(config, ln));
             decision!(needs::handle_needs(&cache.needs, config, ln));
-            decision!(ignore_llvm(config, path, ln, line_number));
-            decision!(ignore_backends(config, path, ln, line_number));
-            decision!(needs_backends(config, path, ln, line_number));
+            decision!(ignore_llvm(config, path, ln));
+            decision!(ignore_backends(config, path, ln));
+            decision!(needs_backends(config, path, ln));
             decision!(ignore_cdb(config, ln));
             decision!(ignore_gdb(config, ln));
             decision!(ignore_lldb(config, ln));
@@ -1549,7 +1514,9 @@ pub(crate) fn make_test_description<R: Read>(
     }
 }
 
-fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Cdb) {
         return IgnoreDecision::Continue;
     }
@@ -1572,7 +1539,9 @@ fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Gdb) {
         return IgnoreDecision::Continue;
     }
@@ -1620,7 +1589,9 @@ fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
+fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if config.debugger != Some(Debugger::Lldb) {
         return IgnoreDecision::Continue;
     }
@@ -1642,14 +1613,9 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
     IgnoreDecision::Continue
 }
 
-fn ignore_backends(
-    config: &Config,
-    path: &Utf8Path,
-    line: &str,
-    line_number: usize,
-) -> IgnoreDecision {
+fn ignore_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
     if let Some(backends_to_ignore) =
-        config.parse_name_value_directive(line, "ignore-backends", path, line_number)
+        config.parse_name_value_directive(line, "ignore-backends", path)
     {
         for backend in backends_to_ignore.split_whitespace().map(|backend| {
             match CodegenBackend::try_from(backend) {
@@ -1669,15 +1635,8 @@ fn ignore_backends(
     IgnoreDecision::Continue
 }
 
-fn needs_backends(
-    config: &Config,
-    path: &Utf8Path,
-    line: &str,
-    line_number: usize,
-) -> IgnoreDecision {
-    if let Some(needed_backends) =
-        config.parse_name_value_directive(line, "needs-backends", path, line_number)
-    {
+fn needs_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
+    if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends", path) {
         if !needed_backends
             .split_whitespace()
             .map(|backend| match CodegenBackend::try_from(backend) {
@@ -1699,9 +1658,9 @@ fn needs_backends(
     IgnoreDecision::Continue
 }
 
-fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
     if let Some(needed_components) =
-        config.parse_name_value_directive(line, "needs-llvm-components", path, line_number)
+        config.parse_name_value_directive(line, "needs-llvm-components", path)
     {
         let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
         if let Some(missing_component) = needed_components
@@ -1723,7 +1682,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
         // Note that these `min` versions will check for not just major versions.
 
         if let Some(version_string) =
-            config.parse_name_value_directive(line, "min-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "min-llvm-version", path)
         {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if actual version is smaller than the minimum required version.
@@ -1735,7 +1694,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number)
+            config.parse_name_value_directive(line, "max-llvm-major-version", path)
         {
             let max_version = extract_llvm_version(&version_string);
             // Ignore if actual major version is larger than the maximum required major version.
@@ -1749,7 +1708,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "min-system-llvm-version", path)
         {
             let min_version = extract_llvm_version(&version_string);
             // Ignore if using system LLVM and actual version
@@ -1762,7 +1721,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 };
             }
         } else if let Some(version_range) =
-            config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number)
+            config.parse_name_value_directive(line, "ignore-llvm-version", path)
         {
             // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
             let (v_min, v_max) =
@@ -1788,7 +1747,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
                 }
             }
         } else if let Some(version_string) =
-            config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number)
+            config.parse_name_value_directive(line, "exact-llvm-major-version", path)
         {
             // Syntax is "exact-llvm-major-version: <version>"
             let version = extract_llvm_version(&version_string);
@@ -1810,3 +1769,86 @@ enum IgnoreDecision {
     Continue,
     Error { message: String },
 }
+
+fn parse_edition_range(
+    config: &Config,
+    line: &DirectiveLine<'_>,
+    testfile: &Utf8Path,
+) -> Option<EditionRange> {
+    let raw = config.parse_name_value_directive(line, "edition", testfile)?;
+    let line_number = line.line_number;
+
+    // Edition range is half-open: `[lower_bound, upper_bound)`
+    if let Some((lower_bound, upper_bound)) = raw.split_once("..") {
+        Some(match (maybe_parse_edition(lower_bound), maybe_parse_edition(upper_bound)) {
+            (Some(lower_bound), Some(upper_bound)) if upper_bound <= lower_bound => {
+                fatal!(
+                    "{testfile}:{line_number}: the left side of `//@ edition` cannot be greater than or equal to the right side"
+                );
+            }
+            (Some(lower_bound), Some(upper_bound)) => {
+                EditionRange::Range { lower_bound, upper_bound }
+            }
+            (Some(lower_bound), None) => EditionRange::RangeFrom(lower_bound),
+            (None, Some(_)) => {
+                fatal!(
+                    "{testfile}:{line_number}: `..edition` is not a supported range in `//@ edition`"
+                );
+            }
+            (None, None) => {
+                fatal!("{testfile}:{line_number}: `..` is not a supported range in `//@ edition`");
+            }
+        })
+    } else {
+        match maybe_parse_edition(&raw) {
+            Some(edition) => Some(EditionRange::Exact(edition)),
+            None => {
+                fatal!("{testfile}:{line_number}: empty value for `//@ edition`");
+            }
+        }
+    }
+}
+
+fn maybe_parse_edition(mut input: &str) -> Option<Edition> {
+    input = input.trim();
+    if input.is_empty() {
+        return None;
+    }
+    Some(parse_edition(input))
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+enum EditionRange {
+    Exact(Edition),
+    RangeFrom(Edition),
+    /// Half-open range: `[lower_bound, upper_bound)`
+    Range {
+        lower_bound: Edition,
+        upper_bound: Edition,
+    },
+}
+
+impl EditionRange {
+    fn edition_to_test(&self, requested: impl Into<Option<Edition>>) -> Edition {
+        let min_edition = Edition::Year(2015);
+        let requested = requested.into().unwrap_or(min_edition);
+
+        match *self {
+            EditionRange::Exact(exact) => exact,
+            EditionRange::RangeFrom(lower_bound) => {
+                if requested >= lower_bound {
+                    requested
+                } else {
+                    lower_bound
+                }
+            }
+            EditionRange::Range { lower_bound, upper_bound } => {
+                if requested >= lower_bound && requested < upper_bound {
+                    requested
+                } else {
+                    lower_bound
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs
index 7c1ed2e7006..0675a6feac3 100644
--- a/src/tools/compiletest/src/directives/auxiliary.rs
+++ b/src/tools/compiletest/src/directives/auxiliary.rs
@@ -7,6 +7,7 @@ use camino::Utf8Path;
 
 use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
 use crate::common::Config;
+use crate::directives::DirectiveLine;
 
 /// Properties parsed from `aux-*` test directives.
 #[derive(Clone, Debug, Default)]
@@ -45,40 +46,28 @@ impl AuxProps {
 /// and update [`AuxProps`] accordingly.
 pub(super) fn parse_and_update_aux(
     config: &Config,
-    ln: &str,
+    directive_line: &DirectiveLine<'_>,
     testfile: &Utf8Path,
-    line_number: usize,
     aux: &mut AuxProps,
 ) {
+    let &DirectiveLine { raw_directive: ln, .. } = directive_line;
+
     if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
         return;
     }
 
-    config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| {
+    let ln = directive_line;
+
+    config.push_name_value_directive(ln, AUX_BUILD, testfile, &mut aux.builds, |r| {
         r.trim().to_string()
     });
-    config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| {
+    config
+        .push_name_value_directive(ln, AUX_BIN, testfile, &mut aux.bins, |r| r.trim().to_string());
+    config.push_name_value_directive(ln, AUX_CRATE, testfile, &mut aux.crates, parse_aux_crate);
+    config.push_name_value_directive(ln, PROC_MACRO, testfile, &mut aux.proc_macros, |r| {
         r.trim().to_string()
     });
-    config.push_name_value_directive(
-        ln,
-        AUX_CRATE,
-        testfile,
-        line_number,
-        &mut aux.crates,
-        parse_aux_crate,
-    );
-    config.push_name_value_directive(
-        ln,
-        PROC_MACRO,
-        testfile,
-        line_number,
-        &mut aux.proc_macros,
-        |r| r.trim().to_string(),
-    );
-    if let Some(r) =
-        config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number)
-    {
+    if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile) {
         aux.codegen_backend = Some(r.trim().to_owned());
     }
 }
diff --git a/src/tools/compiletest/src/directives/cfg.rs b/src/tools/compiletest/src/directives/cfg.rs
index 802a1d63d1f..62a4b88a33a 100644
--- a/src/tools/compiletest/src/directives/cfg.rs
+++ b/src/tools/compiletest/src/directives/cfg.rs
@@ -1,12 +1,14 @@
 use std::collections::HashSet;
 
 use crate::common::{CompareMode, Config, Debugger};
-use crate::directives::IgnoreDecision;
+use crate::directives::{DirectiveLine, IgnoreDecision};
 
 const EXTRA_ARCHS: &[&str] = &["spirv"];
 
-pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
+pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
     let parsed = parse_cfg_name_directive(config, line, "ignore");
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     match parsed.outcome {
         MatchOutcome::NoMatch => IgnoreDecision::Continue,
         MatchOutcome::Match => IgnoreDecision::Ignore {
@@ -21,8 +23,10 @@ pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
     }
 }
 
-pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
+pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
     let parsed = parse_cfg_name_directive(config, line, "only");
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     match parsed.outcome {
         MatchOutcome::Match => IgnoreDecision::Continue,
         MatchOutcome::NoMatch => IgnoreDecision::Ignore {
@@ -43,9 +47,11 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
 /// or `only-windows`.
 fn parse_cfg_name_directive<'a>(
     config: &Config,
-    line: &'a str,
+    line: &'a DirectiveLine<'a>,
     prefix: &str,
 ) -> ParsedNameDirective<'a> {
+    let &DirectiveLine { raw_directive: line, .. } = line;
+
     if !line.as_bytes().starts_with(prefix.as_bytes()) {
         return ParsedNameDirective::not_a_directive();
     }
diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs
index 3b7a9478717..c8a729d8aab 100644
--- a/src/tools/compiletest/src/directives/needs.rs
+++ b/src/tools/compiletest/src/directives/needs.rs
@@ -1,10 +1,10 @@
 use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
-use crate::directives::{IgnoreDecision, llvm_has_libzstd};
+use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd};
 
 pub(super) fn handle_needs(
     cache: &CachedNeedsConditions,
     config: &Config,
-    ln: &str,
+    ln: &DirectiveLine<'_>,
 ) -> IgnoreDecision {
     // Note that we intentionally still put the needs- prefix here to make the file show up when
     // grepping for a directive name, even though we could technically strip that.
@@ -181,6 +181,8 @@ pub(super) fn handle_needs(
         },
     ];
 
+    let &DirectiveLine { raw_directive: ln, .. } = ln;
+
     let (name, rest) = match ln.split_once([':', ' ']) {
         Some((name, rest)) => (name, Some(rest)),
         None => (ln, None),
diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs
index 16cf76be9a5..93621192d4b 100644
--- a/src/tools/compiletest/src/directives/tests.rs
+++ b/src/tools/compiletest/src/directives/tests.rs
@@ -4,10 +4,11 @@ use camino::Utf8Path;
 use semver::Version;
 
 use super::{
-    DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
-    parse_normalize_rule,
+    DirectivesCache, EarlyProps, Edition, EditionRange, extract_llvm_version,
+    extract_version_range, iter_directives, parse_normalize_rule,
 };
 use crate::common::{Config, Debugger, TestMode};
+use crate::directives::parse_edition;
 use crate::executor::{CollectedTestDesc, ShouldPanic};
 
 fn make_test_description<R: Read>(
@@ -73,6 +74,7 @@ fn test_parse_normalize_rule() {
 struct ConfigBuilder {
     mode: Option<String>,
     channel: Option<String>,
+    edition: Option<Edition>,
     host: Option<String>,
     target: Option<String>,
     stage: Option<u32>,
@@ -96,6 +98,11 @@ impl ConfigBuilder {
         self
     }
 
+    fn edition(&mut self, e: Edition) -> &mut Self {
+        self.edition = Some(e);
+        self
+    }
+
     fn host(&mut self, s: &str) -> &mut Self {
         self.host = Some(s.to_owned());
         self
@@ -183,6 +190,10 @@ impl ConfigBuilder {
         ];
         let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
 
+        if let Some(edition) = &self.edition {
+            args.push(format!("--edition={edition}"));
+        }
+
         if let Some(ref llvm_version) = self.llvm_version {
             args.push("--llvm-version".to_owned());
             args.push(llvm_version.clone());
@@ -941,3 +952,130 @@ fn test_needs_target_std() {
     let config = cfg().target("x86_64-unknown-linux-gnu").build();
     assert!(!check_ignore(&config, "//@ needs-target-std"));
 }
+
+fn parse_edition_range(line: &str) -> Option<EditionRange> {
+    let config = cfg().build();
+    let line = super::DirectiveLine { line_number: 0, revision: None, raw_directive: line };
+
+    super::parse_edition_range(&config, &line, "tmp.rs".into())
+}
+
+#[test]
+fn test_parse_edition_range() {
+    assert_eq!(None, parse_edition_range("hello-world"));
+    assert_eq!(None, parse_edition_range("edition"));
+
+    assert_eq!(Some(EditionRange::Exact(2018.into())), parse_edition_range("edition: 2018"));
+    assert_eq!(Some(EditionRange::Exact(2021.into())), parse_edition_range("edition:2021"));
+    assert_eq!(Some(EditionRange::Exact(2024.into())), parse_edition_range("edition: 2024 "));
+    assert_eq!(Some(EditionRange::Exact(Edition::Future)), parse_edition_range("edition: future"));
+
+    assert_eq!(Some(EditionRange::RangeFrom(2018.into())), parse_edition_range("edition: 2018.."));
+    assert_eq!(Some(EditionRange::RangeFrom(2021.into())), parse_edition_range("edition:2021 .."));
+    assert_eq!(
+        Some(EditionRange::RangeFrom(2024.into())),
+        parse_edition_range("edition: 2024 .. ")
+    );
+    assert_eq!(
+        Some(EditionRange::RangeFrom(Edition::Future)),
+        parse_edition_range("edition: future.. ")
+    );
+
+    assert_eq!(
+        Some(EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() }),
+        parse_edition_range("edition: 2018..2024")
+    );
+    assert_eq!(
+        Some(EditionRange::Range { lower_bound: 2015.into(), upper_bound: 2021.into() }),
+        parse_edition_range("edition:2015 .. 2021 ")
+    );
+    assert_eq!(
+        Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: 2027.into() }),
+        parse_edition_range("edition: 2021 .. 2027 ")
+    );
+    assert_eq!(
+        Some(EditionRange::Range { lower_bound: 2021.into(), upper_bound: Edition::Future }),
+        parse_edition_range("edition: 2021..future")
+    );
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_empty() {
+    parse_edition_range("edition:");
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_invalid_edition() {
+    parse_edition_range("edition: hello");
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_double_dots() {
+    parse_edition_range("edition: ..");
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_inverted_range() {
+    parse_edition_range("edition: 2021..2015");
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_inverted_range_future() {
+    parse_edition_range("edition: future..2015");
+}
+
+#[test]
+#[should_panic]
+fn test_parse_edition_range_empty_range() {
+    parse_edition_range("edition: 2021..2021");
+}
+
+#[track_caller]
+fn assert_edition_to_test(
+    expected: impl Into<Edition>,
+    range: EditionRange,
+    default: Option<Edition>,
+) {
+    let mut cfg = cfg();
+    if let Some(default) = default {
+        cfg.edition(default);
+    }
+    assert_eq!(expected.into(), range.edition_to_test(cfg.build().edition));
+}
+
+#[test]
+fn test_edition_range_edition_to_test() {
+    let e2015 = parse_edition("2015");
+    let e2018 = parse_edition("2018");
+    let e2021 = parse_edition("2021");
+    let e2024 = parse_edition("2024");
+    let efuture = parse_edition("future");
+
+    let exact = EditionRange::Exact(2021.into());
+    assert_edition_to_test(2021, exact, None);
+    assert_edition_to_test(2021, exact, Some(e2018));
+    assert_edition_to_test(2021, exact, Some(efuture));
+
+    assert_edition_to_test(Edition::Future, EditionRange::Exact(Edition::Future), None);
+
+    let greater_equal_than = EditionRange::RangeFrom(2021.into());
+    assert_edition_to_test(2021, greater_equal_than, None);
+    assert_edition_to_test(2021, greater_equal_than, Some(e2015));
+    assert_edition_to_test(2021, greater_equal_than, Some(e2018));
+    assert_edition_to_test(2021, greater_equal_than, Some(e2021));
+    assert_edition_to_test(2024, greater_equal_than, Some(e2024));
+    assert_edition_to_test(Edition::Future, greater_equal_than, Some(efuture));
+
+    let range = EditionRange::Range { lower_bound: 2018.into(), upper_bound: 2024.into() };
+    assert_edition_to_test(2018, range, None);
+    assert_edition_to_test(2018, range, Some(e2015));
+    assert_edition_to_test(2018, range, Some(e2018));
+    assert_edition_to_test(2021, range, Some(e2021));
+    assert_edition_to_test(2018, range, Some(e2024));
+    assert_edition_to_test(2018, range, Some(efuture));
+}
diff --git a/src/tools/compiletest/src/edition.rs b/src/tools/compiletest/src/edition.rs
new file mode 100644
index 00000000000..36550cf5b2b
--- /dev/null
+++ b/src/tools/compiletest/src/edition.rs
@@ -0,0 +1,35 @@
+use crate::fatal;
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum Edition {
+    // Note that the ordering here is load-bearing, as we want the future edition to be greater than
+    // any year-based edition.
+    Year(u32),
+    Future,
+}
+
+impl std::fmt::Display for Edition {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Edition::Year(year) => write!(f, "{year}"),
+            Edition::Future => f.write_str("future"),
+        }
+    }
+}
+
+impl From<u32> for Edition {
+    fn from(value: u32) -> Self {
+        Edition::Year(value)
+    }
+}
+
+pub fn parse_edition(mut input: &str) -> Edition {
+    input = input.trim();
+    if input == "future" {
+        Edition::Future
+    } else {
+        Edition::Year(input.parse().unwrap_or_else(|_| {
+            fatal!("`{input}` doesn't look like an edition");
+        }))
+    }
+}
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 15e31dadf97..2d759279f34 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -7,6 +7,7 @@ pub mod common;
 mod debuggers;
 pub mod diagnostics;
 pub mod directives;
+pub mod edition;
 pub mod errors;
 mod executor;
 mod json;
@@ -39,6 +40,7 @@ use crate::common::{
     expected_output_path, output_base_dir, output_relative_path,
 };
 use crate::directives::DirectivesCache;
+use crate::edition::parse_edition;
 use crate::executor::{CollectedTest, ColorConfig};
 
 /// Creates the `Config` instance for this invocation of compiletest.
@@ -449,7 +451,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         has_enzyme,
         channel: matches.opt_str("channel").unwrap(),
         git_hash: matches.opt_present("git-hash"),
-        edition: matches.opt_str("edition"),
+        edition: matches.opt_str("edition").as_deref().map(parse_edition),
 
         cc: matches.opt_str("cc").unwrap(),
         cxx: matches.opt_str("cxx").unwrap(),
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index ba824124e87..3d439e98eb7 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader};
 
 use camino::{Utf8Path, Utf8PathBuf};
 
-use crate::common::Config;
 use crate::runtest::ProcRes;
 
 /// Representation of information to invoke a debugger and check its output
@@ -20,11 +19,7 @@ pub(super) struct DebuggerCommands {
 }
 
 impl DebuggerCommands {
-    pub fn parse_from(
-        file: &Utf8Path,
-        config: &Config,
-        debugger_prefix: &str,
-    ) -> Result<Self, String> {
+    pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result<Self, String> {
         let command_directive = format!("{debugger_prefix}-command");
         let check_directive = format!("{debugger_prefix}-check");
 
@@ -47,14 +42,10 @@ impl DebuggerCommands {
                 continue;
             };
 
-            if let Some(command) =
-                config.parse_name_value_directive(&line, &command_directive, file, line_no)
-            {
+            if let Some(command) = parse_name_value(&line, &command_directive) {
                 commands.push(command);
             }
-            if let Some(pattern) =
-                config.parse_name_value_directive(&line, &check_directive, file, line_no)
-            {
+            if let Some(pattern) = parse_name_value(&line, &check_directive) {
                 check_lines.push((line_no, pattern));
             }
         }
@@ -114,6 +105,18 @@ impl DebuggerCommands {
     }
 }
 
+/// Split off from the main `parse_name_value_directive`, so that improvements
+/// to directive handling aren't held back by debuginfo test commands.
+fn parse_name_value(line: &str, name: &str) -> Option<String> {
+    if let Some(after_name) = line.strip_prefix(name)
+        && let Some(value) = after_name.strip_prefix(':')
+    {
+        Some(value.to_owned())
+    } else {
+        None
+    }
+}
+
 /// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match.
 fn check_single_line(line: &str, check_line: &str) -> bool {
     // Allow check lines to leave parts unspecified (e.g., uninitialized
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 071c0863b7e..9175a38ffa5 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -59,7 +59,7 @@ impl TestCx<'_> {
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
@@ -130,7 +130,7 @@ impl TestCx<'_> {
     }
 
     fn run_debuginfo_gdb_test_no_opt(&self) {
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb")
             .unwrap_or_else(|e| self.fatal(&e));
         let mut cmds = dbg_cmds.commands.join("\n");
 
@@ -397,7 +397,7 @@ impl TestCx<'_> {
         }
 
         // Parse debugger commands etc from test files
-        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb")
+        let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb")
             .unwrap_or_else(|e| self.fatal(&e));
 
         // Write debugger script:
diff --git a/src/tools/miri/tests/pass/static_align.rs b/src/tools/miri/tests/pass/static_align.rs
index f292f028568..bc6a9bf8af7 100644
--- a/src/tools/miri/tests/pass/static_align.rs
+++ b/src/tools/miri/tests/pass/static_align.rs
@@ -1,4 +1,7 @@
 #![feature(static_align)]
+#![deny(non_upper_case_globals)]
+
+use std::cell::Cell;
 
 // When a static uses `align(N)`, its address should be a multiple of `N`.
 
@@ -8,7 +11,64 @@ static FOO: u64 = 0;
 #[rustc_align_static(512)]
 static BAR: u64 = 0;
 
+struct HasDrop(*const HasDrop);
+
+impl Drop for HasDrop {
+    fn drop(&mut self) {
+        assert_eq!(core::ptr::from_mut(self).cast_const(), self.0);
+    }
+}
+
+thread_local! {
+    #[rustc_align_static(4096)]
+    static LOCAL: u64 = 0;
+
+    #[allow(unused_mut, reason = "test attribute handling")]
+    #[cfg_attr(true, rustc_align_static(4096))]
+    static CONST_LOCAL: u64 = const { 0 };
+
+    #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))]
+    #[allow(unused_mut, reason = "test attribute handling")]
+    static HASDROP_LOCAL: Cell<HasDrop> = Cell::new(HasDrop(core::ptr::null()));
+
+    /// I love doc comments.
+    #[allow(unused_mut, reason = "test attribute handling")]
+    #[cfg_attr(all(),
+      cfg_attr(any(true),
+      cfg_attr(true, rustc_align_static(4096))))]
+    #[allow(unused_mut, reason = "test attribute handling")]
+    /// I love doc comments.
+    static HASDROP_CONST_LOCAL: Cell<HasDrop> = const { Cell::new(HasDrop(core::ptr::null())) };
+
+    #[cfg_attr(true,)]
+    #[cfg_attr(false,)]
+    #[cfg_attr(
+        true,
+        rustc_align_static(32),
+        cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")),
+        cfg_attr(false,)
+    )]
+    #[cfg_attr(false, rustc_align_static(0))]
+    static more_attr_testing: u64 = 0;
+}
+
+fn thread_local_ptr<T>(key: &'static std::thread::LocalKey<T>) -> *const T {
+    key.with(|local| core::ptr::from_ref::<T>(local))
+}
+
 fn main() {
     assert!(core::ptr::from_ref(&FOO).addr().is_multiple_of(256));
     assert!(core::ptr::from_ref(&BAR).addr().is_multiple_of(512));
+
+    assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32));
+
+    // Test that address (and therefore alignment) is maintained during drop
+    let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL);
+    core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast())));
+    let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL);
+    core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast())));
 }
diff --git a/src/tools/miri/tests/pass/thread_local-panic.rs b/src/tools/miri/tests/pass/thread_local-panic.rs
new file mode 100644
index 00000000000..549acd23987
--- /dev/null
+++ b/src/tools/miri/tests/pass/thread_local-panic.rs
@@ -0,0 +1,8 @@
+thread_local! {
+    static LOCAL: u64 = panic!();
+
+}
+
+fn main() {
+    let _ = std::panic::catch_unwind(|| LOCAL.with(|_| {}));
+}
diff --git a/src/tools/miri/tests/pass/thread_local-panic.stderr b/src/tools/miri/tests/pass/thread_local-panic.stderr
new file mode 100644
index 00000000000..e69340a8102
--- /dev/null
+++ b/src/tools/miri/tests/pass/thread_local-panic.stderr
@@ -0,0 +1,5 @@
+
+thread 'main' ($TID) panicked at tests/pass/thread_local-panic.rs:LL:CC:
+explicit panic
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 770652494f4..0eb57a605f8 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -56,8 +56,8 @@ jobs:
       # Install a pinned rustc commit to avoid surprises
       - name: Install Rust toolchain
         run: |
-          RUSTC_VERSION=`cat rust-version`
-          rustup-toolchain-install-master ${RUSTC_VERSION} -c rust-src -c rustfmt
+          RUSTC_VERSION=$(cat rust-version)
+          rustup-toolchain-install-master ${RUSTC_VERSION} -c cargo -c rust-src -c rustfmt
           rustup default ${RUSTC_VERSION}
 
       # Emulate a nightly toolchain, because the toolchain installed above does not have "nightly"
@@ -98,9 +98,9 @@ jobs:
         run: |
           rustup update --no-self-update stable
           rustup default stable
-          rustup component add --toolchain stable rust-src clippy
-          # We always use a nightly rustfmt, regardless of channel, because we need
-          # --file-lines.
+          rustup component add --toolchain stable rust-src clippy rustfmt
+          # We also install a nightly rustfmt, because we use `--file-lines` in
+          # a test.
           rustup toolchain install nightly --profile minimal --component rustfmt
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 17dea1ba4cd..086f38f06a5 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -546,6 +546,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
 name = "flate2"
 version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -775,6 +781,7 @@ dependencies = [
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "oorandom",
+ "petgraph",
  "project-model",
  "query-group-macro",
  "ra-ap-rustc_abi",
@@ -1327,9 +1334,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.5"
+version = "2.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
 
 [[package]]
 name = "memmap2"
@@ -1595,6 +1602,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "petgraph"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54acf3a685220b533e437e264e4d932cfbdc4cc7ec0cd232ed73c08d03b8a7ca"
+dependencies = [
+ "fixedbitset",
+ "hashbrown 0.15.4",
+ "indexmap",
+]
+
+[[package]]
 name = "pin-project-lite"
 version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 0401367f786..d3a4e375613 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -170,6 +170,7 @@ tracing-subscriber = { version = "0.3.20", default-features = false, features =
 triomphe = { version = "0.1.14", default-features = false, features = ["std"] }
 url = "2.5.4"
 xshell = "0.2.7"
+petgraph = { version = "0.8.2", default-features = false }
 
 # We need to freeze the version of the crate, as the raw-api feature is considered unstable
 dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 138d02e5a61..4013d19ad08 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -34,6 +34,7 @@ rustc_apfloat = "0.2.3"
 query-group.workspace = true
 salsa.workspace = true
 salsa-macros.workspace = true
+petgraph.workspace = true
 
 ra-ap-rustc_abi.workspace = true
 ra-ap-rustc_index.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index fd60ffcf24b..21a86d3e437 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -32,11 +32,11 @@ const AUTODEREF_RECURSION_LIMIT: usize = 20;
 /// - the yielded types don't contain inference variables (but may contain `TyKind::Error`).
 /// - a type won't be yielded more than once; in other words, the returned iterator will stop if it
 ///   detects a cycle in the deref chain.
-pub fn autoderef(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn autoderef<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     ty: crate::Canonical<crate::Ty>,
-) -> impl Iterator<Item = crate::Ty> {
+) -> impl Iterator<Item = crate::Ty> + use<> {
     let mut table = InferenceTable::new(db, env);
     let interner = table.interner;
     let ty = table.instantiate_canonical(ty);
@@ -298,7 +298,7 @@ fn structurally_normalize_ty<'db>(
 ) -> Option<(Ty<'db>, PredicateObligations<'db>)> {
     let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
     let Ok(normalized_ty) =
-        ocx.structurally_normalize_ty(&ObligationCause::misc(), table.param_env, ty)
+        ocx.structurally_normalize_ty(&ObligationCause::misc(), table.trait_env.env, ty)
     else {
         // We shouldn't have errors here in the old solver, except for
         // evaluate/fulfill mismatches, but that's not a reason for an ICE.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index 3755175cf51..5511587c71a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -3,17 +3,20 @@
 use chalk_ir::{
     AdtId, DebruijnIndex, Scalar,
     cast::{Cast, CastTo, Caster},
-    fold::TypeFoldable,
-    interner::HasInterner,
 };
 use hir_def::{GenericDefId, GenericParamId, TraitId, TypeAliasId, builtin_type::BuiltinType};
 use smallvec::SmallVec;
 
 use crate::{
-    Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
-    Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, consteval::unknown_const_as_generic,
-    db::HirDatabase, error_lifetime, generics::generics, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id,
+    BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution,
+    TraitRef, Ty, TyDefId, TyExt, TyKind,
+    consteval::unknown_const_as_generic,
+    db::HirDatabase,
+    error_lifetime,
+    generics::generics,
+    infer::unify::InferenceTable,
+    next_solver::{DbInterner, EarlyBinder, mapping::ChalkToNextSolver},
+    primitive, to_assoc_type_id, to_chalk_trait_id,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -345,19 +348,20 @@ impl TyBuilder<TypeAliasId> {
     }
 }
 
-impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
-    pub fn build(self) -> T {
+impl<'db, T: rustc_type_ir::TypeFoldable<DbInterner<'db>>> TyBuilder<EarlyBinder<'db, T>> {
+    pub fn build(self, interner: DbInterner<'db>) -> T {
         let (b, subst) = self.build_internal();
-        b.substitute(Interner, &subst)
+        let args: crate::next_solver::GenericArgs<'db> = subst.to_nextsolver(interner);
+        b.instantiate(interner, args)
     }
 }
 
-impl TyBuilder<Binders<Ty>> {
+impl<'db> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
     pub fn def_ty(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         def: TyDefId,
         parent_subst: Option<Substitution>,
-    ) -> TyBuilder<Binders<Ty>> {
+    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
         let poly_ty = db.ty(def);
         let id: GenericDefId = match def {
             TyDefId::BuiltinType(_) => {
@@ -370,7 +374,10 @@ impl TyBuilder<Binders<Ty>> {
         TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
     }
 
-    pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
+    pub fn impl_self_ty(
+        db: &'db dyn HirDatabase,
+        def: hir_def::ImplId,
+    ) -> TyBuilder<EarlyBinder<'db, crate::next_solver::Ty<'db>>> {
         TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 1faf9f66dc5..6956a0a1232 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -15,8 +15,13 @@ use crate::{
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
     ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, ToChalk, TraitRef, Ty, TyBuilder, TyKind, TypeFlags,
-    WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
+    WhereClause,
+    db::HirDatabase,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
+    generics::generics,
+    next_solver::{DbInterner, mapping::NextSolverToChalk},
+    to_chalk_trait_id,
+    utils::ClosureSubst,
 };
 
 pub trait TyExt {
@@ -372,7 +377,10 @@ impl TyExt for Ty {
         let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build();
         let env = db.trait_environment_for_body(owner);
         let goal = Canonical {
-            value: InEnvironment::new(&env.env, trait_ref.cast(Interner)),
+            value: InEnvironment::new(
+                &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+                trait_ref.cast(Interner),
+            ),
             binders: CanonicalVarKinds::empty(Interner),
         };
         !db.trait_solve(crate_id, None, goal).no_solution()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index 0f2cc17f563..b2daed425ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -229,7 +229,7 @@ pub(crate) fn const_eval_cycle_result(
     _: &dyn HirDatabase,
     _: GeneralConstId,
     _: Substitution,
-    _: Option<Arc<TraitEnvironment>>,
+    _: Option<Arc<TraitEnvironment<'_>>>,
 ) -> Result<Const, ConstEvalError> {
     Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
 }
@@ -252,7 +252,7 @@ pub(crate) fn const_eval_query(
     db: &dyn HirDatabase,
     def: GeneralConstId,
     subst: Substitution,
-    trait_env: Option<Arc<TraitEnvironment>>,
+    trait_env: Option<Arc<TraitEnvironment<'_>>>,
 ) -> Result<Const, ConstEvalError> {
     let body = match def {
         GeneralConstId::ConstId(c) => {
@@ -327,7 +327,7 @@ pub(crate) fn eval_to_const(
     debruijn: DebruijnIndex,
 ) -> Const {
     let db = ctx.db;
-    let infer = ctx.clone().resolve_all();
+    let infer = ctx.fixme_resolve_all_clone();
     fn has_closure(body: &Body, expr: ExprId) -> bool {
         if matches!(body[expr], Expr::Closure { .. }) {
             return true;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index 299b73a7d6c..1586846bbe5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -36,12 +36,12 @@ fn check_fail(
     error: impl FnOnce(ConstEvalError) -> bool,
 ) {
     let (db, file_id) = TestDB::with_single_file(ra_fixture);
-    match eval_goal(&db, file_id) {
+    salsa::attach(&db, || match eval_goal(&db, file_id) {
         Ok(_) => panic!("Expected fail, but it succeeded"),
         Err(e) => {
-            assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, db))
+            assert!(error(simplify(e.clone())), "Actual error was: {}", pretty_print_err(e, &db))
         }
-    }
+    })
 }
 
 #[track_caller]
@@ -79,36 +79,38 @@ fn check_answer(
     check: impl FnOnce(&[u8], &MemoryMap<'_>),
 ) {
     let (db, file_ids) = TestDB::with_many_files(ra_fixture);
-    let file_id = *file_ids.last().unwrap();
-    let r = match eval_goal(&db, file_id) {
-        Ok(t) => t,
-        Err(e) => {
-            let err = pretty_print_err(e, db);
-            panic!("Error in evaluating goal: {err}");
-        }
-    };
-    match &r.data(Interner).value {
-        chalk_ir::ConstValue::Concrete(c) => match &c.interned {
-            ConstScalar::Bytes(b, mm) => {
-                check(b, mm);
+    salsa::attach(&db, || {
+        let file_id = *file_ids.last().unwrap();
+        let r = match eval_goal(&db, file_id) {
+            Ok(t) => t,
+            Err(e) => {
+                let err = pretty_print_err(e, &db);
+                panic!("Error in evaluating goal: {err}");
             }
-            x => panic!("Expected number but found {x:?}"),
-        },
-        _ => panic!("result of const eval wasn't a concrete const"),
-    }
+        };
+        match &r.data(Interner).value {
+            chalk_ir::ConstValue::Concrete(c) => match &c.interned {
+                ConstScalar::Bytes(b, mm) => {
+                    check(b, mm);
+                }
+                x => panic!("Expected number but found {x:?}"),
+            },
+            _ => panic!("result of const eval wasn't a concrete const"),
+        }
+    });
 }
 
-fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String {
+fn pretty_print_err(e: ConstEvalError, db: &TestDB) -> String {
     let mut err = String::new();
     let span_formatter = |file, range| format!("{file:?} {range:?}");
     let display_target =
-        DisplayTarget::from_crate(&db, *db.all_crates().last().expect("no crate graph present"));
+        DisplayTarget::from_crate(db, *db.all_crates().last().expect("no crate graph present"));
     match e {
         ConstEvalError::MirLowerError(e) => {
-            e.pretty_print(&mut err, &db, span_formatter, display_target)
+            e.pretty_print(&mut err, db, span_formatter, display_target)
         }
         ConstEvalError::MirEvalError(e) => {
-            e.pretty_print(&mut err, &db, span_formatter, display_target)
+            e.pretty_print(&mut err, db, span_formatter, display_target)
         }
     }
     .unwrap();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
index 6e07d3afe55..155f1336e41 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval_nextsolver.rs
@@ -222,7 +222,7 @@ pub(crate) fn const_eval_discriminant_variant(
 // and make this function private. See the fixme comment on `InferenceContext::resolve_all`.
 pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'db>) -> Const<'db> {
     let interner = DbInterner::new_with(ctx.db, None, None);
-    let infer = ctx.clone().resolve_all();
+    let infer = ctx.fixme_resolve_all_clone();
     fn has_closure(body: &Body, expr: ExprId) -> bool {
         if matches!(body[expr], Expr::Closure { .. }) {
             return true;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 448fc4aede0..71fb3d44fb7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -16,8 +16,8 @@ use smallvec::SmallVec;
 use triomphe::Arc;
 
 use crate::{
-    Binders, Const, ImplTraitId, ImplTraits, InferenceResult, PolyFnSig, Substitution,
-    TraitEnvironment, TraitRef, Ty, TyDefId, ValueTyDefId, chalk_db,
+    Binders, Const, ImplTraitId, ImplTraits, InferenceResult, Substitution, TraitEnvironment, Ty,
+    TyDefId, ValueTyDefId, chalk_db,
     consteval::ConstEvalError,
     drop::DropGlue,
     dyn_compatibility::DynCompatibilityViolation,
@@ -49,7 +49,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: DefWithBodyId,
         subst: Substitution,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Result<Arc<MirBody>, MirLowerError>;
 
     #[salsa::invoke(crate::mir::monomorphized_mir_body_for_closure_query)]
@@ -57,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: InternedClosureId,
         subst: Substitution,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Result<Arc<MirBody>, MirLowerError>;
 
     #[salsa::invoke(crate::mir::borrowck_query)]
@@ -70,7 +70,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &self,
         def: GeneralConstId,
         subst: Substitution,
-        trait_env: Option<Arc<TraitEnvironment>>,
+        trait_env: Option<Arc<TraitEnvironment<'_>>>,
     ) -> Result<Const, ConstEvalError>;
 
     #[salsa::invoke(crate::consteval::const_eval_static_query)]
@@ -84,7 +84,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::method_resolution::lookup_impl_method_query)]
     fn lookup_impl_method(
         &self,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
         func: FunctionId,
         fn_subst: Substitution,
     ) -> (FunctionId, Substitution);
@@ -97,7 +97,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &'db self,
         def: AdtId,
         args: crate::next_solver::GenericArgs<'db>,
-        trait_env: Arc<TraitEnvironment>,
+        trait_env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::layout_of_ty_query)]
@@ -105,7 +105,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     fn layout_of_ty<'db>(
         &'db self,
         ty: crate::next_solver::Ty<'db>,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'db>>,
     ) -> Result<Arc<Layout>, LayoutError>;
 
     #[salsa::invoke(crate::layout::target_data_layout_query)]
@@ -114,55 +114,94 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::dyn_compatibility::dyn_compatibility_of_trait_query)]
     fn dyn_compatibility_of_trait(&self, trait_: TraitId) -> Option<DynCompatibilityViolation>;
 
-    #[salsa::invoke(crate::lower::ty_query)]
+    #[salsa::invoke(crate::lower_nextsolver::ty_query)]
     #[salsa::transparent]
-    fn ty(&self, def: TyDefId) -> Binders<Ty>;
+    fn ty<'db>(
+        &'db self,
+        def: TyDefId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
 
-    #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::type_for_type_alias_with_diagnostics_cycle_result)]
-    fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics);
+    #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
+    fn type_for_type_alias_with_diagnostics<'db>(
+        &'db self,
+        def: TypeAliasId,
+    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
 
     /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
     /// a `StructId` or `EnumVariantId` with a record constructor.
-    #[salsa::invoke(crate::lower::value_ty_query)]
-    fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>;
+    #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
+    fn value_ty<'db>(
+        &'db self,
+        def: ValueTyDefId,
+    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
 
-    #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::impl_self_ty_with_diagnostics_cycle_result)]
-    fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics);
+    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
+    fn impl_self_ty_with_diagnostics<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
 
-    #[salsa::invoke(crate::lower::impl_self_ty_query)]
+    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
     #[salsa::transparent]
-    fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
+    fn impl_self_ty<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
 
     // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
-    fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
+    #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower_nextsolver::const_param_ty_with_diagnostics_cycle_result)]
+    fn const_param_ty_with_diagnostics<'db>(
+        &'db self,
+        def: ConstParamId,
+    ) -> (crate::next_solver::Ty<'db>, Diagnostics);
 
-    #[salsa::invoke(crate::lower::const_param_ty_query)]
-    #[salsa::transparent]
+    // FIXME: Make this a non-interned query.
+    #[salsa::invoke_interned(crate::lower::const_param_ty_query)]
+    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_cycle_result)]
     fn const_param_ty(&self, def: ConstParamId) -> Ty;
 
-    #[salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)]
-    fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders<TraitRef>, Diagnostics)>;
+    #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
+    fn impl_trait_with_diagnostics<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> Option<(
+        crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
+        Diagnostics,
+    )>;
 
-    #[salsa::invoke(crate::lower::impl_trait_query)]
+    #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
     #[salsa::transparent]
-    fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
+    fn impl_trait<'db>(
+        &'db self,
+        def: ImplId,
+    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
 
-    #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)]
-    fn field_types_with_diagnostics(
-        &self,
+    #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
+    fn field_types_with_diagnostics<'db>(
+        &'db self,
         var: VariantId,
-    ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics);
+    ) -> (
+        Arc<
+            ArenaMap<
+                LocalFieldId,
+                crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
+            >,
+        >,
+        Diagnostics,
+    );
 
     #[salsa::invoke(crate::lower::field_types_query)]
     #[salsa::transparent]
     fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>;
 
-    #[salsa::invoke(crate::lower::callable_item_signature_query)]
-    fn callable_item_signature(&self, def: CallableDefId) -> PolyFnSig;
+    #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
+    fn callable_item_signature<'db>(
+        &'db self,
+        def: CallableDefId,
+    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
 
     #[salsa::invoke(crate::lower::return_type_impl_traits)]
     fn return_type_impl_traits(&self, def: FunctionId) -> Option<Arc<Binders<ImplTraits>>>;
@@ -182,12 +221,28 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::lower::generic_predicates_query)]
     fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates;
 
-    #[salsa::invoke(crate::lower::trait_environment_for_body_query)]
+    #[salsa::invoke(
+        crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
+    )]
+    fn generic_predicates_without_parent_with_diagnostics<'db>(
+        &'db self,
+        def: GenericDefId,
+    ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
+
+    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
+    #[salsa::transparent]
+    fn generic_predicates_without_parent<'db>(
+        &'db self,
+        def: GenericDefId,
+    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
+
+    #[salsa::invoke(crate::lower_nextsolver::trait_environment_for_body_query)]
     #[salsa::transparent]
-    fn trait_environment_for_body(&self, def: DefWithBodyId) -> Arc<TraitEnvironment>;
+    fn trait_environment_for_body<'db>(&'db self, def: DefWithBodyId)
+    -> Arc<TraitEnvironment<'db>>;
 
-    #[salsa::invoke(crate::lower::trait_environment_query)]
-    fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>;
+    #[salsa::invoke(crate::lower_nextsolver::trait_environment_query)]
+    fn trait_environment<'db>(&'db self, def: GenericDefId) -> Arc<TraitEnvironment<'db>>;
 
     #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)]
     #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)]
@@ -258,7 +313,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     fn normalize_projection(
         &self,
         projection: crate::ProjectionTy,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'_>>,
     ) -> Ty;
 
     #[salsa::invoke(crate::traits::trait_solve_query)]
@@ -272,87 +327,14 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     #[salsa::invoke(crate::drop::has_drop_glue)]
     #[salsa::cycle(cycle_result = crate::drop::has_drop_glue_cycle_result)]
-    fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue;
+    fn has_drop_glue(&self, ty: Ty, env: Arc<TraitEnvironment<'_>>) -> DropGlue;
 
     // next trait solver
 
-    #[salsa::invoke(crate::lower_nextsolver::ty_query)]
-    #[salsa::transparent]
-    fn ty_ns<'db>(
-        &'db self,
-        def: TyDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
-
-    /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is
-    /// a `StructId` or `EnumVariantId` with a record constructor.
-    #[salsa::invoke(crate::lower_nextsolver::value_ty_query)]
-    fn value_ty_ns<'db>(
-        &'db self,
-        def: ValueTyDefId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::type_for_type_alias_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::type_for_type_alias_with_diagnostics_cycle_result)]
-    fn type_for_type_alias_with_diagnostics_ns<'db>(
-        &'db self,
-        def: TypeAliasId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_with_diagnostics_query)]
-    #[salsa::cycle(cycle_result = crate::lower_nextsolver::impl_self_ty_with_diagnostics_cycle_result)]
-    fn impl_self_ty_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> (crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_self_ty_query)]
-    #[salsa::transparent]
-    fn impl_self_ty_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>;
-
-    // FIXME: Make this a non-interned query.
-    #[salsa::invoke_interned(crate::lower_nextsolver::const_param_ty_with_diagnostics_query)]
-    fn const_param_ty_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ConstParamId,
-    ) -> (crate::next_solver::Ty<'db>, Diagnostics);
-
     #[salsa::invoke(crate::lower_nextsolver::const_param_ty_query)]
     #[salsa::transparent]
     fn const_param_ty_ns<'db>(&'db self, def: ConstParamId) -> crate::next_solver::Ty<'db>;
 
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_with_diagnostics_query)]
-    fn impl_trait_with_diagnostics_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> Option<(
-        crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>,
-        Diagnostics,
-    )>;
-
-    #[salsa::invoke(crate::lower_nextsolver::impl_trait_query)]
-    #[salsa::transparent]
-    fn impl_trait_ns<'db>(
-        &'db self,
-        def: ImplId,
-    ) -> Option<crate::next_solver::EarlyBinder<'db, crate::next_solver::TraitRef<'db>>>;
-
-    #[salsa::invoke(crate::lower_nextsolver::field_types_with_diagnostics_query)]
-    fn field_types_with_diagnostics_ns<'db>(
-        &'db self,
-        var: VariantId,
-    ) -> (
-        Arc<
-            ArenaMap<
-                LocalFieldId,
-                crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>,
-            >,
-        >,
-        Diagnostics,
-    );
-
     #[salsa::invoke(crate::lower_nextsolver::field_types_query)]
     #[salsa::transparent]
     fn field_types_ns<'db>(
@@ -362,12 +344,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         ArenaMap<LocalFieldId, crate::next_solver::EarlyBinder<'db, crate::next_solver::Ty<'db>>>,
     >;
 
-    #[salsa::invoke(crate::lower_nextsolver::callable_item_signature_query)]
-    fn callable_item_signature_ns<'db>(
-        &'db self,
-        def: CallableDefId,
-    ) -> crate::next_solver::EarlyBinder<'db, crate::next_solver::PolyFnSig<'db>>;
-
     #[salsa::invoke(crate::lower_nextsolver::return_type_impl_traits)]
     fn return_type_impl_traits_ns<'db>(
         &'db self,
@@ -394,21 +370,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
         &'db self,
         def: GenericDefId,
     ) -> crate::lower_nextsolver::GenericPredicates<'db>;
-
-    #[salsa::invoke(
-        crate::lower_nextsolver::generic_predicates_without_parent_with_diagnostics_query
-    )]
-    fn generic_predicates_without_parent_with_diagnostics_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> (crate::lower_nextsolver::GenericPredicates<'db>, Diagnostics);
-
-    #[salsa::invoke(crate::lower_nextsolver::generic_predicates_without_parent_query)]
-    #[salsa::transparent]
-    fn generic_predicates_without_parent_ns<'db>(
-        &'db self,
-        def: GenericDefId,
-    ) -> crate::lower_nextsolver::GenericPredicates<'db>;
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 403ea05a4f5..d05814e0e7e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -81,17 +81,17 @@ impl BodyValidationDiagnostic {
     }
 }
 
-struct ExprValidator {
+struct ExprValidator<'db> {
     owner: DefWithBodyId,
     body: Arc<Body>,
     infer: Arc<InferenceResult>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     diagnostics: Vec<BodyValidationDiagnostic>,
     validate_lints: bool,
 }
 
-impl ExprValidator {
-    fn validate_body(&mut self, db: &dyn HirDatabase) {
+impl<'db> ExprValidator<'db> {
+    fn validate_body(&mut self, db: &'db dyn HirDatabase) {
         let mut filter_map_next_checker = None;
         // we'll pass &mut self while iterating over body.exprs, so they need to be disjoint
         let body = Arc::clone(&self.body);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 56fd12e1f2b..eb20d3c51ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -70,7 +70,7 @@ pub(crate) struct MatchCheckCtx<'db> {
     body: DefWithBodyId,
     pub(crate) db: &'db dyn HirDatabase,
     exhaustive_patterns: bool,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 }
 
 impl<'db> MatchCheckCtx<'db> {
@@ -78,7 +78,7 @@ impl<'db> MatchCheckCtx<'db> {
         module: ModuleId,
         body: DefWithBodyId,
         db: &'db dyn HirDatabase,
-        env: Arc<TraitEnvironment>,
+        env: Arc<TraitEnvironment<'db>>,
     ) -> Self {
         let def_map = module.crate_def_map(db);
         let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 3f04b72c2fc..3c78f5ef387 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -315,6 +315,22 @@ impl<'db> UnsafeVisitor<'db> {
                     }
                     _ => (),
                 }
+
+                let mut peeled = *expr;
+                while let Expr::Field { expr: lhs, .. } = &self.body[peeled] {
+                    if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
+                        self.infer.field_resolution(peeled)
+                    {
+                        peeled = *lhs;
+                    } else {
+                        break;
+                    }
+                }
+
+                // Walk the peeled expression (the LHS of the union field chain)
+                self.walk_expr(peeled);
+                // Return so we don't recurse directly onto the union field access(es)
+                return;
             }
             Expr::MethodCall { .. } => {
                 if let Some((func, _)) = self.infer.method_resolution(current) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 519e4b59237..e11ce51cdb8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -46,8 +46,8 @@ use span::Edition;
 use stdx::never;
 use triomphe::Arc;
 
-use crate::next_solver::infer::DbInternerInferExt;
 use crate::next_solver::infer::traits::ObligationCause;
+use crate::next_solver::{infer::DbInternerInferExt, mapping::NextSolverToChalk};
 use crate::{
     AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar,
     ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
@@ -792,19 +792,16 @@ fn render_const_scalar_ns(
     let trait_env = TraitEnvironment::empty(f.krate());
     let interner = DbInterner::new_with(f.db, Some(trait_env.krate), trait_env.block);
     let infcx = interner.infer_ctxt().build(rustc_type_ir::TypingMode::PostAnalysis);
-    let ty = infcx
-        .at(&ObligationCause::new(), trait_env.env.to_nextsolver(interner))
-        .deeply_normalize(ty)
-        .unwrap_or(ty);
+    let ty = infcx.at(&ObligationCause::new(), trait_env.env).deeply_normalize(ty).unwrap_or(ty);
     render_const_scalar_inner(f, b, memory_map, ty, trait_env)
 }
 
-fn render_const_scalar_inner(
+fn render_const_scalar_inner<'db>(
     f: &mut HirFormatter<'_>,
     b: &[u8],
     memory_map: &MemoryMap<'_>,
-    ty: crate::next_solver::Ty<'_>,
-    trait_env: Arc<TraitEnvironment>,
+    ty: crate::next_solver::Ty<'db>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<(), HirDisplayError> {
     use rustc_type_ir::TyKind;
     match ty.kind() {
@@ -1068,11 +1065,11 @@ fn render_const_scalar_inner(
     }
 }
 
-fn render_variant_after_name(
+fn render_variant_after_name<'db>(
     data: &VariantFields,
     f: &mut HirFormatter<'_>,
     field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
     layout: &Layout,
     args: GenericArgs<'_>,
     b: &[u8],
@@ -1301,7 +1298,9 @@ impl<'db> HirDisplay for crate::next_solver::Ty<'db> {
                 let def = def.0;
                 let sig = db
                     .callable_item_signature(def)
-                    .substitute(Interner, &convert_args_for_result(interner, args.as_slice()));
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
 
                 if f.display_kind.is_source_code() {
                     // `FnDef` is anonymous and there's no surface syntax for it. Show it as a
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
index f5c2f41069e..413f70532a5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
@@ -7,6 +7,8 @@ use hir_def::signatures::StructFlags;
 use stdx::never;
 use triomphe::Arc;
 
+use crate::next_solver::DbInterner;
+use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
     AliasTy, Canonical, CanonicalVarKinds, ConcreteConst, ConstScalar, ConstValue, InEnvironment,
     Interner, ProjectionTy, TraitEnvironment, Ty, TyBuilder, TyKind, db::HirDatabase,
@@ -43,7 +45,11 @@ pub enum DropGlue {
     HasDropGlue,
 }
 
-pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> DropGlue {
+pub(crate) fn has_drop_glue(
+    db: &dyn HirDatabase,
+    ty: Ty,
+    env: Arc<TraitEnvironment<'_>>,
+) -> DropGlue {
     match ty.kind(Interner) {
         TyKind::Adt(adt, subst) => {
             if has_destructor(db, adt.0) {
@@ -165,7 +171,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
 
 fn projection_has_drop_glue(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     projection: ProjectionTy,
     ty: Ty,
 ) -> DropGlue {
@@ -178,13 +184,16 @@ fn projection_has_drop_glue(
     }
 }
 
-fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool {
+fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment<'_>>) -> bool {
     let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else {
         return false;
     };
     let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build();
     let goal = Canonical {
-        value: InEnvironment::new(&env.env, trait_ref.cast(Interner)),
+        value: InEnvironment::new(
+            &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+            trait_ref.cast(Interner),
+        ),
         binders: CanonicalVarKinds::empty(Interner),
     };
     db.trait_solve(env.krate, env.block, goal).certain()
@@ -193,7 +202,7 @@ fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironment>) -> bool {
 pub(crate) fn has_drop_glue_cycle_result(
     _db: &dyn HirDatabase,
     _ty: Ty,
-    _env: Arc<TraitEnvironment>,
+    _env: Arc<TraitEnvironment<'_>>,
 ) -> DropGlue {
     DropGlue::None
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index b87c9982177..b2406a08895 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -329,7 +329,7 @@ where
         cb(MethodViolationCode::AsyncFn)?;
     }
 
-    let sig = db.callable_item_signature_ns(func.into());
+    let sig = db.callable_item_signature(func.into());
     if sig
         .skip_binder()
         .inputs()
@@ -364,7 +364,7 @@ where
         cb(MethodViolationCode::UndispatchableReceiver)?;
     }
 
-    let predicates = &*db.generic_predicates_without_parent_ns(func.into());
+    let predicates = &*db.generic_predicates_without_parent(func.into());
     for pred in predicates {
         let pred = pred.kind().skip_binder();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 017119781a7..0282b7a9363 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -19,6 +19,7 @@ pub(crate) mod closure;
 mod coerce;
 pub(crate) mod diagnostics;
 mod expr;
+mod fallback;
 mod mutability;
 mod pat;
 mod path;
@@ -53,16 +54,16 @@ use indexmap::IndexSet;
 use intern::sym;
 use la_arena::{ArenaMap, Entry};
 use rustc_hash::{FxHashMap, FxHashSet};
+use rustc_type_ir::inherent::Ty as _;
 use stdx::{always, never};
 use triomphe::Arc;
 
-use crate::db::InternedClosureId;
 use crate::{
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, ImplTraitId, ImplTraitIdx,
     IncorrectGenericsLenKind, Interner, Lifetime, OpaqueTyId, ParamLoweringMode,
     PathLoweringDiagnostic, ProjectionTy, Substitution, TargetFeatures, TraitEnvironment, Ty,
     TyBuilder, TyExt,
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosureId},
     fold_tys,
     generics::Generics,
     infer::{
@@ -75,6 +76,7 @@ use crate::{
     mir::MirSpan,
     next_solver::{
         self, DbInterner,
+        infer::{DefineOpaqueTypes, traits::ObligationCause},
         mapping::{ChalkToNextSolver, NextSolverToChalk},
     },
     static_lifetime, to_assoc_type_id,
@@ -138,6 +140,20 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
 
     ctx.infer_mut_body();
 
+    ctx.type_inference_fallback();
+
+    // Comment from rustc:
+    // Even though coercion casts provide type hints, we check casts after fallback for
+    // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
+    let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks);
+    for mut cast in cast_checks.into_iter() {
+        if let Err(diag) = cast.check(&mut ctx) {
+            ctx.diagnostics.push(diag);
+        }
+    }
+
+    ctx.table.select_obligations_where_possible();
+
     ctx.infer_closures();
 
     Arc::new(ctx.resolve_all())
@@ -152,7 +168,7 @@ pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<I
 /// This is appropriate to use only after type-check: it assumes
 /// that normalization will succeed, for example.
 #[tracing::instrument(level = "debug", skip(db))]
-pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
+pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment<'_>>, ty: Ty) -> Ty {
     // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
     // works for the type case, so we check array unconditionally. Remove the array part
     // when the bug in chalk becomes fixed.
@@ -165,7 +181,6 @@ pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>,
 
     let ty_with_vars = table.normalize_associated_types_in(ty);
     table.select_obligations_where_possible();
-    table.propagate_diverging_flag();
     table.resolve_completely(ty_with_vars)
 }
 
@@ -632,6 +647,26 @@ impl InferenceResult {
     pub fn binding_mode(&self, id: PatId) -> Option<BindingMode> {
         self.binding_modes.get(id).copied()
     }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn expression_types(&self) -> impl Iterator<Item = (ExprId, &Ty)> {
+        self.type_of_expr.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn pattern_types(&self) -> impl Iterator<Item = (PatId, &Ty)> {
+        self.type_of_pat.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn binding_types(&self) -> impl Iterator<Item = (BindingId, &Ty)> {
+        self.type_of_binding.iter()
+    }
+
+    // This method is consumed by external tools to run rust-analyzer as a library. Don't remove, please.
+    pub fn return_position_impl_trait_types(&self) -> impl Iterator<Item = (ImplTraitIdx, &Ty)> {
+        self.type_of_rpit.iter()
+    }
 }
 
 impl Index<ExprId> for InferenceResult {
@@ -666,6 +701,25 @@ impl Index<BindingId> for InferenceResult {
     }
 }
 
+#[derive(Debug, Clone)]
+struct InternedStandardTypesNextSolver<'db> {
+    unit: crate::next_solver::Ty<'db>,
+    never: crate::next_solver::Ty<'db>,
+    i32: crate::next_solver::Ty<'db>,
+    f64: crate::next_solver::Ty<'db>,
+}
+
+impl<'db> InternedStandardTypesNextSolver<'db> {
+    fn new(interner: DbInterner<'db>) -> Self {
+        Self {
+            unit: crate::next_solver::Ty::new_unit(interner),
+            never: crate::next_solver::Ty::new(interner, crate::next_solver::TyKind::Never),
+            i32: crate::next_solver::Ty::new_int(interner, rustc_type_ir::IntTy::I32),
+            f64: crate::next_solver::Ty::new_float(interner, rustc_type_ir::FloatTy::F64),
+        }
+    }
+}
+
 /// The inference context contains all information needed during type inference.
 #[derive(Clone, Debug)]
 pub(crate) struct InferenceContext<'db> {
@@ -698,6 +752,7 @@ pub(crate) struct InferenceContext<'db> {
     resume_yield_tys: Option<(Ty, Ty)>,
     diverges: Diverges,
     breakables: Vec<BreakableContext<'db>>,
+    types: InternedStandardTypesNextSolver<'db>,
 
     /// Whether we are inside the pattern of a destructuring assignment.
     inside_assignment: bool,
@@ -778,11 +833,13 @@ impl<'db> InferenceContext<'db> {
         resolver: Resolver<'db>,
     ) -> Self {
         let trait_env = db.trait_environment_for_body(owner);
+        let table = unify::InferenceTable::new(db, trait_env);
         InferenceContext {
+            types: InternedStandardTypesNextSolver::new(table.interner),
             target_features: OnceCell::new(),
             generics: OnceCell::new(),
             result: InferenceResult::default(),
-            table: unify::InferenceTable::new(db, trait_env),
+            table,
             tuple_field_accesses_rev: Default::default(),
             return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
             resume_yield_tys: None,
@@ -845,24 +902,33 @@ impl<'db> InferenceContext<'db> {
         self.result.has_errors = true;
     }
 
-    // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
-    // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
-    // used this function for another workaround, mention it here. If you really need this function and believe that
-    // there is no problem in it being `pub(crate)`, remove this comment.
-    pub(crate) fn resolve_all(mut self) -> InferenceResult {
-        self.table.select_obligations_where_possible();
-        self.table.fallback_if_possible();
+    /// Clones `self` and calls `resolve_all()` on it.
+    // FIXME: Remove this.
+    pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult {
+        let mut ctx = self.clone();
+
+        ctx.type_inference_fallback();
 
         // Comment from rustc:
         // Even though coercion casts provide type hints, we check casts after fallback for
         // backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
-        let cast_checks = std::mem::take(&mut self.deferred_cast_checks);
+        let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks);
         for mut cast in cast_checks.into_iter() {
-            if let Err(diag) = cast.check(&mut self) {
-                self.diagnostics.push(diag);
+            if let Err(diag) = cast.check(&mut ctx) {
+                ctx.diagnostics.push(diag);
             }
         }
 
+        ctx.table.select_obligations_where_possible();
+
+        ctx.resolve_all()
+    }
+
+    // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
+    // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
+    // used this function for another workaround, mention it here. If you really need this function and believe that
+    // there is no problem in it being `pub(crate)`, remove this comment.
+    pub(crate) fn resolve_all(self) -> InferenceResult {
         let InferenceContext {
             mut table, mut result, tuple_field_accesses_rev, diagnostics, ..
         } = self;
@@ -894,11 +960,6 @@ impl<'db> InferenceContext<'db> {
             diagnostics: _,
         } = &mut result;
 
-        // FIXME resolve obligations as well (use Guidance if necessary)
-        table.select_obligations_where_possible();
-
-        // make sure diverging type variables are marked as such
-        table.propagate_diverging_flag();
         for ty in type_of_expr.values_mut() {
             *ty = table.resolve_completely(ty.clone());
             *has_errors = *has_errors || ty.contains_unknown();
@@ -1653,6 +1714,22 @@ impl<'db> InferenceContext<'db> {
         self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
     }
 
+    fn demand_eqtype(
+        &mut self,
+        expected: crate::next_solver::Ty<'db>,
+        actual: crate::next_solver::Ty<'db>,
+    ) {
+        let result = self
+            .table
+            .infer_ctxt
+            .at(&ObligationCause::new(), self.table.trait_env.env)
+            .eq(DefineOpaqueTypes::Yes, expected, actual)
+            .map(|infer_ok| self.table.register_infer_ok(infer_ok));
+        if let Err(_err) = result {
+            // FIXME: Emit diagnostic.
+        }
+    }
+
     fn resolve_associated_type_with_params(
         &mut self,
         inner_ty: Ty,
@@ -1708,6 +1785,7 @@ impl<'db> InferenceContext<'db> {
             LifetimeElisionKind::Infer,
         );
         let mut path_ctx = ctx.at_path(path, node);
+        let interner = DbInterner::conjure();
         let (resolution, unresolved) = if value_ns {
             let Some(res) = path_ctx.resolve_path_in_value_ns(HygieneId::ROOT) else {
                 return (self.err_ty(), None);
@@ -1717,15 +1795,27 @@ impl<'db> InferenceContext<'db> {
                     ValueNs::EnumVariantId(var) => {
                         let substs = path_ctx.substs_from_path(var.into(), true, false);
                         drop(ctx);
-                        let ty = self.db.ty(var.lookup(self.db).parent.into());
-                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
+                        let ty = self
+                            .db
+                            .ty(var.lookup(self.db).parent.into())
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
+                        let ty = self.insert_type_vars(ty);
                         return (ty, Some(var.into()));
                     }
                     ValueNs::StructId(strukt) => {
                         let substs = path_ctx.substs_from_path(strukt.into(), true, false);
                         drop(ctx);
-                        let ty = self.db.ty(strukt.into());
-                        let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
+                        let ty = self
+                            .db
+                            .ty(strukt.into())
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
+                        let ty = self.insert_type_vars(ty);
                         return (ty, Some(strukt.into()));
                     }
                     ValueNs::ImplSelf(impl_id) => (TypeNs::SelfType(impl_id), None),
@@ -1746,28 +1836,37 @@ impl<'db> InferenceContext<'db> {
             TypeNs::AdtId(AdtId::StructId(strukt)) => {
                 let substs = path_ctx.substs_from_path(strukt.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(strukt.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(strukt.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
             }
             TypeNs::AdtId(AdtId::UnionId(u)) => {
                 let substs = path_ctx.substs_from_path(u.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(u.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(u.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
             }
             TypeNs::EnumVariantId(var) => {
                 let substs = path_ctx.substs_from_path(var.into(), true, false);
                 drop(ctx);
-                let ty = self.db.ty(var.lookup(self.db).parent.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self
+                    .db
+                    .ty(var.lookup(self.db).parent.into())
+                    .instantiate(interner, args)
+                    .to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
                 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
             }
             TypeNs::SelfType(impl_id) => {
                 let generics = crate::generics::generics(self.db, impl_id.into());
                 let substs = generics.placeholder_subst(self.db);
-                let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let mut ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
 
                 let Some(remaining_idx) = unresolved else {
                     drop(ctx);
@@ -1844,8 +1943,10 @@ impl<'db> InferenceContext<'db> {
                 };
                 let substs = path_ctx.substs_from_path_segment(it.into(), true, None, false);
                 drop(ctx);
-                let ty = self.db.ty(it.into());
-                let ty = self.insert_type_vars(ty.substitute(Interner, &substs));
+                let interner = DbInterner::conjure();
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty = self.db.ty(it.into()).instantiate(interner, args).to_chalk(interner);
+                let ty = self.insert_type_vars(ty);
 
                 self.resolve_variant_on_alias(ty, unresolved, mod_path)
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 1d5d8dd13ed..4a57b2f3751 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -318,7 +318,7 @@ impl<'db> InferenceContext<'db> {
                     _ = self
                         .table
                         .infer_ctxt
-                        .at(&ObligationCause::new(), self.table.param_env)
+                        .at(&ObligationCause::new(), self.table.trait_env.env)
                         .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig)
                         .map(|infer_ok| self.table.register_infer_ok(infer_ok));
 
@@ -703,7 +703,7 @@ impl<'db> InferenceContext<'db> {
                 let cause = ObligationCause::new();
                 let InferOk { value: (), obligations } = table
                     .infer_ctxt
-                    .at(&cause, table.param_env)
+                    .at(&cause, table.trait_env.env)
                     .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?;
                 all_obligations.extend(obligations);
             }
@@ -711,7 +711,7 @@ impl<'db> InferenceContext<'db> {
             let supplied_output_ty = supplied_sig.output();
             let cause = ObligationCause::new();
             let InferOk { value: (), obligations } =
-                table.infer_ctxt.at(&cause, table.param_env).eq(
+                table.infer_ctxt.at(&cause, table.trait_env.env).eq(
                     DefineOpaqueTypes::Yes,
                     expected_sigs.liberated_sig.output(),
                     supplied_output_ty,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 7930d8b0ed6..62ce00a2e33 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -144,7 +144,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
     fn unify_raw(&mut self, a: Ty<'db>, b: Ty<'db>) -> InferResult<'db, Ty<'db>> {
         debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
         self.commit_if_ok(|this| {
-            let at = this.infer_ctxt().at(&this.cause, this.table.param_env);
+            let at = this.infer_ctxt().at(&this.cause, this.table.trait_env.env);
 
             let res = if this.use_lub {
                 at.lub(b, a)
@@ -210,9 +210,8 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
             // If we're coercing into an inference var, mark it as possibly diverging.
-            // FIXME: rustc does this differently.
-            if let TyKind::Infer(rustc_type_ir::TyVar(b)) = b.kind() {
-                self.table.set_diverging(b.as_u32().into(), chalk_ir::TyVariableKind::General);
+            if b.is_infer() {
+                self.table.set_diverging(b);
             }
 
             if self.coerce_never {
@@ -330,7 +329,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
                     obligations.push(Obligation::new(
                         self.interner(),
                         self.cause.clone(),
-                        self.table.param_env,
+                        self.table.trait_env.env,
                         Binder::dummy(PredicateKind::Coerce(CoercePredicate {
                             a: source_ty,
                             b: target_ty,
@@ -718,7 +717,7 @@ impl<'a, 'b, 'db> Coerce<'a, 'b, 'db> {
         let mut queue: SmallVec<[PredicateObligation<'db>; 4]> = smallvec![Obligation::new(
             self.interner(),
             cause,
-            self.table.param_env,
+            self.table.trait_env.env,
             TraitRef::new(
                 self.interner(),
                 coerce_unsized_did.into(),
@@ -1114,8 +1113,12 @@ impl<'db> InferenceContext<'db> {
                         match self.table.commit_if_ok(|table| {
                             // We need to eagerly handle nested obligations due to lazy norm.
                             let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
-                            let value =
-                                ocx.lub(&ObligationCause::new(), table.param_env, prev_ty, new_ty)?;
+                            let value = ocx.lub(
+                                &ObligationCause::new(),
+                                table.trait_env.env,
+                                prev_ty,
+                                new_ty,
+                            )?;
                             if ocx.select_where_possible().is_empty() {
                                 Ok(InferOk { value, obligations: ocx.into_pending_obligations() })
                             } else {
@@ -1158,7 +1161,7 @@ impl<'db> InferenceContext<'db> {
             let sig = self
                 .table
                 .infer_ctxt
-                .at(&ObligationCause::new(), self.table.param_env)
+                .at(&ObligationCause::new(), self.table.trait_env.env)
                 .lub(a_sig, b_sig)
                 .map(|ok| self.table.register_infer_ok(ok))?;
 
@@ -1248,7 +1251,7 @@ impl<'db> InferenceContext<'db> {
                         .commit_if_ok(|table| {
                             table
                                 .infer_ctxt
-                                .at(&ObligationCause::new(), table.param_env)
+                                .at(&ObligationCause::new(), table.trait_env.env)
                                 .lub(prev_ty, new_ty)
                         })
                         .unwrap_err())
@@ -1498,7 +1501,7 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
             assert!(expression_ty.is_unit(), "if let hack without unit type");
             icx.table
                 .infer_ctxt
-                .at(cause, icx.table.param_env)
+                .at(cause, icx.table.trait_env.env)
                 .eq(
                     // needed for tests/ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs
                     DefineOpaqueTypes::Yes,
@@ -1564,9 +1567,9 @@ impl<'db, 'exprs> CoerceMany<'db, 'exprs> {
     }
 }
 
-pub fn could_coerce(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn could_coerce<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     tys: &crate::Canonical<(crate::Ty, crate::Ty)>,
 ) -> bool {
     coerce(db, env, tys).is_ok()
@@ -1574,7 +1577,7 @@ pub fn could_coerce(
 
 fn coerce<'db>(
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     tys: &crate::Canonical<(crate::Ty, crate::Ty)>,
 ) -> Result<(Vec<Adjustment>, crate::Ty), TypeError<DbInterner<'db>>> {
     let mut table = InferenceTable::new(db, env);
@@ -1609,16 +1612,21 @@ fn coerce<'db>(
             chalk_ir::GenericArgData::Const(c) => c.inference_var(Interner),
         } == Some(iv))
     };
-    let fallback = |iv, kind, default, binder| match kind {
-        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
-            .map_or(default, |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or(default, |i| {
-            crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)
-        }),
-        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or(default, |i| {
-            crate::BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)
-        }),
+    let fallback = |iv, kind, binder| match kind {
+        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else(
+            || chalk_ir::TyKind::Error.intern(Interner).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_ty(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else(
+            || crate::LifetimeData::Error.intern(Interner).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else(
+            || crate::unknown_const(ty.clone()).cast(Interner),
+            |i| crate::BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner),
+        ),
     };
     // FIXME also map the types in the adjustments
+    // FIXME: We don't fallback correctly since this is done on `InferenceContext` and we only have `InferenceTable`.
     Ok((adjustments, table.resolve_with_fallback(ty.to_chalk(table.interner), &fallback)))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index c5a51dfc4cf..ddf632c1c81 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -23,13 +23,13 @@ use syntax::ast::RangeOp;
 use tracing::debug;
 
 use crate::autoderef::overloaded_deref_ty;
-use crate::next_solver::ErrorGuaranteed;
 use crate::next_solver::infer::DefineOpaqueTypes;
 use crate::next_solver::obligation_ctxt::ObligationCtxt;
+use crate::next_solver::{DbInterner, ErrorGuaranteed};
 use crate::{
-    Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
-    DeclOrigin, IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar,
-    Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval,
+    Adjust, Adjustment, AdtId, AutoBorrow, CallableDefId, CallableSig, DeclContext, DeclOrigin,
+    IncorrectGenericsLenKind, Interner, LifetimeElisionKind, Rawness, Scalar, Substitution,
+    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, consteval,
     generics::generics,
     infer::{
         AllowTwoPhase, BreakableKind,
@@ -1481,7 +1481,10 @@ impl<'db> InferenceContext<'db> {
 
         self.write_method_resolution(tgt_expr, func, subst.clone());
 
-        let method_ty = self.db.value_ty(func.into()).unwrap().substitute(Interner, &subst);
+        let interner = DbInterner::new_with(self.db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+        let method_ty =
+            self.db.value_ty(func.into()).unwrap().instantiate(interner, args).to_chalk(interner);
         self.register_obligations_for_call(&method_ty);
 
         self.infer_expr_coerce(rhs, &Expectation::has_type(rhs_ty.clone()), ExprIsRead::Yes);
@@ -1662,7 +1665,6 @@ impl<'db> InferenceContext<'db> {
             });
         self.resolver.reset_to_guard(g);
         if let Some(prev_env) = prev_env {
-            self.table.param_env = prev_env.env.to_nextsolver(self.table.interner);
             self.table.trait_env = prev_env;
         }
 
@@ -1801,11 +1803,17 @@ impl<'db> InferenceContext<'db> {
                         self.write_expr_adj(receiver, adjustments.into_boxed_slice());
                         self.write_method_resolution(tgt_expr, func, substs.clone());
 
+                        let interner = DbInterner::new_with(self.db, None, None);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         self.check_method_call(
                             tgt_expr,
                             &[],
-                            self.db.value_ty(func.into()).unwrap(),
-                            substs,
+                            self.db
+                                .value_ty(func.into())
+                                .unwrap()
+                                .instantiate(interner, args)
+                                .to_chalk(interner),
                             ty,
                             expected,
                         )
@@ -1964,11 +1972,16 @@ impl<'db> InferenceContext<'db> {
 
                 let substs = self.substs_for_method_call(tgt_expr, func.into(), generic_args);
                 self.write_method_resolution(tgt_expr, func, substs.clone());
+                let interner = DbInterner::new_with(self.db, None, None);
+                let gen_args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
                 self.check_method_call(
                     tgt_expr,
                     args,
-                    self.db.value_ty(func.into()).expect("we have a function def"),
-                    substs,
+                    self.db
+                        .value_ty(func.into())
+                        .expect("we have a function def")
+                        .instantiate(interner, gen_args)
+                        .to_chalk(interner),
                     ty,
                     expected,
                 )
@@ -2013,11 +2026,15 @@ impl<'db> InferenceContext<'db> {
                 let recovered = match assoc_func_with_same_name {
                     Some(f) => {
                         let substs = self.substs_for_method_call(tgt_expr, f.into(), generic_args);
+                        let interner = DbInterner::new_with(self.db, None, None);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         let f = self
                             .db
                             .value_ty(f.into())
                             .expect("we have a function def")
-                            .substitute(Interner, &substs);
+                            .instantiate(interner, args)
+                            .to_chalk(interner);
                         let sig = f.callable_sig(self.db).expect("we have a function def");
                         Some((f, sig, true))
                     }
@@ -2057,12 +2074,10 @@ impl<'db> InferenceContext<'db> {
         &mut self,
         tgt_expr: ExprId,
         args: &[ExprId],
-        method_ty: Binders<Ty>,
-        substs: Substitution,
+        method_ty: Ty,
         receiver_ty: Ty,
         expected: &Expectation,
     ) -> Ty {
-        let method_ty = method_ty.substitute(Interner, &substs);
         self.register_obligations_for_call(&method_ty);
         let interner = self.table.interner;
         let ((formal_receiver_ty, param_tys), ret_ty, is_varargs) =
@@ -2132,7 +2147,7 @@ impl<'db> InferenceContext<'db> {
                         let origin = ObligationCause::new();
                         ocx.sup(
                             &origin,
-                            self.table.param_env,
+                            self.table.trait_env.env,
                             expected_output.to_nextsolver(interner),
                             formal_output,
                         )?;
@@ -2239,7 +2254,7 @@ impl<'db> InferenceContext<'db> {
             let formal_ty_error = this
                 .table
                 .infer_ctxt
-                .at(&ObligationCause::new(), this.table.param_env)
+                .at(&ObligationCause::new(), this.table.trait_env.env)
                 .eq(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty);
 
             // If neither check failed, the types are compatible
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs
new file mode 100644
index 00000000000..2022447ad43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/fallback.rs
@@ -0,0 +1,439 @@
+//! Fallback of infer vars to `!` and `i32`/`f64`.
+
+use intern::sym;
+use petgraph::{
+    Graph,
+    visit::{Dfs, Walker},
+};
+use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
+use rustc_type_ir::{
+    TyVid,
+    inherent::{IntoKind, Ty as _},
+};
+use tracing::debug;
+
+use crate::{
+    infer::InferenceContext,
+    next_solver::{CoercePredicate, PredicateKind, SubtypePredicate, Ty, TyKind},
+};
+
+#[derive(Copy, Clone)]
+pub(crate) enum DivergingFallbackBehavior {
+    /// Always fallback to `()` (aka "always spontaneous decay")
+    ToUnit,
+    /// Sometimes fallback to `!`, but mainly fallback to `()` so that most of the crates are not broken.
+    ContextDependent,
+    /// Always fallback to `!` (which should be equivalent to never falling back + not making
+    /// never-to-any coercions unless necessary)
+    ToNever,
+}
+
+impl<'db> InferenceContext<'db> {
+    pub(super) fn type_inference_fallback(&mut self) {
+        debug!(
+            "type-inference-fallback start obligations: {:#?}",
+            self.table.fulfillment_cx.pending_obligations()
+        );
+
+        // All type checking constraints were added, try to fallback unsolved variables.
+        self.table.select_obligations_where_possible();
+
+        debug!(
+            "type-inference-fallback post selection obligations: {:#?}",
+            self.table.fulfillment_cx.pending_obligations()
+        );
+
+        let fallback_occurred = self.fallback_types();
+
+        if !fallback_occurred {
+            return;
+        }
+
+        // We now see if we can make progress. This might cause us to
+        // unify inference variables for opaque types, since we may
+        // have unified some other type variables during the first
+        // phase of fallback. This means that we only replace
+        // inference variables with their underlying opaque types as a
+        // last resort.
+        //
+        // In code like this:
+        //
+        // ```rust
+        // type MyType = impl Copy;
+        // fn produce() -> MyType { true }
+        // fn bad_produce() -> MyType { panic!() }
+        // ```
+        //
+        // we want to unify the opaque inference variable in `bad_produce`
+        // with the diverging fallback for `panic!` (e.g. `()` or `!`).
+        // This will produce a nice error message about conflicting concrete
+        // types for `MyType`.
+        //
+        // If we had tried to fallback the opaque inference variable to `MyType`,
+        // we will generate a confusing type-check error that does not explicitly
+        // refer to opaque types.
+        self.table.select_obligations_where_possible();
+    }
+
+    fn diverging_fallback_behavior(&self) -> DivergingFallbackBehavior {
+        if self.krate().data(self.db).edition.at_least_2024() {
+            return DivergingFallbackBehavior::ToNever;
+        }
+
+        if self.resolver.def_map().is_unstable_feature_enabled(&sym::never_type_fallback) {
+            return DivergingFallbackBehavior::ContextDependent;
+        }
+
+        DivergingFallbackBehavior::ToUnit
+    }
+
+    fn fallback_types(&mut self) -> bool {
+        // Check if we have any unresolved variables. If not, no need for fallback.
+        let unresolved_variables = self.table.infer_ctxt.unresolved_variables();
+
+        if unresolved_variables.is_empty() {
+            return false;
+        }
+
+        let diverging_fallback_behavior = self.diverging_fallback_behavior();
+
+        let diverging_fallback =
+            self.calculate_diverging_fallback(&unresolved_variables, diverging_fallback_behavior);
+
+        // We do fallback in two passes, to try to generate
+        // better error messages.
+        // The first time, we do *not* replace opaque types.
+        let mut fallback_occurred = false;
+        for ty in unresolved_variables {
+            debug!("unsolved_variable = {:?}", ty);
+            fallback_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
+        }
+
+        fallback_occurred
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with `f64`.
+    //
+    // - Non-numerics may get replaced with `()` or `!`, depending on
+    //   how they were categorized by `calculate_diverging_fallback`
+    //   (and the setting of `#![feature(never_type_fallback)]`).
+    //
+    // Fallback becomes very dubious if we have encountered
+    // type-checking errors. In that case, fallback to Error.
+    //
+    // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
+    // during this call.
+    fn fallback_if_possible(
+        &mut self,
+        ty: Ty<'db>,
+        diverging_fallback: &FxHashMap<Ty<'db>, Ty<'db>>,
+    ) -> bool {
+        // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
+        // is an unsolved variable, and we determine its fallback
+        // based solely on how it was created, not what other type
+        // variables it may have been unified with since then.
+        //
+        // The reason this matters is that other attempts at fallback
+        // may (in principle) conflict with this fallback, and we wish
+        // to generate a type error in that case. (However, this
+        // actually isn't true right now, because we're only using the
+        // builtin fallback rules. This would be true if we were using
+        // user-supplied fallbacks. But it's still useful to write the
+        // code to detect bugs.)
+        //
+        // (Note though that if we have a general type variable `?T`
+        // that is then unified with an integer type variable `?I`
+        // that ultimately never gets resolved to a special integral
+        // type, `?T` is not considered unsolved, but `?I` is. The
+        // same is true for float variables.)
+        let fallback = match ty.kind() {
+            TyKind::Infer(rustc_type_ir::IntVar(_)) => self.types.i32,
+            TyKind::Infer(rustc_type_ir::FloatVar(_)) => self.types.f64,
+            _ => match diverging_fallback.get(&ty) {
+                Some(&fallback_ty) => fallback_ty,
+                None => return false,
+            },
+        };
+        debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
+
+        self.demand_eqtype(ty, fallback);
+        true
+    }
+
+    /// The "diverging fallback" system is rather complicated. This is
+    /// a result of our need to balance 'do the right thing' with
+    /// backwards compatibility.
+    ///
+    /// "Diverging" type variables are variables created when we
+    /// coerce a `!` type into an unbound type variable `?X`. If they
+    /// never wind up being constrained, the "right and natural" thing
+    /// is that `?X` should "fallback" to `!`. This means that e.g. an
+    /// expression like `Some(return)` will ultimately wind up with a
+    /// type like `Option<!>` (presuming it is not assigned or
+    /// constrained to have some other type).
+    ///
+    /// However, the fallback used to be `()` (before the `!` type was
+    /// added). Moreover, there are cases where the `!` type 'leaks
+    /// out' from dead code into type variables that affect live
+    /// code. The most common case is something like this:
+    ///
+    /// ```rust
+    /// # fn foo() -> i32 { 4 }
+    /// match foo() {
+    ///     22 => Default::default(), // call this type `?D`
+    ///     _ => return, // return has type `!`
+    /// } // call the type of this match `?M`
+    /// ```
+    ///
+    /// Here, coercing the type `!` into `?M` will create a diverging
+    /// type variable `?X` where `?X <: ?M`. We also have that `?D <:
+    /// ?M`. If `?M` winds up unconstrained, then `?X` will
+    /// fallback. If it falls back to `!`, then all the type variables
+    /// will wind up equal to `!` -- this includes the type `?D`
+    /// (since `!` doesn't implement `Default`, we wind up a "trait
+    /// not implemented" error in code like this). But since the
+    /// original fallback was `()`, this code used to compile with `?D
+    /// = ()`. This is somewhat surprising, since `Default::default()`
+    /// on its own would give an error because the types are
+    /// insufficiently constrained.
+    ///
+    /// Our solution to this dilemma is to modify diverging variables
+    /// so that they can *either* fallback to `!` (the default) or to
+    /// `()` (the backwards compatibility case). We decide which
+    /// fallback to use based on whether there is a coercion pattern
+    /// like this:
+    ///
+    /// ```ignore (not-rust)
+    /// ?Diverging -> ?V
+    /// ?NonDiverging -> ?V
+    /// ?V != ?NonDiverging
+    /// ```
+    ///
+    /// Here `?Diverging` represents some diverging type variable and
+    /// `?NonDiverging` represents some non-diverging type
+    /// variable. `?V` can be any type variable (diverging or not), so
+    /// long as it is not equal to `?NonDiverging`.
+    ///
+    /// Intuitively, what we are looking for is a case where a
+    /// "non-diverging" type variable (like `?M` in our example above)
+    /// is coerced *into* some variable `?V` that would otherwise
+    /// fallback to `!`. In that case, we make `?V` fallback to `!`,
+    /// along with anything that would flow into `?V`.
+    ///
+    /// The algorithm we use:
+    /// * Identify all variables that are coerced *into* by a
+    ///   diverging variable. Do this by iterating over each
+    ///   diverging, unsolved variable and finding all variables
+    ///   reachable from there. Call that set `D`.
+    /// * Walk over all unsolved, non-diverging variables, and find
+    ///   any variable that has an edge into `D`.
+    fn calculate_diverging_fallback(
+        &self,
+        unresolved_variables: &[Ty<'db>],
+        behavior: DivergingFallbackBehavior,
+    ) -> FxHashMap<Ty<'db>, Ty<'db>> {
+        debug!("calculate_diverging_fallback({:?})", unresolved_variables);
+
+        // Construct a coercion graph where an edge `A -> B` indicates
+        // a type variable is that is coerced
+        let coercion_graph = self.create_coercion_graph();
+
+        // Extract the unsolved type inference variable vids; note that some
+        // unsolved variables are integer/float variables and are excluded.
+        let unsolved_vids = unresolved_variables.iter().filter_map(|ty| ty.ty_vid());
+
+        // Compute the diverging root vids D -- that is, the root vid of
+        // those type variables that (a) are the target of a coercion from
+        // a `!` type and (b) have not yet been solved.
+        //
+        // These variables are the ones that are targets for fallback to
+        // either `!` or `()`.
+        let diverging_roots: FxHashSet<TyVid> = self
+            .table
+            .diverging_type_vars
+            .iter()
+            .map(|&ty| self.shallow_resolve(ty))
+            .filter_map(|ty| ty.ty_vid())
+            .map(|vid| self.table.infer_ctxt.root_var(vid))
+            .collect();
+        debug!(
+            "calculate_diverging_fallback: diverging_type_vars={:?}",
+            self.table.diverging_type_vars
+        );
+        debug!("calculate_diverging_fallback: diverging_roots={:?}", diverging_roots);
+
+        // Find all type variables that are reachable from a diverging
+        // type variable. These will typically default to `!`, unless
+        // we find later that they are *also* reachable from some
+        // other type variable outside this set.
+        let mut roots_reachable_from_diverging = Dfs::empty(&coercion_graph);
+        let mut diverging_vids = vec![];
+        let mut non_diverging_vids = vec![];
+        for unsolved_vid in unsolved_vids {
+            let root_vid = self.table.infer_ctxt.root_var(unsolved_vid);
+            debug!(
+                "calculate_diverging_fallback: unsolved_vid={:?} root_vid={:?} diverges={:?}",
+                unsolved_vid,
+                root_vid,
+                diverging_roots.contains(&root_vid),
+            );
+            if diverging_roots.contains(&root_vid) {
+                diverging_vids.push(unsolved_vid);
+                roots_reachable_from_diverging.move_to(root_vid.as_u32().into());
+
+                // drain the iterator to visit all nodes reachable from this node
+                while roots_reachable_from_diverging.next(&coercion_graph).is_some() {}
+            } else {
+                non_diverging_vids.push(unsolved_vid);
+            }
+        }
+
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_diverging={:?}",
+            roots_reachable_from_diverging,
+        );
+
+        // Find all type variables N0 that are not reachable from a
+        // diverging variable, and then compute the set reachable from
+        // N0, which we call N. These are the *non-diverging* type
+        // variables. (Note that this set consists of "root variables".)
+        let mut roots_reachable_from_non_diverging = Dfs::empty(&coercion_graph);
+        for &non_diverging_vid in &non_diverging_vids {
+            let root_vid = self.table.infer_ctxt.root_var(non_diverging_vid);
+            if roots_reachable_from_diverging.discovered.contains(root_vid.as_usize()) {
+                continue;
+            }
+            roots_reachable_from_non_diverging.move_to(root_vid.as_u32().into());
+            while roots_reachable_from_non_diverging.next(&coercion_graph).is_some() {}
+        }
+        debug!(
+            "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}",
+            roots_reachable_from_non_diverging,
+        );
+
+        debug!("obligations: {:#?}", self.table.fulfillment_cx.pending_obligations());
+
+        // For each diverging variable, figure out whether it can
+        // reach a member of N. If so, it falls back to `()`. Else
+        // `!`.
+        let mut diverging_fallback =
+            FxHashMap::with_capacity_and_hasher(diverging_vids.len(), FxBuildHasher);
+
+        for &diverging_vid in &diverging_vids {
+            let diverging_ty = Ty::new_var(self.table.interner, diverging_vid);
+            let root_vid = self.table.infer_ctxt.root_var(diverging_vid);
+            let can_reach_non_diverging = Dfs::new(&coercion_graph, root_vid.as_u32().into())
+                .iter(&coercion_graph)
+                .any(|n| roots_reachable_from_non_diverging.discovered.contains(n.index()));
+
+            let mut fallback_to = |ty| {
+                diverging_fallback.insert(diverging_ty, ty);
+            };
+
+            match behavior {
+                DivergingFallbackBehavior::ToUnit => {
+                    debug!("fallback to () - legacy: {:?}", diverging_vid);
+                    fallback_to(self.types.unit);
+                }
+                DivergingFallbackBehavior::ContextDependent => {
+                    // FIXME: rustc does the following, but given this is only relevant when the unstable
+                    // `never_type_fallback` feature is active, I chose to not port this.
+                    // if found_infer_var_info.self_in_trait && found_infer_var_info.output {
+                    //     // This case falls back to () to ensure that the code pattern in
+                    //     // tests/ui/never_type/fallback-closure-ret.rs continues to
+                    //     // compile when never_type_fallback is enabled.
+                    //     //
+                    //     // This rule is not readily explainable from first principles,
+                    //     // but is rather intended as a patchwork fix to ensure code
+                    //     // which compiles before the stabilization of never type
+                    //     // fallback continues to work.
+                    //     //
+                    //     // Typically this pattern is encountered in a function taking a
+                    //     // closure as a parameter, where the return type of that closure
+                    //     // (checked by `relationship.output`) is expected to implement
+                    //     // some trait (checked by `relationship.self_in_trait`). This
+                    //     // can come up in non-closure cases too, so we do not limit this
+                    //     // rule to specifically `FnOnce`.
+                    //     //
+                    //     // When the closure's body is something like `panic!()`, the
+                    //     // return type would normally be inferred to `!`. However, it
+                    //     // needs to fall back to `()` in order to still compile, as the
+                    //     // trait is specifically implemented for `()` but not `!`.
+                    //     //
+                    //     // For details on the requirements for these relationships to be
+                    //     // set, see the relationship finding module in
+                    //     // compiler/rustc_trait_selection/src/traits/relationships.rs.
+                    //     debug!("fallback to () - found trait and projection: {:?}", diverging_vid);
+                    //     fallback_to(self.types.unit);
+                    // }
+                    if can_reach_non_diverging {
+                        debug!("fallback to () - reached non-diverging: {:?}", diverging_vid);
+                        fallback_to(self.types.unit);
+                    } else {
+                        debug!("fallback to ! - all diverging: {:?}", diverging_vid);
+                        fallback_to(self.types.never);
+                    }
+                }
+                DivergingFallbackBehavior::ToNever => {
+                    debug!(
+                        "fallback to ! - `rustc_never_type_mode = \"fallback_to_never\")`: {:?}",
+                        diverging_vid
+                    );
+                    fallback_to(self.types.never);
+                }
+            }
+        }
+
+        diverging_fallback
+    }
+
+    /// Returns a graph whose nodes are (unresolved) inference variables and where
+    /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
+    fn create_coercion_graph(&self) -> Graph<(), ()> {
+        let pending_obligations = self.table.fulfillment_cx.pending_obligations();
+        let pending_obligations_len = pending_obligations.len();
+        debug!("create_coercion_graph: pending_obligations={:?}", pending_obligations);
+        let coercion_edges = pending_obligations
+            .into_iter()
+            .filter_map(|obligation| {
+                // The predicates we are looking for look like `Coerce(?A -> ?B)`.
+                // They will have no bound variables.
+                obligation.predicate.kind().no_bound_vars()
+            })
+            .filter_map(|atom| {
+                // We consider both subtyping and coercion to imply 'flow' from
+                // some position in the code `a` to a different position `b`.
+                // This is then used to determine which variables interact with
+                // live code, and as such must fall back to `()` to preserve
+                // soundness.
+                //
+                // In practice currently the two ways that this happens is
+                // coercion and subtyping.
+                let (a, b) = match atom {
+                    PredicateKind::Coerce(CoercePredicate { a, b }) => (a, b),
+                    PredicateKind::Subtype(SubtypePredicate { a_is_expected: _, a, b }) => (a, b),
+                    _ => return None,
+                };
+
+                let a_vid = self.root_vid(a)?;
+                let b_vid = self.root_vid(b)?;
+                Some((a_vid.as_u32(), b_vid.as_u32()))
+            });
+        let num_ty_vars = self.table.infer_ctxt.num_ty_vars();
+        let mut graph = Graph::with_capacity(num_ty_vars, pending_obligations_len);
+        for _ in 0..num_ty_vars {
+            graph.add_node(());
+        }
+        graph.extend_with_edges(coercion_edges);
+        graph
+    }
+
+    /// If `ty` is an unresolved type variable, returns its root vid.
+    fn root_vid(&self, ty: Ty<'db>) -> Option<TyVid> {
+        Some(self.table.infer_ctxt.root_var(self.shallow_resolve(ty).ty_vid()?))
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 80f7324e58b..733f3c27880 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -17,7 +17,10 @@ use crate::{
     generics::generics,
     infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext,
     method_resolution::{self, VisibleFromModule},
-    next_solver::mapping::ChalkToNextSolver,
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     to_chalk_trait_id,
 };
 
@@ -36,7 +39,9 @@ impl<'db> InferenceContext<'db> {
 
         self.add_required_obligations_for_value_path(generic_def, &substs);
 
-        let ty = self.db.value_ty(value_def)?.substitute(Interner, &substs);
+        let interner = DbInterner::new_with(self.db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = self.db.value_ty(value_def)?.instantiate(interner, args).to_chalk(interner);
         let ty = self.process_remote_user_written_ty(ty);
         Some(ty)
     }
@@ -69,8 +74,11 @@ impl<'db> InferenceContext<'db> {
             }
             ValueNs::ImplSelf(impl_id) => {
                 let generics = crate::generics::generics(self.db, impl_id.into());
+                let interner = DbInterner::new_with(self.db, None, None);
                 let substs = generics.placeholder_subst(self.db);
-                let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
                 return if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
                     Some(ValuePathResolution::GenericDef(
                         struct_id.into(),
@@ -89,9 +97,9 @@ impl<'db> InferenceContext<'db> {
 
         let generic_def = value_def.to_generic_def_id(self.db);
         if let GenericDefId::StaticId(_) = generic_def {
+            let interner = DbInterner::new_with(self.db, None, None);
             // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type.
-            let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
-            stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",);
+            let ty = self.db.value_ty(value_def)?.skip_binder().to_chalk(interner);
             return Some(ValuePathResolution::NonGeneric(ty));
         };
 
@@ -354,10 +362,13 @@ impl<'db> InferenceContext<'db> {
         };
         let substs = match container {
             ItemContainerId::ImplId(impl_id) => {
+                let interner = DbInterner::new_with(self.db, None, None);
                 let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
                     .fill_with_inference_vars(&mut self.table)
                     .build();
-                let impl_self_ty = self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
+                let args: crate::next_solver::GenericArgs<'_> = impl_substs.to_nextsolver(interner);
+                let impl_self_ty =
+                    self.db.impl_self_ty(impl_id).instantiate(interner, args).to_chalk(interner);
                 self.unify(&impl_self_ty, &ty);
                 impl_substs
             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 1687857ae1a..108cf5b1a2b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -3,47 +3,42 @@
 use std::fmt;
 
 use chalk_ir::{
-    CanonicalVarKind, FloatTy, IntTy, TyVariableKind, cast::Cast, fold::TypeFoldable,
-    interner::HasInterner,
+    CanonicalVarKind, TyVariableKind, cast::Cast, fold::TypeFoldable, interner::HasInterner,
 };
 use either::Either;
 use hir_def::{AdtId, lang_item::LangItem};
 use hir_expand::name::Name;
 use intern::sym;
 use rustc_hash::{FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::Ty as _;
 use rustc_type_ir::{
-    FloatVid, IntVid, TyVid, TypeVisitableExt,
-    inherent::{IntoKind, Span, Term as _},
+    TyVid, TypeVisitableExt, UpcastFrom,
+    inherent::{IntoKind, Span, Term as _, Ty as _},
     relate::{Relate, solver_relating::RelateExt},
-    solve::{Certainty, GoalSource, NoSolution},
+    solve::{Certainty, GoalSource},
 };
 use smallvec::SmallVec;
 use triomphe::Arc;
 
 use super::{InferResult, InferenceContext, TypeError};
-use crate::next_solver::ErrorGuaranteed;
 use crate::{
     AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg, GenericArgData,
-    Goal, GoalData, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind,
-    ProjectionTy, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
-    VariableKind, WhereClause,
+    InferenceVar, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, TraitEnvironment, Ty,
+    TyExt, TyKind, VariableKind,
     consteval::unknown_const,
     db::HirDatabase,
     fold_generic_args, fold_tys_and_consts,
-    next_solver::infer::InferOk,
     next_solver::{
-        self, ClauseKind, DbInterner, ParamEnv, Predicate, PredicateKind, SolverDefIds, Term,
+        self, ClauseKind, DbInterner, ErrorGuaranteed, Predicate, PredicateKind, SolverDefIds,
+        Term, TraitRef,
         fulfill::FulfillmentCtxt,
         infer::{
-            DbInternerInferExt, InferCtxt,
+            DbInternerInferExt, InferCtxt, InferOk,
             snapshot::CombinedSnapshot,
             traits::{Obligation, ObligationCause},
         },
         inspect::{InspectConfig, InspectGoal, ProofTreeVisitor},
         mapping::{ChalkToNextSolver, NextSolverToChalk},
     },
-    to_chalk_trait_id,
     traits::{
         FnTrait, NextTraitSolveResult, next_trait_solve_canonical_in_ctxt, next_trait_solve_in_ctxt,
     },
@@ -125,7 +120,7 @@ impl<'a, 'db> ProofTreeVisitor<'db> for NestedObligationsForSelfTy<'a, 'db> {
 /// unresolved goal `T = U`.
 pub fn could_unify(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> bool {
     unify(db, env, tys).is_some()
@@ -137,7 +132,7 @@ pub fn could_unify(
 /// them. For example `Option<T>` and `Option<U>` do not unify as we cannot show that `T = U`
 pub fn could_unify_deeply(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> bool {
     let mut table = InferenceTable::new(db, env);
@@ -147,7 +142,6 @@ pub fn could_unify_deeply(
     let ty1_with_vars = table.normalize_associated_types_in(ty1_with_vars);
     let ty2_with_vars = table.normalize_associated_types_in(ty2_with_vars);
     table.select_obligations_where_possible();
-    table.propagate_diverging_flag();
     let ty1_with_vars = table.resolve_completely(ty1_with_vars);
     let ty2_with_vars = table.resolve_completely(ty2_with_vars);
     table.unify_deeply(&ty1_with_vars, &ty2_with_vars)
@@ -155,7 +149,7 @@ pub fn could_unify_deeply(
 
 pub(crate) fn unify(
     db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
     tys: &Canonical<(Ty, Ty)>,
 ) -> Option<Substitution> {
     let mut table = InferenceTable::new(db, env);
@@ -174,13 +168,19 @@ pub(crate) fn unify(
             GenericArgData::Const(c) => c.inference_var(Interner),
         } == Some(iv))
     };
-    let fallback = |iv, kind, default, binder| match kind {
-        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Lifetime => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner)),
-        chalk_ir::VariableKind::Const(ty) => find_var(iv)
-            .map_or(default, |i| BoundVar::new(binder, i).to_const(Interner, ty).cast(Interner)),
+    let fallback = |iv, kind, binder| match kind {
+        chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or_else(
+            || TyKind::Error.intern(Interner).cast(Interner),
+            |i| BoundVar::new(binder, i).to_ty(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Lifetime => find_var(iv).map_or_else(
+            || crate::error_lifetime().cast(Interner),
+            |i| BoundVar::new(binder, i).to_lifetime(Interner).cast(Interner),
+        ),
+        chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or_else(
+            || crate::unknown_const(ty.clone()).cast(Interner),
+            |i| BoundVar::new(binder, i).to_const(Interner, ty.clone()).cast(Interner),
+        ),
     };
     Some(Substitution::from_iter(
         Interner,
@@ -216,22 +216,20 @@ bitflags::bitflags! {
 pub(crate) struct InferenceTable<'db> {
     pub(crate) db: &'db dyn HirDatabase,
     pub(crate) interner: DbInterner<'db>,
-    pub(crate) trait_env: Arc<TraitEnvironment>,
-    pub(crate) param_env: ParamEnv<'db>,
+    pub(crate) trait_env: Arc<TraitEnvironment<'db>>,
     pub(crate) tait_coercion_table: Option<FxHashMap<OpaqueTyId, Ty>>,
     pub(crate) infer_ctxt: InferCtxt<'db>,
-    diverging_tys: FxHashSet<Ty>,
     pub(super) fulfillment_cx: FulfillmentCtxt<'db>,
+    pub(super) diverging_type_vars: FxHashSet<crate::next_solver::Ty<'db>>,
 }
 
 pub(crate) struct InferenceTableSnapshot<'db> {
     ctxt_snapshot: CombinedSnapshot,
     obligations: FulfillmentCtxt<'db>,
-    diverging_tys: FxHashSet<Ty>,
 }
 
 impl<'db> InferenceTable<'db> {
-    pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
+    pub(crate) fn new(db: &'db dyn HirDatabase, trait_env: Arc<TraitEnvironment<'db>>) -> Self {
         let interner = DbInterner::new_with(db, Some(trait_env.krate), trait_env.block);
         let infer_ctxt = interner.infer_ctxt().build(rustc_type_ir::TypingMode::Analysis {
             defining_opaque_types_and_generators: SolverDefIds::new_from_iter(interner, []),
@@ -239,12 +237,11 @@ impl<'db> InferenceTable<'db> {
         InferenceTable {
             db,
             interner,
-            param_env: trait_env.env.to_nextsolver(interner),
             trait_env,
             tait_coercion_table: None,
             fulfillment_cx: FulfillmentCtxt::new(&infer_ctxt),
             infer_ctxt,
-            diverging_tys: FxHashSet::default(),
+            diverging_type_vars: FxHashSet::default(),
         }
     }
 
@@ -327,74 +324,8 @@ impl<'db> InferenceTable<'db> {
         }
     }
 
-    /// Chalk doesn't know about the `diverging` flag, so when it unifies two
-    /// type variables of which one is diverging, the chosen root might not be
-    /// diverging and we have no way of marking it as such at that time. This
-    /// function goes through all type variables and make sure their root is
-    /// marked as diverging if necessary, so that resolving them gives the right
-    /// result.
-    pub(super) fn propagate_diverging_flag(&mut self) {
-        let mut new_tys = FxHashSet::default();
-        for ty in self.diverging_tys.iter() {
-            match ty.kind(Interner) {
-                TyKind::InferenceVar(var, kind) => match kind {
-                    TyVariableKind::General => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt.root_var(TyVid::from_u32(var.index())).as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                    TyVariableKind::Integer => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt
-                                .inner
-                                .borrow_mut()
-                                .int_unification_table()
-                                .find(IntVid::from_usize(var.index() as usize))
-                                .as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                    TyVariableKind::Float => {
-                        let root = InferenceVar::from(
-                            self.infer_ctxt
-                                .inner
-                                .borrow_mut()
-                                .float_unification_table()
-                                .find(FloatVid::from_usize(var.index() as usize))
-                                .as_u32(),
-                        );
-                        if root.index() != var.index() {
-                            new_tys.insert(TyKind::InferenceVar(root, *kind).intern(Interner));
-                        }
-                    }
-                },
-                _ => {}
-            }
-        }
-        self.diverging_tys.extend(new_tys);
-    }
-
-    pub(super) fn set_diverging(&mut self, iv: InferenceVar, kind: TyVariableKind) {
-        self.diverging_tys.insert(TyKind::InferenceVar(iv, kind).intern(Interner));
-    }
-
-    fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
-        let is_diverging =
-            self.diverging_tys.contains(&TyKind::InferenceVar(iv, kind).intern(Interner));
-        if is_diverging {
-            return TyKind::Never.intern(Interner);
-        }
-        match kind {
-            TyVariableKind::General => TyKind::Error,
-            TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
-            TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
-        }
-        .intern(Interner)
+    pub(super) fn set_diverging(&mut self, ty: crate::next_solver::Ty<'db>) {
+        self.diverging_type_vars.insert(ty);
     }
 
     pub(crate) fn canonicalize<T>(&mut self, t: T) -> rustc_type_ir::Canonical<DbInterner<'db>, T>
@@ -430,7 +361,7 @@ impl<'db> InferenceTable<'db> {
     {
         let ty = self.resolve_vars_with_obligations(ty);
         self.infer_ctxt
-            .at(&ObligationCause::new(), self.param_env)
+            .at(&ObligationCause::new(), self.trait_env.env)
             .deeply_normalize(ty.clone())
             .unwrap_or(ty)
     }
@@ -535,7 +466,7 @@ impl<'db> InferenceTable<'db> {
 
         let ty = var.to_ty(Interner, kind);
         if diverging {
-            self.diverging_tys.insert(ty.clone());
+            self.diverging_type_vars.insert(ty.to_nextsolver(self.interner));
         }
         ty
     }
@@ -579,7 +510,7 @@ impl<'db> InferenceTable<'db> {
     pub(crate) fn resolve_with_fallback<T>(
         &mut self,
         t: T,
-        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     ) -> T
     where
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
@@ -621,7 +552,7 @@ impl<'db> InferenceTable<'db> {
     fn resolve_with_fallback_inner<T>(
         &mut self,
         t: T,
-        fallback: &dyn Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        fallback: &dyn Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     ) -> T
     where
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
@@ -638,53 +569,15 @@ impl<'db> InferenceTable<'db> {
         T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + ChalkToNextSolver<'db, U>,
         U: NextSolverToChalk<'db, T> + rustc_type_ir::TypeFoldable<DbInterner<'db>>,
     {
-        let t = self.resolve_with_fallback(t, &|_, _, d, _| d);
-        let t = self.normalize_associated_types_in(t);
-        // let t = self.resolve_opaque_tys_in(t);
-        // Resolve again, because maybe normalization inserted infer vars.
-        self.resolve_with_fallback(t, &|_, _, d, _| d)
-    }
+        let value = t.to_nextsolver(self.interner);
+        let value = self.infer_ctxt.resolve_vars_if_possible(value);
 
-    /// Apply a fallback to unresolved scalar types. Integer type variables and float type
-    /// variables are replaced with i32 and f64, respectively.
-    ///
-    /// This method is only intended to be called just before returning inference results (i.e. in
-    /// `InferenceContext::resolve_all()`).
-    ///
-    /// FIXME: This method currently doesn't apply fallback to unconstrained general type variables
-    /// whereas rustc replaces them with `()` or `!`.
-    pub(super) fn fallback_if_possible(&mut self) {
-        let int_fallback = TyKind::Scalar(Scalar::Int(IntTy::I32)).intern(Interner);
-        let float_fallback = TyKind::Scalar(Scalar::Float(FloatTy::F64)).intern(Interner);
-
-        let int_vars = self.infer_ctxt.inner.borrow_mut().int_unification_table().len();
-        for v in 0..int_vars {
-            let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Integer);
-            let maybe_resolved = self.resolve_ty_shallow(&var);
-            if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
-                // I don't think we can ever unify these vars with float vars, but keep this here for now
-                let fallback = match kind {
-                    TyVariableKind::Integer => &int_fallback,
-                    TyVariableKind::Float => &float_fallback,
-                    TyVariableKind::General => unreachable!(),
-                };
-                self.unify(&var, fallback);
-            }
-        }
-        let float_vars = self.infer_ctxt.inner.borrow_mut().float_unification_table().len();
-        for v in 0..float_vars {
-            let var = InferenceVar::from(v as u32).to_ty(Interner, TyVariableKind::Float);
-            let maybe_resolved = self.resolve_ty_shallow(&var);
-            if let TyKind::InferenceVar(_, kind) = maybe_resolved.kind(Interner) {
-                // I don't think we can ever unify these vars with float vars, but keep this here for now
-                let fallback = match kind {
-                    TyVariableKind::Integer => &int_fallback,
-                    TyVariableKind::Float => &float_fallback,
-                    TyVariableKind::General => unreachable!(),
-                };
-                self.unify(&var, fallback);
-            }
-        }
+        let mut goals = vec![];
+        let value = value.fold_with(&mut resolve_completely::Resolver::new(self, true, &mut goals));
+
+        // FIXME(next-solver): Handle `goals`.
+
+        value.to_chalk(self.interner)
     }
 
     /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
@@ -745,7 +638,7 @@ impl<'db> InferenceTable<'db> {
     ) -> InferResult<'db, ()> {
         let variance = rustc_type_ir::Variance::Invariant;
         let span = crate::next_solver::Span::dummy();
-        match self.infer_ctxt.relate(self.param_env, lhs, variance, rhs, span) {
+        match self.infer_ctxt.relate(self.trait_env.env, lhs, variance, rhs, span) {
             Ok(goals) => Ok(crate::infer::InferOk { goals, value: () }),
             Err(_) => Err(TypeError),
         }
@@ -786,7 +679,7 @@ impl<'db> InferenceTable<'db> {
     }
 
     pub(crate) fn structurally_resolve_type(&mut self, ty: &Ty) -> Ty {
-        if let TyKind::Alias(..) = ty.kind(Interner) {
+        if let TyKind::Alias(chalk_ir::AliasTy::Projection(..)) = ty.kind(Interner) {
             self.structurally_normalize_ty(ty)
         } else {
             self.resolve_vars_with_obligations(ty.to_nextsolver(self.interner))
@@ -802,7 +695,7 @@ impl<'db> InferenceTable<'db> {
 
     fn structurally_normalize_term(&mut self, term: Term<'db>) -> Term<'db> {
         self.infer_ctxt
-            .at(&ObligationCause::new(), self.param_env)
+            .at(&ObligationCause::new(), self.trait_env.env)
             .structurally_normalize_term(term, &mut self.fulfillment_cx)
             .unwrap_or(term)
     }
@@ -822,7 +715,7 @@ impl<'db> InferenceTable<'db> {
             // in a reentrant borrow, causing an ICE.
             let result = self
                 .infer_ctxt
-                .at(&ObligationCause::misc(), self.param_env)
+                .at(&ObligationCause::misc(), self.trait_env.env)
                 .structurally_normalize_ty(ty, &mut self.fulfillment_cx);
             match result {
                 Ok(normalized_ty) => normalized_ty,
@@ -835,15 +728,13 @@ impl<'db> InferenceTable<'db> {
 
     pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot<'db> {
         let ctxt_snapshot = self.infer_ctxt.start_snapshot();
-        let diverging_tys = self.diverging_tys.clone();
         let obligations = self.fulfillment_cx.clone();
-        InferenceTableSnapshot { ctxt_snapshot, diverging_tys, obligations }
+        InferenceTableSnapshot { ctxt_snapshot, obligations }
     }
 
     #[tracing::instrument(skip_all)]
     pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot<'db>) {
         self.infer_ctxt.rollback_to(snapshot.ctxt_snapshot);
-        self.diverging_tys = snapshot.diverging_tys;
         self.fulfillment_cx = snapshot.obligations;
     }
 
@@ -877,26 +768,15 @@ impl<'db> InferenceTable<'db> {
     /// whether a trait *might* be implemented before deciding to 'lock in' the
     /// choice (during e.g. method resolution or deref).
     #[tracing::instrument(level = "debug", skip(self))]
-    pub(crate) fn try_obligation(&mut self, goal: Goal) -> NextTraitSolveResult {
-        let in_env = InEnvironment::new(&self.trait_env.env, goal);
-        let canonicalized = self.canonicalize(in_env.to_nextsolver(self.interner));
+    pub(crate) fn try_obligation(&mut self, predicate: Predicate<'db>) -> NextTraitSolveResult {
+        let goal = next_solver::Goal { param_env: self.trait_env.env, predicate };
+        let canonicalized = self.canonicalize(goal);
 
         next_trait_solve_canonical_in_ctxt(&self.infer_ctxt, canonicalized)
     }
 
-    #[tracing::instrument(level = "debug", skip(self))]
-    pub(crate) fn solve_obligation(&mut self, goal: Goal) -> Result<Certainty, NoSolution> {
-        let goal = InEnvironment::new(&self.trait_env.env, goal);
-        let goal = goal.to_nextsolver(self.interner);
-        let result = next_trait_solve_in_ctxt(&self.infer_ctxt, goal);
-        result.map(|m| m.1)
-    }
-
     pub(crate) fn register_obligation(&mut self, predicate: Predicate<'db>) {
-        let goal = next_solver::Goal {
-            param_env: self.trait_env.env.to_nextsolver(self.interner),
-            predicate,
-        };
+        let goal = next_solver::Goal { param_env: self.trait_env.env, predicate };
         self.register_obligation_in_env(goal)
     }
 
@@ -984,7 +864,7 @@ impl<'db> InferenceTable<'db> {
         &mut self,
         ty: &Ty,
         num_args: usize,
-    ) -> Option<(FnTrait, Vec<crate::next_solver::Ty<'db>>, crate::next_solver::Ty<'db>)> {
+    ) -> Option<(FnTrait, Vec<next_solver::Ty<'db>>, next_solver::Ty<'db>)> {
         for (fn_trait_name, output_assoc_name, subtraits) in [
             (FnTrait::FnOnce, sym::Output, &[FnTrait::Fn, FnTrait::FnMut][..]),
             (FnTrait::AsyncFnMut, sym::CallRefFuture, &[FnTrait::AsyncFn]),
@@ -997,42 +877,34 @@ impl<'db> InferenceTable<'db> {
                 trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?;
 
             let mut arg_tys = Vec::with_capacity(num_args);
-            let arg_ty = TyBuilder::tuple(num_args)
-                .fill(|it| {
-                    let arg = match it {
-                        ParamKind::Type => self.new_type_var(),
-                        ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"),
-                        ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
-                    };
-                    arg_tys.push(arg.to_nextsolver(self.interner));
-                    arg.cast(Interner)
+            let arg_ty = next_solver::Ty::new_tup_from_iter(
+                self.interner,
+                std::iter::repeat_with(|| {
+                    let ty = self.next_ty_var();
+                    arg_tys.push(ty);
+                    ty
                 })
-                .build();
-
-            let b = TyBuilder::trait_ref(self.db, fn_trait);
-            if b.remaining() != 2 {
-                return None;
-            }
-            let mut trait_ref = b.push(ty.clone()).push(arg_ty).build();
-
-            let projection = TyBuilder::assoc_type_projection(
-                self.db,
-                output_assoc_type,
-                Some(trait_ref.substitution.clone()),
-            )
-            .fill_with_unknown()
-            .build();
-
-            let goal: Goal = trait_ref.clone().cast(Interner);
-            if !self.try_obligation(goal.clone()).no_solution() {
-                self.register_obligation(goal.to_nextsolver(self.interner));
-                let return_ty =
-                    self.normalize_projection_ty(projection).to_nextsolver(self.interner);
+                .take(num_args),
+            );
+            let args = [ty.to_nextsolver(self.interner), arg_ty];
+            let trait_ref = crate::next_solver::TraitRef::new(self.interner, fn_trait.into(), args);
+
+            let projection = crate::next_solver::Ty::new_alias(
+                self.interner,
+                rustc_type_ir::AliasTyKind::Projection,
+                crate::next_solver::AliasTy::new(self.interner, output_assoc_type.into(), args),
+            );
+
+            let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner);
+            if !self.try_obligation(pred).no_solution() {
+                self.register_obligation(pred);
+                let return_ty = self.normalize_alias_ty(projection);
                 for &fn_x in subtraits {
                     let fn_x_trait = fn_x.get_id(self.db, krate)?;
-                    trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
-                    let goal = trait_ref.clone().cast(Interner);
-                    if !self.try_obligation(goal).no_solution() {
+                    let trait_ref =
+                        crate::next_solver::TraitRef::new(self.interner, fn_x_trait.into(), args);
+                    let pred = crate::next_solver::Predicate::upcast_from(trait_ref, self.interner);
+                    if !self.try_obligation(pred).no_solution() {
                         return Some((fn_x, arg_tys, return_ty));
                     }
                 }
@@ -1171,12 +1043,11 @@ impl<'db> InferenceTable<'db> {
         let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else {
             return false;
         };
-        let sized_pred = WhereClause::Implemented(TraitRef {
-            trait_id: to_chalk_trait_id(sized),
-            substitution: Substitution::from1(Interner, ty),
-        });
-        let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner);
-        self.try_obligation(goal).certain()
+        let sized_pred = Predicate::upcast_from(
+            TraitRef::new(self.interner, sized.into(), [ty.to_nextsolver(self.interner)]),
+            self.interner,
+        );
+        self.try_obligation(sized_pred).certain()
     }
 }
 
@@ -1192,14 +1063,10 @@ impl fmt::Debug for InferenceTable<'_> {
 mod resolve {
     use super::InferenceTable;
     use crate::{
-        ConcreteConst, Const, ConstData, ConstScalar, ConstValue, DebruijnIndex, GenericArg,
-        InferenceVar, Interner, Lifetime, Ty, TyVariableKind, VariableKind,
-        next_solver::mapping::NextSolverToChalk,
-    };
-    use chalk_ir::{
-        cast::Cast,
-        fold::{TypeFoldable, TypeFolder},
+        Const, DebruijnIndex, GenericArg, InferenceVar, Interner, Lifetime, Ty, TyVariableKind,
+        VariableKind, next_solver::mapping::NextSolverToChalk,
     };
+    use chalk_ir::fold::{TypeFoldable, TypeFolder};
     use rustc_type_ir::{FloatVid, IntVid, TyVid};
 
     #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -1213,7 +1080,7 @@ mod resolve {
     pub(super) struct Resolver<
         'a,
         'b,
-        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     > {
         pub(super) table: &'a mut InferenceTable<'b>,
         pub(super) var_stack: &'a mut Vec<(InferenceVar, VarKind)>,
@@ -1221,7 +1088,7 @@ mod resolve {
     }
     impl<F> TypeFolder<Interner> for Resolver<'_, '_, F>
     where
-        F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
+        F: Fn(InferenceVar, VariableKind, DebruijnIndex) -> GenericArg,
     {
         fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
             self
@@ -1243,8 +1110,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1256,8 +1122,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1273,8 +1138,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1286,8 +1150,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1303,8 +1166,7 @@ mod resolve {
                     let var = InferenceVar::from(vid.as_u32());
                     if self.var_stack.contains(&(var, VarKind::Ty(kind))) {
                         // recursive type
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        return (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        return (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone();
                     }
@@ -1316,8 +1178,7 @@ mod resolve {
                         self.var_stack.pop();
                         result
                     } else {
-                        let default = self.table.fallback_value(var, kind).cast(Interner);
-                        (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
+                        (self.fallback)(var, VariableKind::Ty(kind), outer_binder)
                             .assert_ty_ref(Interner)
                             .clone()
                     }
@@ -1336,15 +1197,9 @@ mod resolve {
                 .infer_ctxt
                 .root_const_var(rustc_type_ir::ConstVid::from_u32(var.index()));
             let var = InferenceVar::from(vid.as_u32());
-            let default = ConstData {
-                ty: ty.clone(),
-                value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
-            }
-            .intern(Interner)
-            .cast(Interner);
             if self.var_stack.contains(&(var, VarKind::Const)) {
                 // recursive
-                return (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+                return (self.fallback)(var, VariableKind::Const(ty), outer_binder)
                     .assert_const_ref(Interner)
                     .clone();
             }
@@ -1356,7 +1211,7 @@ mod resolve {
                 self.var_stack.pop();
                 result
             } else {
-                (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
+                (self.fallback)(var, VariableKind::Const(ty), outer_binder)
                     .assert_const_ref(Interner)
                     .clone()
             }
@@ -1375,3 +1230,124 @@ mod resolve {
         }
     }
 }
+
+mod resolve_completely {
+    use rustc_type_ir::{
+        DebruijnIndex, Flags, TypeFolder, TypeSuperFoldable,
+        inherent::{Const as _, Ty as _},
+    };
+
+    use crate::next_solver::Region;
+    use crate::{
+        infer::unify::InferenceTable,
+        next_solver::{
+            Const, DbInterner, ErrorGuaranteed, Goal, Predicate, Term, Ty,
+            infer::traits::ObligationCause,
+            normalize::deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals,
+        },
+    };
+
+    pub(super) struct Resolver<'a, 'db> {
+        ctx: &'a mut InferenceTable<'db>,
+        /// Whether we should normalize, disabled when resolving predicates.
+        should_normalize: bool,
+        nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
+    }
+
+    impl<'a, 'db> Resolver<'a, 'db> {
+        pub(super) fn new(
+            ctx: &'a mut InferenceTable<'db>,
+            should_normalize: bool,
+            nested_goals: &'a mut Vec<Goal<'db, Predicate<'db>>>,
+        ) -> Resolver<'a, 'db> {
+            Resolver { ctx, nested_goals, should_normalize }
+        }
+
+        fn handle_term<T>(
+            &mut self,
+            value: T,
+            outer_exclusive_binder: impl FnOnce(T) -> DebruijnIndex,
+        ) -> T
+        where
+            T: Into<Term<'db>> + TypeSuperFoldable<DbInterner<'db>> + Copy,
+        {
+            let value = if self.should_normalize {
+                let cause = ObligationCause::new();
+                let at = self.ctx.infer_ctxt.at(&cause, self.ctx.trait_env.env);
+                let universes = vec![None; outer_exclusive_binder(value).as_usize()];
+                match deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals(
+                    at, value, universes,
+                ) {
+                    Ok((value, goals)) => {
+                        self.nested_goals.extend(goals);
+                        value
+                    }
+                    Err(_errors) => {
+                        // FIXME: Report the error.
+                        value
+                    }
+                }
+            } else {
+                value
+            };
+
+            value.fold_with(&mut ReplaceInferWithError { interner: self.ctx.interner })
+        }
+    }
+
+    impl<'cx, 'db> TypeFolder<DbInterner<'db>> for Resolver<'cx, 'db> {
+        fn cx(&self) -> DbInterner<'db> {
+            self.ctx.interner
+        }
+
+        fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+            if r.is_var() { Region::error(self.ctx.interner) } else { r }
+        }
+
+        fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
+            self.handle_term(ty, |it| it.outer_exclusive_binder())
+        }
+
+        fn fold_const(&mut self, ct: Const<'db>) -> Const<'db> {
+            self.handle_term(ct, |it| it.outer_exclusive_binder())
+        }
+
+        fn fold_predicate(&mut self, predicate: Predicate<'db>) -> Predicate<'db> {
+            assert!(
+                !self.should_normalize,
+                "normalizing predicates in writeback is not generally sound"
+            );
+            predicate.super_fold_with(self)
+        }
+    }
+
+    struct ReplaceInferWithError<'db> {
+        interner: DbInterner<'db>,
+    }
+
+    impl<'db> TypeFolder<DbInterner<'db>> for ReplaceInferWithError<'db> {
+        fn cx(&self) -> DbInterner<'db> {
+            self.interner
+        }
+
+        fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
+            if t.is_infer() {
+                Ty::new_error(self.interner, ErrorGuaranteed)
+            } else {
+                t.super_fold_with(self)
+            }
+        }
+
+        fn fold_const(&mut self, c: Const<'db>) -> Const<'db> {
+            if c.is_ct_infer() {
+                Const::new_error(self.interner, ErrorGuaranteed)
+            } else {
+                c.super_fold_with(self)
+            }
+        }
+
+        fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
+            if r.is_var() { Region::error(self.interner) } else { r }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index b16b6a11784..bdebe41b299 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -20,7 +20,7 @@ pub(crate) fn is_ty_uninhabited_from(
     db: &dyn HirDatabase,
     ty: &Ty,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
 ) -> bool {
     let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
     let mut uninhabited_from =
@@ -36,7 +36,7 @@ pub(crate) fn is_enum_variant_uninhabited_from(
     variant: EnumVariantId,
     subst: &Substitution,
     target_mod: ModuleId,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'_>>,
 ) -> bool {
     let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
 
@@ -52,7 +52,7 @@ struct UninhabitedFrom<'a> {
     // guard for preventing stack overflow in non trivial non terminating types
     max_depth: usize,
     db: &'a dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'a>>,
 }
 
 const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index f21673c732e..4071b9a1d5e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -132,7 +132,7 @@ fn layout_of_simd_ty<'db>(
     id: StructId,
     repr_packed: bool,
     args: &GenericArgs<'db>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     dl: &TargetDataLayout,
 ) -> Result<Arc<Layout>, LayoutError> {
     // Supported SIMD vectors are homogeneous ADTs with exactly one array field:
@@ -160,7 +160,7 @@ fn layout_of_simd_ty<'db>(
 pub fn layout_of_ty_query<'db>(
     db: &'db dyn HirDatabase,
     ty: Ty<'db>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     let krate = trait_env.krate;
     let interner = DbInterner::new_with(db, Some(krate), trait_env.block);
@@ -371,7 +371,7 @@ pub fn layout_of_ty_query<'db>(
 pub(crate) fn layout_of_ty_cycle_result<'db>(
     _: &dyn HirDatabase,
     _: Ty<'db>,
-    _: Arc<TraitEnvironment>,
+    _: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     Err(LayoutError::RecursiveTypeWithoutIndirection)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 9a746ca8885..a8f04bf8c13 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -23,7 +23,7 @@ pub fn layout_of_adt_query<'db>(
     db: &'db dyn HirDatabase,
     def: AdtId,
     args: GenericArgs<'db>,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     let krate = trait_env.krate;
     let Ok(target) = db.target_data_layout(krate) else {
@@ -99,7 +99,7 @@ pub(crate) fn layout_of_adt_cycle_result<'db>(
     _: &'db dyn HirDatabase,
     _def: AdtId,
     _args: GenericArgs<'db>,
-    _trait_env: Arc<TraitEnvironment>,
+    _trait_env: Arc<TraitEnvironment<'db>>,
 ) -> Result<Arc<Layout>, LayoutError> {
     Err(LayoutError::RecursiveTypeWithoutIndirection)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 8be5eaca63b..275ad841f4b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -1,18 +1,17 @@
 use base_db::target::TargetData;
-use chalk_ir::{AdtId, TyKind};
 use either::Either;
 use hir_def::db::DefDatabase;
 use project_model::{Sysroot, toolchain_info::QueryConfig};
 use rustc_hash::FxHashMap;
+use rustc_type_ir::inherent::{GenericArgs as _, Ty as _};
 use syntax::ToSmolStr;
 use test_fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{
-    Interner, Substitution,
     db::HirDatabase,
     layout::{Layout, LayoutError},
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
+    next_solver::{AdtDef, DbInterner, GenericArgs, mapping::ChalkToNextSolver},
     setup_tracing,
     test_db::TestDB,
 };
@@ -80,18 +79,18 @@ fn eval_goal(
             Some(adt_or_type_alias_id)
         })
         .unwrap();
-    let goal_ty = match adt_or_type_alias_id {
-        Either::Left(adt_id) => {
-            TyKind::Adt(AdtId(adt_id), Substitution::empty(Interner)).intern(Interner)
-        }
-        Either::Right(ty_id) => {
-            db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner))
-        }
-    };
     salsa::attach(&db, || {
         let interner = DbInterner::new_with(&db, None, None);
+        let goal_ty = match adt_or_type_alias_id {
+            Either::Left(adt_id) => crate::next_solver::Ty::new_adt(
+                interner,
+                AdtDef::new(adt_id, interner),
+                GenericArgs::identity_for_item(interner, adt_id.into()),
+            ),
+            Either::Right(ty_id) => db.ty(ty_id.into()).instantiate_identity(),
+        };
         db.layout_of_ty(
-            goal_ty.to_nextsolver(interner),
+            goal_ty,
             db.trait_environment(match adt_or_type_alias_id {
                 Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
                 Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 2e59a488e67..281cf6b2d4b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -72,7 +72,10 @@ use intern::{Symbol, sym};
 use la_arena::{Arena, Idx};
 use mir::{MirEvalError, VTableMap};
 use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
-use rustc_type_ir::inherent::SliceLike;
+use rustc_type_ir::{
+    UpcastFrom,
+    inherent::{SliceLike, Ty as _},
+};
 use syntax::ast::{ConstArg, make};
 use traits::FnTrait;
 use triomphe::Arc;
@@ -85,7 +88,7 @@ use crate::{
     infer::unify::InferenceTable,
     next_solver::{
         DbInterner,
-        mapping::{ChalkToNextSolver, convert_ty_for_result},
+        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
     },
 };
 
@@ -554,8 +557,10 @@ impl CallableSig {
 
     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
         let callable_def = ToChalk::from_chalk(db, def);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
         let sig = db.callable_item_signature(callable_def);
-        sig.substitute(Interner, substs)
+        sig.instantiate(interner, args).skip_binder().to_chalk(interner)
     }
     pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
         CallableSig {
@@ -916,10 +921,10 @@ where
     Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
 }
 
-pub fn callable_sig_from_fn_trait(
+pub fn callable_sig_from_fn_trait<'db>(
     self_ty: &Ty,
-    trait_env: Arc<TraitEnvironment>,
-    db: &dyn HirDatabase,
+    trait_env: Arc<TraitEnvironment<'db>>,
+    db: &'db dyn HirDatabase,
 ) -> Option<(FnTrait, CallableSig)> {
     let krate = trait_env.krate;
     let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
@@ -936,26 +941,32 @@ pub fn callable_sig_from_fn_trait(
     // Register two obligations:
     // - Self: FnOnce<?args_ty>
     // - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
-    let args_ty = table.new_type_var();
-    let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
-    let projection = TyBuilder::assoc_type_projection(
-        db,
-        output_assoc_type,
-        Some(trait_ref.substitution.clone()),
-    )
-    .build();
-
-    let goal: Goal = trait_ref.clone().cast(Interner);
-    let pred = goal.to_nextsolver(table.interner);
-    if !table.try_obligation(goal).no_solution() {
+    let args_ty = table.next_ty_var();
+    let args = [self_ty.to_nextsolver(table.interner), args_ty];
+    let trait_ref = crate::next_solver::TraitRef::new(table.interner, fn_once_trait.into(), args);
+    let projection = crate::next_solver::Ty::new_alias(
+        table.interner,
+        rustc_type_ir::AliasTyKind::Projection,
+        crate::next_solver::AliasTy::new(table.interner, output_assoc_type.into(), args),
+    );
+
+    let pred = crate::next_solver::Predicate::upcast_from(trait_ref, table.interner);
+    if !table.try_obligation(pred).no_solution() {
         table.register_obligation(pred);
-        let return_ty = table.normalize_projection_ty(projection);
+        let return_ty = table.normalize_alias_ty(projection);
         for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
             let fn_x_trait = fn_x.get_id(db, krate)?;
-            trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
-            if !table.try_obligation(trait_ref.clone().cast(Interner)).no_solution() {
-                let ret_ty = table.resolve_completely(return_ty);
-                let args_ty = table.resolve_completely(args_ty);
+            let trait_ref =
+                crate::next_solver::TraitRef::new(table.interner, fn_x_trait.into(), args);
+            if !table
+                .try_obligation(crate::next_solver::Predicate::upcast_from(
+                    trait_ref,
+                    table.interner,
+                ))
+                .no_solution()
+            {
+                let ret_ty = table.resolve_completely(return_ty.to_chalk(table.interner));
+                let args_ty = table.resolve_completely(args_ty.to_chalk(table.interner));
                 let params = args_ty
                     .as_tuple()?
                     .iter(Interner)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 4d5172fd4f2..0c197b27034 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -24,19 +24,18 @@ use chalk_ir::{
 
 use either::Either;
 use hir_def::{
-    AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
-    FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId,
-    Lookup, StaticId, StructId, TypeAliasId, TypeOrConstParamId, UnionId, VariantId,
+    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
+    GenericParamId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TypeAliasId,
+    TypeOrConstParamId, UnionId, VariantId,
     builtin_type::BuiltinType,
     expr_store::{ExpressionStore, path::Path},
     hir::generics::{GenericParamDataRef, TypeOrConstParamData, WherePredicate},
-    item_tree::FieldsShape,
     lang_item::LangItem,
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
-    signatures::{FunctionSignature, TraitFlags, TypeAliasFlags},
+    signatures::{FunctionSignature, TraitFlags},
     type_ref::{
-        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier,
-        TraitRef as HirTraitRef, TypeBound, TypeRef, TypeRefId,
+        ConstRef, LifetimeRefId, LiteralConstRef, PathId, TraitBoundModifier, TypeBound, TypeRef,
+        TypeRefId,
     },
 };
 use hir_expand::name::Name;
@@ -46,11 +45,10 @@ use stdx::{impl_from, never};
 use triomphe::{Arc, ThinArc};
 
 use crate::{
-    AliasTy, Binders, BoundVar, CallableSig, Const, DebruijnIndex, DomainGoal, DynTy, FnAbi,
-    FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
-    LifetimeData, LifetimeOutlives, PolyFnSig, QuantifiedWhereClause, QuantifiedWhereClauses,
-    Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
-    all_super_traits,
+    AliasTy, Binders, BoundVar, Const, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst,
+    ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData, LifetimeOutlives,
+    QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitRef, TraitRefExt, Ty,
+    TyBuilder, TyKind, WhereClause, all_super_traits,
     consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
     db::HirDatabase,
     error_lifetime,
@@ -60,7 +58,11 @@ use crate::{
         path::{PathDiagnosticCallback, PathLoweringContext},
     },
     make_binders,
-    mapping::{ToChalk, from_chalk_trait_id, lt_to_placeholder_idx},
+    mapping::{from_chalk_trait_id, lt_to_placeholder_idx},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime, to_chalk_trait_id, to_placeholder_idx,
     utils::all_super_trait_refs,
     variable_kinds_from_iter,
@@ -567,14 +569,6 @@ impl<'a> TyLoweringContext<'a> {
         Some((ctx.lower_trait_ref_from_resolved_path(resolved, explicit_self_ty, false), ctx))
     }
 
-    fn lower_trait_ref(
-        &mut self,
-        trait_ref: &HirTraitRef,
-        explicit_self_ty: Ty,
-    ) -> Option<TraitRef> {
-        self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty).map(|it| it.0)
-    }
-
     /// When lowering predicates from parents (impl, traits) for children defs (fns, consts, types), `generics` should
     /// contain the `Generics` for the **child**, while `predicate_owner` should contain the `GenericDefId` of the
     /// **parent**. This is important so we generate the correct bound var/placeholder.
@@ -826,15 +820,6 @@ impl<'a> TyLoweringContext<'a> {
     }
 }
 
-/// Build the signature of a callable item (function, struct or enum variant).
-pub(crate) fn callable_item_signature_query(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
-    match def {
-        CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f),
-        CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s),
-        CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e),
-    }
-}
-
 fn named_associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     // If the type parameter is defined in an impl and we're in a method, there
@@ -862,21 +847,21 @@ fn named_associated_type_shorthand_candidates<R>(
         })
     };
 
+    let interner = DbInterner::new_with(db, None, None);
     match res {
         TypeNs::SelfType(impl_id) => {
-            // we're _in_ the impl -- the binders get added back later. Correct,
-            // but it would be nice to make this more explicit
-            let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
+            let trait_ref = db.impl_trait(impl_id)?;
 
             let impl_id_as_generic_def: GenericDefId = impl_id.into();
             if impl_id_as_generic_def != def {
                 let subst = TyBuilder::subst_for_def(db, impl_id, None)
                     .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                     .build();
-                let trait_ref = subst.apply(trait_ref, Interner);
+                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+                let trait_ref = trait_ref.instantiate(interner, args).to_chalk(interner);
                 search(trait_ref)
             } else {
-                search(trait_ref)
+                search(trait_ref.skip_binder().to_chalk(interner))
             }
         }
         TypeNs::GenericParam(param_id) => {
@@ -919,7 +904,7 @@ pub(crate) fn field_types_query(
     db: &dyn HirDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
-    db.field_types_with_diagnostics(variant_id).0
+    field_types_with_diagnostics_query(db, variant_id).0
 }
 
 /// Build the type of all specific fields of a struct or enum variant.
@@ -1086,102 +1071,6 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
     GenericPredicates(None)
 }
 
-pub(crate) fn trait_environment_for_body_query(
-    db: &dyn HirDatabase,
-    def: DefWithBodyId,
-) -> Arc<TraitEnvironment> {
-    let Some(def) = def.as_generic_def_id(db) else {
-        let krate = def.module(db).krate();
-        return TraitEnvironment::empty(krate);
-    };
-    db.trait_environment(def)
-}
-
-pub(crate) fn trait_environment_query(
-    db: &dyn HirDatabase,
-    def: GenericDefId,
-) -> Arc<TraitEnvironment> {
-    let generics = generics(db, def);
-    if generics.has_no_predicates() && generics.is_empty() {
-        return TraitEnvironment::empty(def.krate(db));
-    }
-
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        generics.store(),
-        def,
-        LifetimeElisionKind::AnonymousReportError,
-    )
-    .with_type_param_mode(ParamLoweringMode::Placeholder);
-    let mut traits_in_scope = Vec::new();
-    let mut clauses = Vec::new();
-    for maybe_parent_generics in
-        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
-    {
-        ctx.store = maybe_parent_generics.store();
-        for pred in maybe_parent_generics.where_predicates() {
-            for pred in ctx.lower_where_predicate(pred, false) {
-                if let WhereClause::Implemented(tr) = pred.skip_binders() {
-                    traits_in_scope
-                        .push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
-                }
-                let program_clause: Binders<DomainGoal> =
-                    pred.map(|pred| pred.into_from_env_goal(Interner).cast(Interner));
-                clauses.push(program_clause);
-            }
-        }
-    }
-
-    if let Some(trait_id) = def.assoc_trait_container(db) {
-        // add `Self: Trait<T1, T2, ...>` to the environment in trait
-        // function default implementations (and speculative code
-        // inside consts or type aliases)
-        cov_mark::hit!(trait_self_implements_self);
-        let substs = TyBuilder::placeholder_subst(db, trait_id);
-        let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
-        let pred = WhereClause::Implemented(trait_ref);
-        clauses.push(Binders::empty(
-            Interner,
-            pred.cast::<DomainGoal>(Interner).into_from_env_goal(Interner),
-        ));
-    }
-
-    let subst = generics.placeholder_subst(db);
-    if !subst.is_empty(Interner) {
-        let explicitly_unsized_tys = ctx.unsized_types;
-        if let Some(implicitly_sized_clauses) =
-            implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-        {
-            clauses.extend(implicitly_sized_clauses.map(|pred| {
-                Binders::empty(
-                    Interner,
-                    pred.into_from_env_goal(Interner).cast::<DomainGoal>(Interner),
-                )
-            }));
-        };
-    }
-
-    let clauses = chalk_ir::ProgramClauses::from_iter(
-        Interner,
-        clauses.into_iter().map(|g| {
-            chalk_ir::ProgramClause::new(
-                Interner,
-                chalk_ir::ProgramClauseData(g.map(|g| chalk_ir::ProgramClauseImplication {
-                    consequence: g,
-                    conditions: chalk_ir::Goals::empty(Interner),
-                    constraints: chalk_ir::Constraints::empty(Interner),
-                    priority: chalk_ir::ClausePriority::High,
-                })),
-            )
-        }),
-    );
-    let env = chalk_ir::Environment { clauses };
-
-    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates(Option<Arc<[Binders<QuantifiedWhereClause>]>>);
 
@@ -1410,208 +1299,6 @@ pub(crate) fn generic_defaults_with_diagnostics_cycle_result(
     (GenericDefaults(None), None)
 }
 
-fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
-    let data = db.function_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx_params = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::for_fn_params(&data),
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
-
-    let ret = match data.ret_type {
-        Some(ret_type) => {
-            let mut ctx_ret = TyLoweringContext::new(
-                db,
-                &resolver,
-                &data.store,
-                def.into(),
-                LifetimeElisionKind::for_fn_ret(),
-            )
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-            .with_type_param_mode(ParamLoweringMode::Variable);
-            ctx_ret.lower_ty(ret_type)
-        }
-        None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
-    };
-    let generics = generics(db, def.into());
-    let sig = CallableSig::from_params_and_return(
-        params,
-        ret,
-        data.is_varargs(),
-        if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
-        data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-    );
-    make_binders(db, &generics, sig)
-}
-
-/// Build the declared type of a function. This should not need to look at the
-/// function body.
-fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
-    let generics = generics(db, def.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    make_binders(
-        db,
-        &generics,
-        TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
-    )
-}
-
-/// Build the declared type of a const.
-fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
-    let data = db.const_signature(def);
-    let generics = generics(db, def.into());
-    let resolver = def.resolver(db);
-    let parent = def.loc(db).container;
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::for_const(parent),
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-
-    make_binders(db, &generics, ctx.lower_ty(data.type_ref))
-}
-
-/// Build the declared type of a static.
-fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
-    let data = db.static_signature(def);
-    let resolver = def.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &data.store,
-        def.into(),
-        LifetimeElisionKind::Elided(static_lifetime()),
-    );
-
-    Binders::empty(Interner, ctx.lower_ty(data.type_ref))
-}
-
-fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
-    let field_tys = db.field_types(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
-    let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
-    Binders::new(
-        binders,
-        CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
-    )
-}
-
-/// Build the type of a tuple struct constructor.
-fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Option<Binders<Ty>> {
-    let struct_data = def.fields(db);
-    match struct_data.shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, def.into())),
-        FieldsShape::Tuple => {
-            let generics = generics(db, AdtId::from(def).into());
-            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-            Some(make_binders(
-                db,
-                &generics,
-                TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
-            ))
-        }
-    }
-}
-
-fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -> PolyFnSig {
-    let field_tys = db.field_types(def.into());
-    let params = field_tys.iter().map(|(_, ty)| ty.skip_binders().clone());
-    let parent = def.lookup(db).parent;
-    let (ret, binders) = type_for_adt(db, parent.into()).into_value_and_skipped_binders();
-    Binders::new(
-        binders,
-        CallableSig::from_params_and_return(params, ret, false, Safety::Safe, FnAbi::RustCall),
-    )
-}
-
-/// Build the type of a tuple enum variant constructor.
-fn type_for_enum_variant_constructor(
-    db: &dyn HirDatabase,
-    def: EnumVariantId,
-) -> Option<Binders<Ty>> {
-    let e = def.lookup(db).parent;
-    match def.fields(db).shape {
-        FieldsShape::Record => None,
-        FieldsShape::Unit => Some(type_for_adt(db, e.into())),
-        FieldsShape::Tuple => {
-            let generics = generics(db, e.into());
-            let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-            Some(make_binders(
-                db,
-                &generics,
-                TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs)
-                    .intern(Interner),
-            ))
-        }
-    }
-}
-
-#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)]
-fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    type_for_adt(db, adt)
-}
-
-fn type_for_adt_cycle_result(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    let generics = generics(db, adt.into());
-    make_binders(db, &generics, TyKind::Error.intern(Interner))
-}
-
-fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
-    let generics = generics(db, adt.into());
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
-    make_binders(db, &generics, ty)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    t: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, t.into());
-    let type_alias_data = db.type_alias_signature(t);
-    let mut diags = None;
-    let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) {
-        TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
-    } else {
-        let resolver = t.resolver(db);
-        let alias = db.type_alias_signature(t);
-        let mut ctx = TyLoweringContext::new(
-            db,
-            &resolver,
-            &alias.store,
-            t.into(),
-            LifetimeElisionKind::AnonymousReportError,
-        )
-        .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-        .with_type_param_mode(ParamLoweringMode::Variable);
-        let res = alias
-            .ty
-            .map(|type_ref| ctx.lower_ty(type_ref))
-            .unwrap_or_else(|| TyKind::Error.intern(Interner));
-        diags = create_diagnostics(ctx.diagnostics);
-        res
-    };
-
-    (make_binders(db, &generics, inner), diags)
-}
-
-pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    adt: TypeAliasId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, adt.into());
-    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
-}
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum TyDefId {
     BuiltinType(BuiltinType),
@@ -1644,64 +1331,8 @@ impl ValueTyDefId {
     }
 }
 
-/// Build the declared type of an item. This depends on the namespace; e.g. for
-/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
-/// the constructor function `(usize) -> Foo` which lives in the values
-/// namespace.
-pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
-    match def {
-        TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)),
-        TyDefId::AdtId(it) => type_for_adt_tracked(db, it),
-        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
-    }
-}
-
-pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option<Binders<Ty>> {
-    match def {
-        ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)),
-        ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it),
-        ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())),
-        ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it),
-        ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)),
-        ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)),
-    }
-}
-
-pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> {
-    db.impl_self_ty_with_diagnostics(impl_id).0
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
-    let impl_data = db.impl_signature(impl_id);
-    let resolver = impl_id.resolver(db);
-    let generics = generics(db, impl_id.into());
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    (
-        make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)),
-        create_diagnostics(ctx.diagnostics),
-    )
-}
-
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, impl_id.into());
-    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
-}
-
 pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
-    db.const_param_ty_with_diagnostics(def).0
+    const_param_ty_with_diagnostics_query(db, def).0
 }
 
 // returns None if def is a type arg
@@ -1729,36 +1360,12 @@ pub(crate) fn const_param_ty_with_diagnostics_query(
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
-pub(crate) fn const_param_ty_with_diagnostics_cycle_result(
+pub(crate) fn const_param_ty_cycle_result(
     _: &dyn HirDatabase,
     _: crate::db::HirDatabaseData,
     _: ConstParamId,
-) -> (Ty, Diagnostics) {
-    (TyKind::Error.intern(Interner), None)
-}
-
-pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
-    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
-}
-
-pub(crate) fn impl_trait_with_diagnostics_query(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> Option<(Binders<TraitRef>, Diagnostics)> {
-    let impl_data = db.impl_signature(impl_id);
-    let resolver = impl_id.resolver(db);
-    let mut ctx = TyLoweringContext::new(
-        db,
-        &resolver,
-        &impl_data.store,
-        impl_id.into(),
-        LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
-    )
-    .with_type_param_mode(ParamLoweringMode::Variable);
-    let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
-    let target_trait = impl_data.target_trait.as_ref()?;
-    let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?);
-    Some((trait_ref, create_diagnostics(ctx.diagnostics)))
+) -> Ty {
+    TyKind::Error.intern(Interner)
 }
 
 pub(crate) fn return_type_impl_traits(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
index b0132e4dcbc..da9dd21183e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -28,6 +28,10 @@ use crate::{
     error_lifetime,
     generics::{Generics, generics},
     lower::{LifetimeElisionKind, named_associated_type_shorthand_candidates},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::associated_type_by_name_including_super_traits,
 };
@@ -251,12 +255,20 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         // `def` can be either impl itself or item within, and we need impl itself
                         // now.
                         let generics = generics.parent_or_self();
+                        let interner = DbInterner::new_with(self.ctx.db, None, None);
                         let subst = generics.placeholder_subst(self.ctx.db);
-                        self.ctx.db.impl_self_ty(impl_id).substitute(Interner, &subst)
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            subst.to_nextsolver(interner);
+                        self.ctx
+                            .db
+                            .impl_self_ty(impl_id)
+                            .instantiate(interner, args)
+                            .to_chalk(interner)
                     }
                     ParamLoweringMode::Variable => TyBuilder::impl_self_ty(self.ctx.db, impl_id)
                         .fill_with_bound_vars(self.ctx.in_binders, 0)
-                        .build(),
+                        .build(DbInterner::conjure())
+                        .to_chalk(DbInterner::conjure()),
                 }
             }
             TypeNs::AdtSelfType(adt) => {
@@ -267,7 +279,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         generics.bound_vars_subst(self.ctx.db, self.ctx.in_binders)
                     }
                 };
-                self.ctx.db.ty(adt.into()).substitute(Interner, &substs)
+                let interner = DbInterner::conjure();
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                self.ctx.db.ty(adt.into()).instantiate(interner, args).to_chalk(interner)
             }
 
             TypeNs::AdtId(it) => self.lower_path_inner(it.into(), infer_args),
@@ -537,7 +551,9 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
             TyDefId::TypeAliasId(it) => it.into(),
         };
         let substs = self.substs_from_path_segment(generic_def, infer_args, None, false);
-        self.ctx.db.ty(typeable).substitute(Interner, &substs)
+        let interner = DbInterner::conjure();
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        self.ctx.db.ty(typeable).instantiate(interner, args).to_chalk(interner)
     }
 
     /// Collect generic arguments from a path into a `Substs`. See also
@@ -603,7 +619,7 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
         explicit_self_ty: Option<Ty>,
         lowering_assoc_type_generics: bool,
     ) -> Substitution {
-        let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+        let old_lifetime_elision = self.ctx.lifetime_elision.clone();
 
         if let Some(args) = self.current_or_prev_segment.args_and_bindings
             && args.parenthesized != GenericArgsParentheses::No
@@ -633,19 +649,21 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
             }
 
             // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
-            lifetime_elision =
+            self.ctx.lifetime_elision =
                 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
         }
 
-        self.substs_from_args_and_bindings(
+        let result = self.substs_from_args_and_bindings(
             self.current_or_prev_segment.args_and_bindings,
             def,
             infer_args,
             explicit_self_ty,
             PathGenericsSource::Segment(self.current_segment_u32()),
             lowering_assoc_type_generics,
-            lifetime_elision,
-        )
+            self.ctx.lifetime_elision.clone(),
+        );
+        self.ctx.lifetime_elision = old_lifetime_elision;
+        result
     }
 
     pub(super) fn substs_from_args_and_bindings(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
index 0076446a958..84cd216b812 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver.rs
@@ -19,9 +19,9 @@ use base_db::Crate;
 use either::Either;
 use hir_def::item_tree::FieldsShape;
 use hir_def::{
-    AdtId, AssocItemId, CallableDefId, ConstParamId, EnumVariantId, FunctionId, GenericDefId,
-    GenericParamId, ImplId, ItemContainerId, LocalFieldId, Lookup, StructId, TraitId, TypeAliasId,
-    TypeOrConstParamId, VariantId,
+    AdtId, AssocItemId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
+    GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup,
+    StructId, TraitId, TypeAliasId, TypeOrConstParamId, VariantId,
     expr_store::{
         ExpressionStore,
         path::{GenericArg, Path},
@@ -57,7 +57,7 @@ use triomphe::Arc;
 
 use crate::ValueTyDefId;
 use crate::{
-    FnAbi, ImplTraitId, Interner, ParamKind, TyDefId, TyLoweringDiagnostic,
+    FnAbi, ImplTraitId, Interner, ParamKind, TraitEnvironment, TyDefId, TyLoweringDiagnostic,
     TyLoweringDiagnosticKind,
     consteval_nextsolver::{intern_const_ref, path_to_const, unknown_const_as_generic},
     db::HirDatabase,
@@ -66,8 +66,10 @@ use crate::{
     next_solver::{
         AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind,
         BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder,
-        EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId,
-        TraitPredicate, TraitRef, Ty, Tys, abi::Safety, mapping::ChalkToNextSolver,
+        EarlyParamRegion, ErrorGuaranteed, GenericArgs, ParamEnv, PolyFnSig, Predicate, Region,
+        SolverDefId, TraitPredicate, TraitRef, Ty, Tys,
+        abi::Safety,
+        mapping::{ChalkToNextSolver, convert_ty_for_result},
     },
 };
 
@@ -902,7 +904,7 @@ pub(crate) fn impl_trait_query<'db>(
     db: &'db dyn HirDatabase,
     impl_id: ImplId,
 ) -> Option<EarlyBinder<'db, TraitRef<'db>>> {
-    db.impl_trait_with_diagnostics_ns(impl_id).map(|it| it.0)
+    db.impl_trait_with_diagnostics(impl_id).map(|it| it.0)
 }
 
 pub(crate) fn impl_trait_with_diagnostics_query<'db>(
@@ -918,7 +920,7 @@ pub(crate) fn impl_trait_with_diagnostics_query<'db>(
         impl_id.into(),
         LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true },
     );
-    let self_ty = db.impl_self_ty_ns(impl_id).skip_binder();
+    let self_ty = db.impl_self_ty(impl_id).skip_binder();
     let target_trait = impl_data.target_trait.as_ref()?;
     let trait_ref = EarlyBinder::bind(ctx.lower_trait_ref(target_trait, self_ty)?);
     Some((trait_ref, create_diagnostics(ctx.diagnostics)))
@@ -984,7 +986,7 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind
             AdtDef::new(it, interner),
             GenericArgs::identity_for_item(interner, it.into()),
         )),
-        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics_ns(it).0,
+        TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0,
     }
 }
 
@@ -1129,7 +1131,7 @@ pub(crate) fn impl_self_ty_query<'db>(
     db: &'db dyn HirDatabase,
     impl_id: ImplId,
 ) -> EarlyBinder<'db, Ty<'db>> {
-    db.impl_self_ty_with_diagnostics_ns(impl_id).0
+    db.impl_self_ty_with_diagnostics(impl_id).0
 }
 
 pub(crate) fn impl_self_ty_with_diagnostics_query<'db>(
@@ -1160,7 +1162,7 @@ pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
 }
 
 pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> {
-    db.const_param_ty_with_diagnostics_ns(def).0
+    db.const_param_ty_with_diagnostics(def).0
 }
 
 // returns None if def is a type arg
@@ -1189,11 +1191,21 @@ pub(crate) fn const_param_ty_with_diagnostics_query<'db>(
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result<'db>(
+    db: &'db dyn HirDatabase,
+    _: crate::db::HirDatabaseData,
+    def: ConstParamId,
+) -> (Ty<'db>, Diagnostics) {
+    let resolver = def.parent().resolver(db);
+    let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+    (Ty::new_error(interner, ErrorGuaranteed), None)
+}
+
 pub(crate) fn field_types_query<'db>(
     db: &'db dyn HirDatabase,
     variant_id: VariantId,
 ) -> Arc<ArenaMap<LocalFieldId, EarlyBinder<'db, Ty<'db>>>> {
-    db.field_types_with_diagnostics_ns(variant_id).0
+    db.field_types_with_diagnostics(variant_id).0
 }
 
 /// Build the type of all specific fields of a struct or enum variant.
@@ -1355,6 +1367,18 @@ pub(crate) fn generic_predicates_for_param_cycle_result(
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GenericPredicates<'db>(Option<Arc<[Clause<'db>]>>);
 
+impl<'db> GenericPredicates<'db> {
+    pub fn instantiate(
+        &self,
+        interner: DbInterner<'db>,
+        args: GenericArgs<'db>,
+    ) -> Option<impl Iterator<Item = Clause<'db>>> {
+        self.0
+            .as_ref()
+            .map(|it| EarlyBinder::bind(it.iter().copied()).iter_instantiated(interner, args))
+    }
+}
+
 impl<'db> ops::Deref for GenericPredicates<'db> {
     type Target = [Clause<'db>];
 
@@ -1363,6 +1387,122 @@ impl<'db> ops::Deref for GenericPredicates<'db> {
     }
 }
 
+pub(crate) fn trait_environment_for_body_query(
+    db: &dyn HirDatabase,
+    def: DefWithBodyId,
+) -> Arc<TraitEnvironment<'_>> {
+    let Some(def) = def.as_generic_def_id(db) else {
+        let krate = def.module(db).krate();
+        return TraitEnvironment::empty(krate);
+    };
+    db.trait_environment(def)
+}
+
+pub(crate) fn trait_environment_query<'db>(
+    db: &'db dyn HirDatabase,
+    def: GenericDefId,
+) -> Arc<TraitEnvironment<'db>> {
+    let generics = generics(db, def);
+    if generics.has_no_predicates() && generics.is_empty() {
+        return TraitEnvironment::empty(def.krate(db));
+    }
+
+    let interner = DbInterner::new_with(db, Some(def.krate(db)), None);
+    let resolver = def.resolver(db);
+    let mut ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        generics.store(),
+        def,
+        LifetimeElisionKind::AnonymousReportError,
+    );
+    let mut traits_in_scope = Vec::new();
+    let mut clauses = Vec::new();
+    for maybe_parent_generics in
+        std::iter::successors(Some(&generics), |generics| generics.parent_generics())
+    {
+        ctx.store = maybe_parent_generics.store();
+        for pred in maybe_parent_generics.where_predicates() {
+            for pred in ctx.lower_where_predicate(pred, false, &generics, PredicateFilter::All) {
+                if let rustc_type_ir::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
+                    traits_in_scope
+                        .push((convert_ty_for_result(interner, tr.self_ty()), tr.def_id().0));
+                }
+                clauses.push(pred);
+            }
+        }
+    }
+
+    if let Some(trait_id) = def.assoc_trait_container(db) {
+        // add `Self: Trait<T1, T2, ...>` to the environment in trait
+        // function default implementations (and speculative code
+        // inside consts or type aliases)
+        cov_mark::hit!(trait_self_implements_self);
+        let trait_ref = TraitRef::identity(ctx.interner, trait_id.into());
+        let clause = Clause(Predicate::new(
+            ctx.interner,
+            Binder::dummy(rustc_type_ir::PredicateKind::Clause(rustc_type_ir::ClauseKind::Trait(
+                TraitPredicate { trait_ref, polarity: rustc_type_ir::PredicatePolarity::Positive },
+            ))),
+        ));
+        clauses.push(clause);
+    }
+
+    let explicitly_unsized_tys = ctx.unsized_types;
+
+    let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+    if let Some(sized_trait) = sized_trait {
+        let (mut generics, mut def_id) =
+            (crate::next_solver::generics::generics(db, def.into()), def);
+        loop {
+            let self_idx = trait_self_param_idx(db, def_id);
+            for (idx, p) in generics.own_params.iter().enumerate() {
+                if let Some(self_idx) = self_idx
+                    && p.index() as usize == self_idx
+                {
+                    continue;
+                }
+                let GenericParamId::TypeParamId(param_id) = p.id else {
+                    continue;
+                };
+                let idx = idx as u32 + generics.parent_count as u32;
+                let param_ty = Ty::new_param(ctx.interner, param_id, idx, p.name.clone());
+                if explicitly_unsized_tys.contains(&param_ty) {
+                    continue;
+                }
+                let trait_ref = TraitRef::new_from_args(
+                    ctx.interner,
+                    sized_trait.into(),
+                    GenericArgs::new_from_iter(ctx.interner, [param_ty.into()]),
+                );
+                let clause = Clause(Predicate::new(
+                    ctx.interner,
+                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                        rustc_type_ir::ClauseKind::Trait(TraitPredicate {
+                            trait_ref,
+                            polarity: rustc_type_ir::PredicatePolarity::Positive,
+                        }),
+                    )),
+                ));
+                clauses.push(clause);
+            }
+
+            if let Some(g) = generics.parent {
+                generics = crate::next_solver::generics::generics(db, g.into());
+                def_id = g;
+            } else {
+                break;
+            }
+        }
+    }
+
+    let clauses = rustc_type_ir::elaborate::elaborate(ctx.interner, clauses);
+    let clauses = Clauses::new_from_iter(ctx.interner, clauses);
+    let env = ParamEnv { clauses };
+
+    TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env)
+}
+
 #[derive(Copy, Clone, Debug)]
 pub(crate) enum PredicateFilter {
     SelfTrait,
@@ -1830,7 +1970,8 @@ fn named_associated_type_shorthand_candidates<'db, R>(
     let mut search = |t: TraitRef<'db>| -> Option<R> {
         let trait_id = t.def_id.0;
         let mut checked_traits = FxHashSet::default();
-        let mut check_trait = |trait_id: TraitId| {
+        let mut check_trait = |trait_ref: TraitRef<'db>| {
+            let trait_id = trait_ref.def_id.0;
             let name = &db.trait_signature(trait_id).name;
             tracing::debug!(?trait_id, ?name);
             if !checked_traits.insert(trait_id) {
@@ -1841,37 +1982,39 @@ fn named_associated_type_shorthand_candidates<'db, R>(
             tracing::debug!(?data.items);
             for (name, assoc_id) in &data.items {
                 if let &AssocItemId::TypeAliasId(alias) = assoc_id
-                    && let Some(ty) = check_alias(name, t, alias)
+                    && let Some(ty) = check_alias(name, trait_ref, alias)
                 {
                     return Some(ty);
                 }
             }
             None
         };
-        let mut stack: SmallVec<[_; 4]> = smallvec![trait_id];
-        while let Some(trait_def_id) = stack.pop() {
-            if let Some(alias) = check_trait(trait_def_id) {
+        let mut stack: SmallVec<[_; 4]> = smallvec![t];
+        while let Some(trait_ref) = stack.pop() {
+            if let Some(alias) = check_trait(trait_ref) {
                 return Some(alias);
             }
             for pred in generic_predicates_filtered_by(
                 db,
-                GenericDefId::TraitId(trait_def_id),
+                GenericDefId::TraitId(trait_ref.def_id.0),
                 PredicateFilter::SelfTrait,
                 // We are likely in the midst of lowering generic predicates of `def`.
                 // So, if we allow `pred == def` we might fall into an infinite recursion.
                 // Actually, we have already checked for the case `pred == def` above as we started
                 // with a stack including `trait_id`
-                |pred| pred != def && pred == GenericDefId::TraitId(trait_def_id),
+                |pred| pred != def && pred == GenericDefId::TraitId(trait_ref.def_id.0),
             )
             .0
             .deref()
             {
                 tracing::debug!(?pred);
-                let trait_id = match pred.kind().skip_binder() {
-                    rustc_type_ir::ClauseKind::Trait(pred) => pred.def_id(),
+                let sup_trait_ref = match pred.kind().skip_binder() {
+                    rustc_type_ir::ClauseKind::Trait(pred) => pred.trait_ref,
                     _ => continue,
                 };
-                stack.push(trait_id.0);
+                let sup_trait_ref =
+                    EarlyBinder::bind(sup_trait_ref).instantiate(interner, trait_ref.args);
+                stack.push(sup_trait_ref);
             }
             tracing::debug!(?stack);
         }
@@ -1881,7 +2024,7 @@ fn named_associated_type_shorthand_candidates<'db, R>(
 
     match res {
         TypeNs::SelfType(impl_id) => {
-            let trait_ref = db.impl_trait_ns(impl_id)?;
+            let trait_ref = db.impl_trait(impl_id)?;
 
             // FIXME(next-solver): same method in `lower` checks for impl or not
             // Is that needed here?
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
index 7d6734303c4..0a9f34c9dab 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower_nextsolver/path.rs
@@ -287,7 +287,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
                     }
                 }
             }
-            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty_ns(impl_id).skip_binder(),
+            TypeNs::SelfType(impl_id) => self.ctx.db.impl_self_ty(impl_id).skip_binder(),
             TypeNs::AdtSelfType(adt) => {
                 let args = crate::next_solver::GenericArgs::identity_for_item(
                     self.ctx.interner,
@@ -616,7 +616,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
         explicit_self_ty: Option<Ty<'db>>,
         lowering_assoc_type_generics: bool,
     ) -> crate::next_solver::GenericArgs<'db> {
-        let mut lifetime_elision = self.ctx.lifetime_elision.clone();
+        let old_lifetime_elision = self.ctx.lifetime_elision.clone();
 
         if let Some(args) = self.current_or_prev_segment.args_and_bindings
             && args.parenthesized != GenericArgsParentheses::No
@@ -646,19 +646,21 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
             }
 
             // `Fn()`-style generics are treated like functions for the purpose of lifetime elision.
-            lifetime_elision =
+            self.ctx.lifetime_elision =
                 LifetimeElisionKind::AnonymousCreateParameter { report_in_path: false };
         }
 
-        self.substs_from_args_and_bindings(
+        let result = self.substs_from_args_and_bindings(
             self.current_or_prev_segment.args_and_bindings,
             def,
             infer_args,
             explicit_self_ty,
             PathGenericsSource::Segment(self.current_segment_u32()),
             lowering_assoc_type_generics,
-            lifetime_elision,
-        )
+            self.ctx.lifetime_elision.clone(),
+        );
+        self.ctx.lifetime_elision = old_lifetime_elision;
+        result
     }
 
     pub(super) fn substs_from_args_and_bindings(
@@ -915,22 +917,36 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = binding.type_ref {
-                    match (&self.ctx.store[type_ref], self.ctx.impl_trait_mode.mode) {
-                        (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
-                        (_, ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque) => {
-                            let ty = self.ctx.lower_ty(type_ref);
-                            let pred = Clause(Predicate::new(
-                                interner,
-                                Binder::dummy(rustc_type_ir::PredicateKind::Clause(
-                                    rustc_type_ir::ClauseKind::Projection(ProjectionPredicate {
-                                        projection_term,
-                                        term: ty.into(),
-                                    }),
-                                )),
-                            ));
-                            predicates.push(pred);
+                    let lifetime_elision =
+                        if args_and_bindings.parenthesized == GenericArgsParentheses::ParenSugar {
+                            // `Fn()`-style generics are elided like functions. This is `Output` (we lower to it in hir-def).
+                            LifetimeElisionKind::for_fn_ret(self.ctx.interner)
+                        } else {
+                            self.ctx.lifetime_elision.clone()
+                        };
+                    self.with_lifetime_elision(lifetime_elision, |this| {
+                        match (&this.ctx.store[type_ref], this.ctx.impl_trait_mode.mode) {
+                            (TypeRef::ImplTrait(_), ImplTraitLoweringMode::Disallowed) => (),
+                            (
+                                _,
+                                ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque,
+                            ) => {
+                                let ty = this.ctx.lower_ty(type_ref);
+                                let pred = Clause(Predicate::new(
+                                    interner,
+                                    Binder::dummy(rustc_type_ir::PredicateKind::Clause(
+                                        rustc_type_ir::ClauseKind::Projection(
+                                            ProjectionPredicate {
+                                                projection_term,
+                                                term: ty.into(),
+                                            },
+                                        ),
+                                    )),
+                                ));
+                                predicates.push(pred);
+                            }
                         }
-                    }
+                    })
                 }
                 for bound in binding.bounds.iter() {
                     predicates.extend(self.ctx.lower_type_bound(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 7fa3d31fe5f..61d3091a0c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -31,10 +31,13 @@ use crate::{
     infer::{Adjust, Adjustment, OverloadedDeref, PointerCast, unify::InferenceTable},
     lang_items::is_box,
     next_solver::{
-        self, SolverDefId,
-        fulfill::FulfillmentCtxt,
-        infer::DefineOpaqueTypes,
+        self, DbInterner, SolverDefId,
+        infer::{
+            DefineOpaqueTypes,
+            traits::{ObligationCause, PredicateObligation},
+        },
         mapping::{ChalkToNextSolver, NextSolverToChalk},
+        obligation_ctxt::ObligationCtxt,
     },
     primitive::{FloatTy, IntTy, UintTy},
     to_chalk_trait_id,
@@ -294,11 +297,12 @@ impl TraitImpls {
                     continue;
                 }
                 let target_trait = match db.impl_trait(impl_id) {
-                    Some(tr) => tr.skip_binders().hir_trait_id(),
+                    Some(tr) => tr.skip_binder().def_id.0,
                     None => continue,
                 };
-                let self_ty = db.impl_self_ty(impl_id);
-                let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
+                let interner = DbInterner::new_with(db, None, None);
+                let self_ty = db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner);
+                let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty);
                 map.entry(target_trait).or_default().entry(self_ty_fp).or_default().push(impl_id);
             }
 
@@ -411,8 +415,8 @@ impl InherentImpls {
                     continue;
                 }
 
-                let self_ty = db.impl_self_ty(impl_id);
-                let self_ty = self_ty.skip_binders();
+                let interner = DbInterner::new_with(db, None, None);
+                let self_ty = &db.impl_self_ty(impl_id).instantiate_identity().to_chalk(interner);
 
                 match is_inherent_impl_coherent(db, def_map, impl_id, self_ty) {
                     true => {
@@ -542,7 +546,7 @@ pub fn def_crates(db: &dyn HirDatabase, ty: &Ty, cur_crate: Crate) -> Option<Sma
 pub(crate) fn lookup_method<'db>(
     db: &'db dyn HirDatabase,
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: &Name,
@@ -711,7 +715,7 @@ impl ReceiverAdjustments {
 pub(crate) fn iterate_method_candidates<'db, T>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -739,9 +743,9 @@ pub(crate) fn iterate_method_candidates<'db, T>(
     slot
 }
 
-pub fn lookup_impl_const(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub fn lookup_impl_const<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     const_id: ConstId,
     subs: Substitution,
 ) -> (ConstId, Substitution) {
@@ -767,9 +771,9 @@ pub fn lookup_impl_const(
 
 /// Checks if the self parameter of `Trait` method is the `dyn Trait` and we should
 /// call the method using the vtable.
-pub fn is_dyn_method(
-    db: &dyn HirDatabase,
-    _env: Arc<TraitEnvironment>,
+pub fn is_dyn_method<'db>(
+    db: &'db dyn HirDatabase,
+    _env: Arc<TraitEnvironment<'db>>,
     func: FunctionId,
     fn_subst: Substitution,
 ) -> Option<usize> {
@@ -809,9 +813,9 @@ pub fn is_dyn_method(
 /// Looks up the impl method that actually runs for the trait method `func`.
 ///
 /// Returns `func` if it's not a method defined in a trait or the lookup failed.
-pub(crate) fn lookup_impl_method_query(
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+pub(crate) fn lookup_impl_method_query<'db>(
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     func: FunctionId,
     fn_subst: Substitution,
 ) -> (FunctionId, Substitution) {
@@ -842,10 +846,10 @@ pub(crate) fn lookup_impl_method_query(
     )
 }
 
-fn lookup_impl_assoc_item_for_trait_ref(
+fn lookup_impl_assoc_item_for_trait_ref<'db>(
     trait_ref: TraitRef,
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    db: &'db dyn HirDatabase,
+    env: Arc<TraitEnvironment<'db>>,
     name: &Name,
 ) -> Option<(AssocItemId, Substitution)> {
     let hir_trait_id = trait_ref.hir_trait_id();
@@ -894,10 +898,13 @@ fn find_matching_impl(
         table.run_in_snapshot(|table| {
             let impl_substs =
                 TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
+            let args: crate::next_solver::GenericArgs<'_> =
+                impl_substs.to_nextsolver(table.interner);
             let trait_ref = db
                 .impl_trait(impl_)
                 .expect("non-trait method in find_matching_impl")
-                .substitute(Interner, &impl_substs);
+                .instantiate(table.interner, args)
+                .to_chalk(table.interner);
 
             if !table.unify(&trait_ref, &actual_trait_ref) {
                 return None;
@@ -907,10 +914,11 @@ fn find_matching_impl(
                 .into_iter()
                 .map(|b| -> Goal { b.cast(Interner) });
             for goal in wcs {
-                if table.try_obligation(goal.clone()).no_solution() {
+                let goal = goal.to_nextsolver(table.interner);
+                if table.try_obligation(goal).no_solution() {
                     return None;
                 }
-                table.register_obligation(goal.to_nextsolver(table.interner));
+                table.register_obligation(goal);
             }
             Some((
                 impl_.impl_items(db),
@@ -1014,7 +1022,9 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
     let local_crate = impl_.lookup(db).container.krate();
     let is_local = |tgt_crate| tgt_crate == local_crate;
 
-    let trait_ref = impl_trait.substitute(Interner, &substs);
+    let interner = DbInterner::new_with(db, None, None);
+    let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+    let trait_ref = impl_trait.instantiate(interner, args).to_chalk(interner);
     let trait_id = from_chalk_trait_id(trait_ref.trait_id);
     if is_local(trait_id.module(db).krate()) {
         // trait to be implemented is local
@@ -1063,7 +1073,7 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
 pub fn iterate_path_candidates<'db>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1085,7 +1095,7 @@ pub fn iterate_path_candidates<'db>(
 pub fn iterate_method_candidates_dyn<'db>(
     ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1347,7 +1357,7 @@ fn iterate_method_candidates_by_receiver<'db>(
 fn iterate_method_candidates_for_self_ty<'db>(
     self_ty: &next_solver::Canonical<'db, crate::next_solver::Ty<'db>>,
     db: &'db dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
@@ -1395,7 +1405,7 @@ fn iterate_trait_method_candidates(
     let db = table.db;
 
     let canonical_self_ty = table.canonicalize(self_ty.clone().to_nextsolver(table.interner));
-    let TraitEnvironment { krate, .. } = *table.trait_env;
+    let krate = table.trait_env.krate;
 
     'traits: for &t in traits_in_scope {
         let data = db.trait_signature(t);
@@ -1635,7 +1645,6 @@ pub(crate) fn resolve_indexing_op<'db>(
     let ty = table.instantiate_canonical_ns(ty);
     let deref_chain = autoderef_method_receiver(table, ty);
     for (ty, adj) in deref_chain {
-        //let goal = generic_implements_goal_ns(db, &table.trait_env, index_trait, &ty);
         let goal = generic_implements_goal_ns(table, index_trait, ty);
         if !next_trait_solve_canonical_in_ctxt(&table.infer_ctxt, goal).no_solution() {
             return Some(adj);
@@ -1694,8 +1703,10 @@ fn is_valid_impl_method_candidate(
                 return IsValidCandidate::NotVisible;
             }
             let self_ty_matches = table.run_in_snapshot(|table| {
-                let expected_self_ty =
-                    TyBuilder::impl_self_ty(db, impl_id).fill_with_inference_vars(table).build();
+                let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
+                    .fill_with_inference_vars(table)
+                    .build(DbInterner::conjure())
+                    .to_chalk(DbInterner::conjure());
                 table.unify(&expected_self_ty, self_ty)
             });
             if !self_ty_matches {
@@ -1741,9 +1752,13 @@ fn is_valid_trait_method_candidate(
                         .fill_with_inference_vars(table)
                         .build();
 
+                    let args: crate::next_solver::GenericArgs<'_> =
+                        fn_subst.to_nextsolver(table.interner);
                     let sig = db.callable_item_signature(fn_id.into());
-                    let expected_receiver =
-                        sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+                    let expected_receiver = sig
+                        .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+                        .instantiate(table.interner, args)
+                        .to_chalk(table.interner);
 
                     // FIXME: Clean up this mess with some context struct like rustc's `ProbeContext`
                     let variance = match mode {
@@ -1754,7 +1769,7 @@ fn is_valid_trait_method_candidate(
                         .infer_ctxt
                         .at(
                             &next_solver::infer::traits::ObligationCause::dummy(),
-                            table.trait_env.env.to_nextsolver(table.interner),
+                            table.trait_env.env,
                         )
                         .relate(
                             DefineOpaqueTypes::No,
@@ -1767,12 +1782,10 @@ fn is_valid_trait_method_candidate(
                     };
 
                     if !infer_ok.obligations.is_empty() {
-                        let mut ctxt = FulfillmentCtxt::new(&table.infer_ctxt);
-                        for pred in infer_ok.into_obligations() {
-                            ctxt.register_predicate_obligation(&table.infer_ctxt, pred);
-                        }
+                        let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
+                        ctxt.register_obligations(infer_ok.into_obligations());
                         // FIXME: Are we doing this correctly? Probably better to follow rustc more closely.
-                        check_that!(ctxt.select_where_possible(&table.infer_ctxt).is_empty());
+                        check_that!(ctxt.select_where_possible().is_empty());
                     }
 
                     check_that!(table.unify(receiver_ty, &expected_receiver));
@@ -1815,9 +1828,11 @@ fn is_valid_impl_fn_candidate(
     }
     table.run_in_snapshot(|table| {
         let _p = tracing::info_span!("subst_for_def").entered();
-        let impl_subst =
-            TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build();
-        let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst);
+        let impl_subst = table.infer_ctxt.fresh_args_for_item(impl_id.into());
+        let expect_self_ty = db
+            .impl_self_ty(impl_id)
+            .instantiate(table.interner, &impl_subst)
+            .to_chalk(table.interner);
 
         check_that!(table.unify(&expect_self_ty, self_ty));
 
@@ -1825,65 +1840,49 @@ fn is_valid_impl_fn_candidate(
             let _p = tracing::info_span!("check_receiver_ty").entered();
             check_that!(data.has_self_param());
 
-            let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
-                .fill_with_inference_vars(table)
-                .build();
+            let fn_subst: crate::Substitution =
+                table.infer_ctxt.fresh_args_for_item(fn_id.into()).to_chalk(table.interner);
 
+            let args: crate::next_solver::GenericArgs<'_> = fn_subst.to_nextsolver(table.interner);
             let sig = db.callable_item_signature(fn_id.into());
-            let expected_receiver =
-                sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
+            let expected_receiver = sig
+                .map_bound(|s| s.skip_binder().inputs_and_output.as_slice()[0])
+                .instantiate(table.interner, args)
+                .to_chalk(table.interner);
 
             check_that!(table.unify(receiver_ty, &expected_receiver));
         }
 
         // We need to consider the bounds on the impl to distinguish functions of the same name
         // for a type.
-        let predicates = db.generic_predicates(impl_id.into());
-        let goals = predicates.iter().map(|p| {
-            let (p, b) = p
-                .clone()
-                .substitute(Interner, &impl_subst)
-                // Skipping the inner binders is ok, as we don't handle quantified where
-                // clauses yet.
-                .into_value_and_skipped_binders();
-            stdx::always!(b.len(Interner) == 0);
-
-            p.cast::<Goal>(Interner)
-        });
-
-        for goal in goals.clone() {
-            match table.solve_obligation(goal) {
-                Ok(_) => {}
-                Err(_) => {
-                    return IsValidCandidate::No;
-                }
-            }
-        }
+        let predicates = db.generic_predicates_ns(impl_id.into());
+        let Some(predicates) = predicates.instantiate(table.interner, impl_subst) else {
+            return IsValidCandidate::Yes;
+        };
 
-        for goal in goals {
-            if table.try_obligation(goal).no_solution() {
-                return IsValidCandidate::No;
-            }
-        }
+        let mut ctxt = ObligationCtxt::new(&table.infer_ctxt);
 
-        IsValidCandidate::Yes
-    })
-}
+        ctxt.register_obligations(predicates.into_iter().map(|p| {
+            PredicateObligation::new(
+                table.interner,
+                ObligationCause::new(),
+                table.trait_env.env,
+                p.0,
+            )
+        }));
 
-pub fn implements_trait(
-    ty: &Canonical<Ty>,
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
-    trait_: TraitId,
-) -> bool {
-    let goal = generic_implements_goal(db, env, trait_, ty);
-    !db.trait_solve(env.krate, env.block, goal.cast(Interner)).no_solution()
+        if ctxt.select_where_possible().is_empty() {
+            IsValidCandidate::Yes
+        } else {
+            IsValidCandidate::No
+        }
+    })
 }
 
-pub fn implements_trait_unique(
+pub fn implements_trait_unique<'db>(
     ty: &Canonical<Ty>,
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
+    db: &'db dyn HirDatabase,
+    env: &TraitEnvironment<'db>,
     trait_: TraitId,
 ) -> bool {
     let goal = generic_implements_goal(db, env, trait_, ty);
@@ -1891,11 +1890,11 @@ pub fn implements_trait_unique(
 }
 
 /// This creates Substs for a trait with the given Self type and type variables
-/// for all other parameters, to query Chalk with it.
+/// for all other parameters, to query next solver with it.
 #[tracing::instrument(skip_all)]
-fn generic_implements_goal(
-    db: &dyn HirDatabase,
-    env: &TraitEnvironment,
+fn generic_implements_goal<'db>(
+    db: &'db dyn HirDatabase,
+    env: &TraitEnvironment<'db>,
     trait_: TraitId,
     self_ty: &Canonical<Ty>,
 ) -> Canonical<InEnvironment<super::DomainGoal>> {
@@ -1917,7 +1916,10 @@ fn generic_implements_goal(
     let binders = CanonicalVarKinds::from_iter(Interner, kinds);
 
     let obligation = trait_ref.cast(Interner);
-    let value = InEnvironment::new(&env.env, obligation);
+    let value = InEnvironment::new(
+        &env.env.to_chalk(DbInterner::new_with(db, Some(env.krate), env.block)),
+        obligation,
+    );
     Canonical { binders, value }
 }
 
@@ -1934,11 +1936,7 @@ fn generic_implements_goal_ns<'db>(
     let trait_ref =
         rustc_type_ir::TraitRef::new_from_args(table.infer_ctxt.interner, trait_.into(), args)
             .with_replaced_self_ty(table.infer_ctxt.interner, self_ty);
-    let goal = next_solver::Goal::new(
-        table.infer_ctxt.interner,
-        table.trait_env.env.to_nextsolver(table.infer_ctxt.interner),
-        trait_ref,
-    );
+    let goal = next_solver::Goal::new(table.infer_ctxt.interner, table.trait_env.env, trait_ref);
 
     table.canonicalize(goal)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index fc7d97fff46..c93165a04c0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -165,7 +165,7 @@ enum MirOrDynIndex {
 
 pub struct Evaluator<'a> {
     db: &'a dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'a>>,
     target_data_layout: Arc<TargetDataLayout>,
     stack: Vec<u8>,
     heap: Vec<u8>,
@@ -432,9 +432,12 @@ impl MirEvalError {
                 let self_ = match func.lookup(db).container {
                     ItemContainerId::ImplId(impl_id) => Some({
                         let generics = crate::generics::generics(db, impl_id.into());
+                        let interner = DbInterner::new_with(db, None, None);
                         let substs = generics.placeholder_subst(db);
+                        let args: crate::next_solver::GenericArgs<'_> =
+                            substs.to_nextsolver(interner);
                         db.impl_self_ty(impl_id)
-                            .substitute(Interner, &substs)
+                            .instantiate(interner, args)
                             .display(db, display_target)
                             .to_string()
                     }),
@@ -582,8 +585,8 @@ impl MirOutput {
     }
 }
 
-pub fn interpret_mir(
-    db: &dyn HirDatabase,
+pub fn interpret_mir<'db>(
+    db: &'db dyn HirDatabase,
     body: Arc<MirBody>,
     // FIXME: This is workaround. Ideally, const generics should have a separate body (issue #7434), but now
     // they share their body with their parent, so in MIR lowering we have locals of the parent body, which
@@ -591,7 +594,7 @@ pub fn interpret_mir(
     // a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
     // (and probably should) do better here, for example by excluding bindings outside of the target expression.
     assert_placeholder_ty_is_unused: bool,
-    trait_env: Option<Arc<TraitEnvironment>>,
+    trait_env: Option<Arc<TraitEnvironment<'db>>>,
 ) -> Result<(Result<Const>, MirOutput)> {
     let ty = body.locals[return_slot()].ty.clone();
     let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env)?;
@@ -632,11 +635,11 @@ const EXECUTION_LIMIT: usize = 10_000_000;
 
 impl<'db> Evaluator<'db> {
     pub fn new(
-        db: &dyn HirDatabase,
+        db: &'db dyn HirDatabase,
         owner: DefWithBodyId,
         assert_placeholder_ty_is_unused: bool,
-        trait_env: Option<Arc<TraitEnvironment>>,
-    ) -> Result<Evaluator<'_>> {
+        trait_env: Option<Arc<TraitEnvironment<'db>>>,
+    ) -> Result<Evaluator<'db>> {
         let crate_id = owner.module(db).krate();
         let target_data_layout = match db.target_data_layout(crate_id) {
             Ok(target_data_layout) => target_data_layout,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 38480493048..40d76bf42e9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -14,6 +14,7 @@ use hir_expand::name::Name;
 use intern::{Symbol, sym};
 use stdx::never;
 
+use crate::next_solver::mapping::NextSolverToChalk;
 use crate::{
     DropGlue,
     display::DisplayTarget,
@@ -1371,9 +1372,8 @@ impl Evaluator<'_> {
                     result = (l as i8).cmp(&(r as i8));
                 }
                 if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) {
-                    let ty = self.db.ty(e.into());
-                    let r = self
-                        .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?;
+                    let ty = self.db.ty(e.into()).skip_binder().to_chalk(interner);
+                    let r = self.compute_discriminant(ty.clone(), &[result as i8 as u8])?;
                     destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?;
                     Ok(())
                 } else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 50e416a66a6..3e44e8c68dd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -43,7 +43,10 @@ use crate::{
         Terminator, TerminatorKind, TupleFieldId, Ty, UnOp, VariantId, intern_const_scalar,
         return_slot,
     },
-    next_solver::{DbInterner, mapping::ChalkToNextSolver},
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
     static_lifetime,
     traits::FnTrait,
     utils::ClosureSubst,
@@ -82,7 +85,7 @@ struct MirLowerCtx<'db> {
     infer: &'db InferenceResult,
     resolver: Resolver<'db>,
     drop_scopes: Vec<DropScope>,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 }
 
 // FIXME: Make this smaller, its stored in database queries
@@ -2207,8 +2210,13 @@ pub fn lower_to_mir(
             // otherwise it's an inline const, and has no parameter
             if let DefWithBodyId::FunctionId(fid) = owner {
                 let substs = TyBuilder::placeholder_subst(db, fid);
-                let callable_sig =
-                    db.callable_item_signature(fid.into()).substitute(Interner, &substs);
+                let interner = DbInterner::new_with(db, None, None);
+                let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+                let callable_sig = db
+                    .callable_item_signature(fid.into())
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
                 let mut params = callable_sig.params().iter();
                 let self_param = body.self_param.and_then(|id| Some((id, params.next()?.clone())));
                 break 'b ctx.lower_params_and_bindings(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index 555b8785092..f293f38c769 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -35,7 +35,7 @@ macro_rules! not_supported {
 
 struct Filler<'a> {
     db: &'a dyn HirDatabase,
-    trait_env: Arc<TraitEnvironment>,
+    trait_env: Arc<TraitEnvironment<'a>>,
     subst: &'a Substitution,
     generics: Option<Generics>,
 }
@@ -301,11 +301,11 @@ impl Filler<'_> {
     }
 }
 
-pub fn monomorphized_mir_body_query(
-    db: &dyn HirDatabase,
+pub fn monomorphized_mir_body_query<'db>(
+    db: &'db dyn HirDatabase,
     owner: DefWithBodyId,
     subst: Substitution,
-    trait_env: Arc<crate::TraitEnvironment>,
+    trait_env: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics };
@@ -315,20 +315,20 @@ pub fn monomorphized_mir_body_query(
     Ok(Arc::new(body))
 }
 
-pub(crate) fn monomorphized_mir_body_cycle_result(
-    _db: &dyn HirDatabase,
+pub(crate) fn monomorphized_mir_body_cycle_result<'db>(
+    _db: &'db dyn HirDatabase,
     _: DefWithBodyId,
     _: Substitution,
-    _: Arc<crate::TraitEnvironment>,
+    _: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     Err(MirLowerError::Loop)
 }
 
-pub fn monomorphized_mir_body_for_closure_query(
-    db: &dyn HirDatabase,
+pub fn monomorphized_mir_body_for_closure_query<'db>(
+    db: &'db dyn HirDatabase,
     closure: InternedClosureId,
     subst: Substitution,
-    trait_env: Arc<crate::TraitEnvironment>,
+    trait_env: Arc<crate::TraitEnvironment<'db>>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
     let InternedClosure(owner, _) = db.lookup_intern_closure(closure);
     let generics = owner.as_generic_def_id(db).map(|g_def| generics(db, g_def));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
index 073a02908de..ab167e88af2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver.rs
@@ -13,7 +13,7 @@ pub(crate) mod inspect;
 pub mod interner;
 mod ir_print;
 pub mod mapping;
-mod normalize;
+pub mod normalize;
 pub mod obligation_ctxt;
 mod opaques;
 pub mod predicate;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
index 9cf56bef957..b72504a19cf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs
@@ -1091,23 +1091,21 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                     ItemContainerId::ImplId(it) => it,
                     _ => panic!("assoc ty value should be in impl"),
                 };
-                self.db().ty_ns(id.into())
+                self.db().ty(id.into())
             }
-            SolverDefId::AdtId(id) => self.db().ty_ns(id.into()),
+            SolverDefId::AdtId(id) => self.db().ty(id.into()),
             // FIXME(next-solver): This uses the types of `query mir_borrowck` in rustc.
             //
             // We currently always use the type from HIR typeck which ignores regions. This
             // should be fine.
             SolverDefId::InternedOpaqueTyId(_) => self.type_of_opaque_hir_typeck(def_id),
-            SolverDefId::FunctionId(id) => self.db.value_ty_ns(id.into()).unwrap(),
+            SolverDefId::FunctionId(id) => self.db.value_ty(id.into()).unwrap(),
             SolverDefId::Ctor(id) => {
                 let id = match id {
                     Ctor::Struct(id) => id.into(),
                     Ctor::Enum(id) => id.into(),
                 };
-                self.db
-                    .value_ty_ns(id)
-                    .expect("`SolverDefId::Ctor` should have a function-like ctor")
+                self.db.value_ty(id).expect("`SolverDefId::Ctor` should have a function-like ctor")
             }
             _ => panic!("Unexpected def_id `{def_id:?}` provided for `type_of`"),
         }
@@ -1227,7 +1225,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         def_id: Self::FunctionId,
     ) -> EarlyBinder<Self, rustc_type_ir::Binder<Self, rustc_type_ir::FnSig<Self>>> {
-        self.db().callable_item_signature_ns(def_id.0)
+        self.db().callable_item_signature(def_id.0)
     }
 
     fn coroutine_movability(self, def_id: Self::CoroutineId) -> rustc_ast_ir::Movability {
@@ -1322,7 +1320,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         def_id: Self::DefId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        let predicates = self.db().generic_predicates_without_parent_ns(def_id.try_into().unwrap());
+        let predicates = self.db().generic_predicates_without_parent(def_id.try_into().unwrap());
         let predicates: Vec<_> = predicates.iter().cloned().collect();
         EarlyBinder::bind(predicates.into_iter())
     }
@@ -1396,7 +1394,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         self,
         impl_id: Self::ImplId,
     ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
-        let trait_ref = self.db().impl_trait_ns(impl_id.0).expect("expected an impl of trait");
+        let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait");
         trait_ref.map_bound(|trait_ref| {
             let clause: Clause<'_> = trait_ref.upcast(self);
             Clauses::new_from_iter(
@@ -1635,7 +1633,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                 |impls| {
                     for i in impls.for_trait(trait_) {
                         use rustc_type_ir::TypeVisitable;
-                        let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| {
+                        let contains_errors = self.db().impl_trait(i).map_or(false, |b| {
                             b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break()
                         });
                         if contains_errors {
@@ -1658,7 +1656,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
                     for fp in fps {
                         for i in impls.for_trait_and_self_ty(trait_, *fp) {
                             use rustc_type_ir::TypeVisitable;
-                            let contains_errors = self.db().impl_trait_ns(i).map_or(false, |b| {
+                            let contains_errors = self.db().impl_trait(i).map_or(false, |b| {
                                 b.skip_binder().visit_with(&mut ContainsTypeErrors).is_break()
                             });
                             if contains_errors {
@@ -1704,7 +1702,7 @@ impl<'db> rustc_type_ir::Interner for DbInterner<'db> {
         impl_id: Self::ImplId,
     ) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> {
         let db = self.db();
-        db.impl_trait_ns(impl_id.0)
+        db.impl_trait(impl_id.0)
             // ImplIds for impls where the trait ref can't be resolved should never reach trait solving
             .expect("invalid impl passed to trait solver")
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
index b24b996b092..f3f74f67c04 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/mapping.rs
@@ -575,6 +575,17 @@ impl<
     }
 }
 
+impl<'db, T: NextSolverToChalk<'db, U>, U: HasInterner<Interner = Interner>>
+    NextSolverToChalk<'db, chalk_ir::Binders<U>> for rustc_type_ir::Binder<DbInterner<'db>, T>
+{
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::Binders<U> {
+        chalk_ir::Binders::new(
+            self.bound_vars().to_chalk(interner),
+            self.skip_binder().to_chalk(interner),
+        )
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKinds {
         BoundVarKinds::new_from_iter(
@@ -584,6 +595,12 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKinds> for chalk_ir::VariableKinds<Inte
     }
 }
 
+impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKinds<Interner>> for BoundVarKinds {
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKinds<Interner> {
+        chalk_ir::VariableKinds::from_iter(Interner, self.iter().map(|v| v.to_chalk(interner)))
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> BoundVarKind {
         match self {
@@ -594,6 +611,18 @@ impl<'db> ChalkToNextSolver<'db, BoundVarKind> for chalk_ir::VariableKind<Intern
     }
 }
 
+impl<'db> NextSolverToChalk<'db, chalk_ir::VariableKind<Interner>> for BoundVarKind {
+    fn to_chalk(self, interner: DbInterner<'db>) -> chalk_ir::VariableKind<Interner> {
+        match self {
+            BoundVarKind::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+            BoundVarKind::Region(_) => chalk_ir::VariableKind::Lifetime,
+            BoundVarKind::Const => {
+                chalk_ir::VariableKind::Const(chalk_ir::TyKind::Error.intern(Interner))
+            }
+        }
+    }
+}
+
 impl<'db> ChalkToNextSolver<'db, GenericArg<'db>> for chalk_ir::GenericArg<Interner> {
     fn to_nextsolver(&self, interner: DbInterner<'db>) -> GenericArg<'db> {
         match self.data(Interner) {
@@ -1233,6 +1262,22 @@ where
     }
 }
 
+impl<'db> NextSolverToChalk<'db, crate::CallableSig> for rustc_type_ir::FnSig<DbInterner<'db>> {
+    fn to_chalk(self, interner: DbInterner<'db>) -> crate::CallableSig {
+        crate::CallableSig {
+            abi: self.abi,
+            is_varargs: self.c_variadic,
+            safety: match self.safety {
+                super::abi::Safety::Safe => chalk_ir::Safety::Safe,
+                super::abi::Safety::Unsafe => chalk_ir::Safety::Unsafe,
+            },
+            params_and_return: triomphe::Arc::from_iter(
+                self.inputs_and_output.iter().map(|ty| convert_ty_for_result(interner, ty)),
+            ),
+        }
+    }
+}
+
 pub fn convert_canonical_args_for_result<'db>(
     interner: DbInterner<'db>,
     args: Canonical<'db, Vec<GenericArg<'db>>>,
@@ -1266,7 +1311,7 @@ pub fn convert_args_for_result<'db>(
     Substitution::from_iter(Interner, substs)
 }
 
-pub(crate) fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
+pub fn convert_ty_for_result<'db>(interner: DbInterner<'db>, ty: Ty<'db>) -> crate::Ty {
     use crate::{Scalar, TyKind};
     use chalk_ir::{FloatTy, IntTy, UintTy};
     match ty.kind() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
index d6214d99156..0bfd2b8003d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/region.rs
@@ -15,7 +15,7 @@ use super::{
     interner::{BoundVarKind, DbInterner, Placeholder},
 };
 
-type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
+pub type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
 
 #[salsa::interned(constructor = new_, debug)]
 pub struct Region<'db> {
@@ -53,6 +53,10 @@ impl<'db> Region<'db> {
         Region::new(interner, RegionKind::ReVar(v))
     }
 
+    pub fn new_erased(interner: DbInterner<'db>) -> Region<'db> {
+        Region::new(interner, RegionKind::ReErased)
+    }
+
     pub fn is_placeholder(&self) -> bool {
         matches!(self.inner(), RegionKind::RePlaceholder(..))
     }
@@ -61,6 +65,10 @@ impl<'db> Region<'db> {
         matches!(self.inner(), RegionKind::ReStatic)
     }
 
+    pub fn is_var(&self) -> bool {
+        matches!(self.inner(), RegionKind::ReVar(_))
+    }
+
     pub fn error(interner: DbInterner<'db>) -> Self {
         Region::new(interner, RegionKind::ReError(ErrorGuaranteed))
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
index 946e57e6cb7..a161423da4d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs
@@ -156,16 +156,16 @@ impl<'db> SolverDelegate for SolverContext<'db> {
             SolverDefId::TypeAliasId(id) => id,
             _ => panic!("Unexpected SolverDefId"),
         };
-        let trait_ref = self
+        let trait_ = self
             .0
             .interner
             .db()
             .impl_trait(impl_id.0)
             // ImplIds for impls where the trait ref can't be resolved should never reach solver
             .expect("invalid impl passed to next-solver")
-            .into_value_and_skipped_binders()
+            .skip_binder()
+            .def_id
             .0;
-        let trait_ = trait_ref.hir_trait_id();
         let trait_data = trait_.trait_items(self.0.interner.db());
         let id =
             impl_id.0.impl_items(self.0.interner.db()).items.iter().find_map(|item| -> Option<_> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
index 70139e86669..a25996ab485 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs
@@ -7,6 +7,7 @@ use hir_def::{GenericDefId, TypeOrConstParamId, TypeParamId};
 use intern::{Interned, Symbol, sym};
 use rustc_abi::{Float, Integer, Size};
 use rustc_ast_ir::{Mutability, try_visit, visit::VisitorResult};
+use rustc_type_ir::TyVid;
 use rustc_type_ir::{
     BoundVar, ClosureKind, CollectAndApply, FlagComputation, Flags, FloatTy, FloatVid, InferTy,
     IntTy, IntVid, Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
@@ -336,6 +337,14 @@ impl<'db> Ty<'db> {
         matches!(self.kind(), TyKind::Tuple(tys) if tys.inner().is_empty())
     }
 
+    #[inline]
+    pub fn ty_vid(self) -> Option<TyVid> {
+        match self.kind() {
+            TyKind::Infer(rustc_type_ir::TyVar(vid)) => Some(vid),
+            _ => None,
+        }
+    }
+
     /// Given a `fn` type, returns an equivalent `unsafe fn` type;
     /// that is, a `fn` type that is equivalent in every way for being
     /// unsafe.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index c0b930e5e12..8587c13e87f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -511,7 +511,6 @@ impl SomeStruct {
                 "struct_signature_shim",
                 "struct_signature_with_source_map_shim",
                 "attrs_shim",
-                "type_for_adt_tracked",
             ]
         "#]],
     );
@@ -609,9 +608,6 @@ fn main() {
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "type_for_adt_tracked",
-                "impl_trait_with_diagnostics_ns_shim",
-                "impl_self_ty_with_diagnostics_ns_shim",
                 "generic_predicates_ns_shim",
                 "value_ty_shim",
                 "generic_predicates_shim",
@@ -700,8 +696,6 @@ fn main() {
                 "trait_impls_in_crate_shim",
                 "impl_trait_with_diagnostics_shim",
                 "impl_self_ty_with_diagnostics_shim",
-                "impl_trait_with_diagnostics_ns_shim",
-                "impl_self_ty_with_diagnostics_ns_shim",
                 "generic_predicates_ns_shim",
                 "generic_predicates_shim",
             ]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index b14ce35aa99..2f8f6664756 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -2050,10 +2050,10 @@ impl dyn Error + Send {
     /// Attempts to downcast the box to a concrete type.
     pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
         let err: Box<dyn Error> = self;
-                               // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + '?>
+                               // ^^^^ expected Box<dyn Error + '?>, got Box<dyn Error + Send + 'static>
                                // FIXME, type mismatch should not occur
         <dyn Error>::downcast(err).map_err(|_| loop {})
-      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + '?>) -> Result<Box<{unknown}>, Box<dyn Error + '?>>
+      //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box<dyn Error + 'static>) -> Result<Box<{unknown}>, Box<dyn Error + 'static>>
     }
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index af5290d7203..4d68179a88b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -14,8 +14,6 @@ fn test() {
     );
 }
 
-// FIXME(next-solver): The never type fallback implemented in r-a no longer works properly because of
-// `Coerce` predicates. We should reimplement fallback like rustc.
 #[test]
 fn infer_never2() {
     check_types(
@@ -26,7 +24,7 @@ fn test() {
     let a = gen();
     if false { a } else { loop {} };
     a;
-} //^ {unknown}
+} //^ !
 "#,
     );
 }
@@ -41,7 +39,7 @@ fn test() {
     let a = gen();
     if false { loop {} } else { a };
     a;
-  //^ {unknown}
+  //^ !
 }
 "#,
     );
@@ -56,7 +54,7 @@ enum Option<T> { None, Some(T) }
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
     a;
-} //^ Option<{unknown}>
+} //^ Option<!>
 "#,
     );
 }
@@ -220,7 +218,7 @@ fn test(a: i32) {
         _ => loop {},
     };
     i;
-} //^ {unknown}
+} //^ !
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 2ba1e2341b2..00835aa0313 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -632,7 +632,7 @@ fn issue_4053_diesel_where_clauses() {
             488..522 '{     ...     }': <SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}> as BoxedDsl<DB>>::Output
             498..502 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
             498..508 'self.order': O
-            498..515 'self.o...into()': dyn QueryFragment<DB> + '?
+            498..515 'self.o...into()': dyn QueryFragment<DB> + 'static
         "#]],
     );
 }
@@ -1951,7 +1951,7 @@ fn main() {
     Alias::Braced;
   //^^^^^^^^^^^^^ {unknown}
     let Alias::Braced = loop {};
-      //^^^^^^^^^^^^^ {unknown}
+      //^^^^^^^^^^^^^ !
   let Alias::Braced(..) = loop {};
     //^^^^^^^^^^^^^^^^^ Enum
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
index ead79a8f5b9..adc35cc9bc1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression/new_solver.rs
@@ -1,6 +1,6 @@
 use expect_test::expect;
 
-use crate::tests::{check_infer, check_no_mismatches};
+use crate::tests::{check_infer, check_no_mismatches, check_types};
 
 #[test]
 fn regression_20365() {
@@ -418,3 +418,57 @@ fn foo() {
         "#]],
     );
 }
+
+#[test]
+fn regression_19637() {
+    check_no_mismatches(
+        r#"
+//- minicore: coerce_unsized
+pub trait Any {}
+
+impl<T: 'static> Any for T {}
+
+pub trait Trait: Any {
+    type F;
+}
+
+pub struct TT {}
+
+impl Trait for TT {
+    type F = f32;
+}
+
+pub fn coercion(x: &mut dyn Any) -> &mut dyn Any {
+    x
+}
+
+fn main() {
+    let mut t = TT {};
+    let tt = &mut t as &mut dyn Trait<F = f32>;
+    let st = coercion(tt);
+}
+    "#,
+    );
+}
+
+#[test]
+fn double_into_iter() {
+    check_types(
+        r#"
+//- minicore: iterator
+
+fn intoiter_issue<A, B>(foo: A)
+where
+    A: IntoIterator<Item = B>,
+    B: IntoIterator<Item = usize>,
+{
+    for x in foo {
+    //  ^ B
+        for m in x {
+        //  ^ usize
+        }
+    }
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 41f8d4ed555..66faac09cc2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -1487,8 +1487,8 @@ fn test(x: Box<dyn Trait<u64>>, y: &dyn Trait<u64>) {
             268..269 'x': Box<dyn Trait<u64> + '?>
             275..276 'y': &'? (dyn Trait<u64> + '?)
             286..287 'z': Box<dyn Trait<u64> + '?>
-            290..293 'bar': fn bar() -> Box<dyn Trait<u64> + '?>
-            290..295 'bar()': Box<dyn Trait<u64> + '?>
+            290..293 'bar': fn bar() -> Box<dyn Trait<u64> + 'static>
+            290..295 'bar()': Box<dyn Trait<u64> + 'static>
             301..302 'x': Box<dyn Trait<u64> + '?>
             301..308 'x.foo()': u64
             314..315 'y': &'? (dyn Trait<u64> + '?)
@@ -1535,7 +1535,7 @@ fn test(s: S<u32, i32>) {
             251..252 's': S<u32, i32>
             267..289 '{     ...z(); }': ()
             273..274 's': S<u32, i32>
-            273..280 's.bar()': &'? (dyn Trait<u32, i32> + '?)
+            273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
             273..286 's.bar().baz()': (u32, i32)
         "#]],
     );
@@ -1568,8 +1568,8 @@ fn test(x: Trait, y: &Trait) -> u64 {
             106..107 'x': dyn Trait + '?
             113..114 'y': &'? (dyn Trait + '?)
             124..125 'z': dyn Trait + '?
-            128..131 'bar': fn bar() -> dyn Trait + '?
-            128..133 'bar()': dyn Trait + '?
+            128..131 'bar': fn bar() -> dyn Trait + 'static
+            128..133 'bar()': dyn Trait + 'static
             139..140 'x': dyn Trait + '?
             139..146 'x.foo()': u64
             152..153 'y': &'? (dyn Trait + '?)
@@ -1597,7 +1597,7 @@ fn main() {
             47..48 '_': &'? (dyn Fn(S) + '?)
             58..60 '{}': ()
             71..105 '{     ...()); }': ()
-            77..78 'f': fn f(&'? (dyn Fn(S) + '?))
+            77..78 'f': fn f(&'? (dyn Fn(S) + 'static))
             77..102 'f(&|nu...foo())': ()
             79..101 '&|numb....foo()': &'? impl Fn(S)
             80..101 '|numbe....foo()': impl Fn(S)
@@ -2952,7 +2952,7 @@ fn test(x: &dyn Foo) {
             34..36 '{}': ()
             46..47 'x': &'? (dyn Foo + '?)
             59..74 '{     foo(x); }': ()
-            65..68 'foo': fn foo(&'? (dyn Foo + '?))
+            65..68 'foo': fn foo(&'? (dyn Foo + 'static))
             65..71 'foo(x)': ()
             69..70 'x': &'? (dyn Foo + '?)
         "#]],
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 8095d702be4..8ac152341e7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -1,4 +1,4 @@
-//! Trait solving using Chalk.
+//! Trait solving using next trait solver.
 
 use core::fmt;
 use std::hash::Hash;
@@ -25,7 +25,7 @@ use crate::{
     db::HirDatabase,
     infer::unify::InferenceTable,
     next_solver::{
-        DbInterner, GenericArg, Predicate, SolverContext, Span,
+        DbInterner, GenericArg, ParamEnv, Predicate, SolverContext, Span,
         infer::{DbInternerInferExt, InferCtxt},
         mapping::{ChalkToNextSolver, convert_canonical_args_for_result},
         util::mini_canonicalize,
@@ -39,21 +39,21 @@ use crate::{
 /// ```
 /// we assume that `T: Default`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct TraitEnvironment {
+pub struct TraitEnvironment<'db> {
     pub krate: Crate,
     pub block: Option<BlockId>,
     // FIXME make this a BTreeMap
     traits_from_clauses: Box<[(Ty, TraitId)]>,
-    pub env: chalk_ir::Environment<Interner>,
+    pub env: ParamEnv<'db>,
 }
 
-impl TraitEnvironment {
+impl<'db> TraitEnvironment<'db> {
     pub fn empty(krate: Crate) -> Arc<Self> {
         Arc::new(TraitEnvironment {
             krate,
             block: None,
             traits_from_clauses: Box::default(),
-            env: chalk_ir::Environment::new(Interner),
+            env: ParamEnv::empty(),
         })
     }
 
@@ -61,7 +61,7 @@ impl TraitEnvironment {
         krate: Crate,
         block: Option<BlockId>,
         traits_from_clauses: Box<[(Ty, TraitId)]>,
-        env: chalk_ir::Environment<Interner>,
+        env: ParamEnv<'db>,
     ) -> Arc<Self> {
         Arc::new(TraitEnvironment { krate, block, traits_from_clauses, env })
     }
@@ -78,10 +78,10 @@ impl TraitEnvironment {
     }
 }
 
-pub(crate) fn normalize_projection_query(
-    db: &dyn HirDatabase,
+pub(crate) fn normalize_projection_query<'db>(
+    db: &'db dyn HirDatabase,
     projection: ProjectionTy,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
 ) -> Ty {
     if projection.substitution.iter(Interner).any(|arg| {
         arg.ty(Interner)
@@ -128,7 +128,7 @@ fn identity_subst(
     chalk_ir::Canonical { binders, value: identity_subst }
 }
 
-/// Solve a trait goal using Chalk.
+/// Solve a trait goal using next trait solver.
 pub(crate) fn trait_solve_query(
     db: &dyn HirDatabase,
     krate: Crate,
@@ -325,7 +325,7 @@ pub fn next_trait_solve_canonical_in_ctxt<'db>(
     }
 }
 
-/// Solve a trait goal using Chalk.
+/// Solve a trait goal using next trait solver.
 pub fn next_trait_solve_in_ctxt<'db, 'a>(
     infer_ctxt: &'a InferCtxt<'db>,
     goal: crate::next_solver::Goal<'db, crate::next_solver::Predicate<'db>>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index 8593dba301b..a17cf378270 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -15,6 +15,8 @@
 
 use crate::db::HirDatabase;
 use crate::generics::{Generics, generics};
+use crate::next_solver::DbInterner;
+use crate::next_solver::mapping::{ChalkToNextSolver, NextSolverToChalk};
 use crate::{
     AliasTy, Const, ConstScalar, DynTyExt, GenericArg, GenericArgData, Interner, Lifetime,
     LifetimeData, Ty, TyKind,
@@ -238,14 +240,15 @@ impl Context<'_> {
             }
             GenericDefId::FunctionId(f) => {
                 let subst = self.generics.placeholder_subst(self.db);
-                self.add_constraints_from_sig(
-                    self.db
-                        .callable_item_signature(f.into())
-                        .substitute(Interner, &subst)
-                        .params_and_return
-                        .iter(),
-                    Variance::Covariant,
-                );
+                let interner = DbInterner::new_with(self.db, None, None);
+                let args: crate::next_solver::GenericArgs<'_> = subst.to_nextsolver(interner);
+                let sig = self
+                    .db
+                    .callable_item_signature(f.into())
+                    .instantiate(interner, args)
+                    .skip_binder()
+                    .to_chalk(interner);
+                self.add_constraints_from_sig(sig.params_and_return.iter(), Variance::Covariant);
             }
             _ => {}
         }
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 833a9ef0306..2bf9bb85e50 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -24,7 +24,7 @@ use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
     ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
     Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, TyBuilder,
-    Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
+    Type, TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
 };
 
 impl HirDisplay for Function {
@@ -437,6 +437,12 @@ impl HirDisplay for Type<'_> {
     }
 }
 
+impl HirDisplay for TypeNs<'_> {
+    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+        self.ty.hir_fmt(f)
+    }
+}
+
 impl HirDisplay for ExternCrateDecl {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 17767955d47..4342624dd64 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -82,7 +82,9 @@ use hir_ty::{
     method_resolution,
     mir::{MutBorrowKind, interpret_mir},
     next_solver::{
-        ClauseKind, DbInterner, GenericArgs, infer::InferCtxt, mapping::ChalkToNextSolver,
+        ClauseKind, DbInterner, GenericArgs,
+        infer::InferCtxt,
+        mapping::{ChalkToNextSolver, NextSolverToChalk, convert_ty_for_result},
     },
     primitive::UintTy,
     traits::FnTrait,
@@ -863,10 +865,13 @@ impl Module {
                     .collect();
 
                 if !missing.is_empty() {
-                    let self_ty = db.impl_self_ty(impl_def.id).substitute(
-                        Interner,
-                        &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db),
-                    );
+                    let interner = DbInterner::new_with(db, None, None);
+                    let args: crate::next_solver::GenericArgs<'_> =
+                        hir_ty::generics::generics(db, impl_def.id.into())
+                            .placeholder_subst(db)
+                            .to_nextsolver(interner);
+                    let self_ty =
+                        db.impl_self_ty(impl_def.id).instantiate(interner, args).to_chalk(interner);
                     let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) =
                         self_ty.kind(Interner)
                     {
@@ -1342,19 +1347,12 @@ impl Field {
         u32::from(self.id.into_raw()) as usize
     }
 
-    /// Returns the type as in the signature of the struct (i.e., with
-    /// placeholder types for type parameters). Only use this in the context of
-    /// the field definition.
-    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
+    /// Returns the type as in the signature of the struct. Only use this in the
+    /// context of the field definition.
+    pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> TypeNs<'db> {
         let var_id = self.parent.into();
-        let generic_def_id: GenericDefId = match self.parent {
-            VariantDef::Struct(it) => it.id.into(),
-            VariantDef::Union(it) => it.id.into(),
-            VariantDef::Variant(it) => it.id.lookup(db).parent.into(),
-        };
-        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
-        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
-        Type::new(db, var_id, ty)
+        let ty = db.field_types_ns(var_id)[self.id].skip_binder();
+        TypeNs::new(db, var_id, ty)
     }
 
     // FIXME: Find better API to also handle const generics
@@ -1384,9 +1382,8 @@ impl Field {
     }
 
     pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        let interner = DbInterner::new_with(db, None, None);
         db.layout_of_ty(
-            self.ty(db).ty.to_nextsolver(interner),
+            self.ty(db).ty,
             db.trait_environment(match hir_def::VariantId::from(self.parent) {
                 hir_def::VariantId::EnumVariantId(id) => {
                     GenericDefId::AdtId(id.lookup(db).parent.into())
@@ -1506,7 +1503,7 @@ impl<'db> InstantiatedStruct<'db> {
         let krate = self.inner.krate(db);
         let interner = DbInterner::new_with(db, Some(krate.base()), None);
 
-        let ty = db.ty_ns(self.inner.id.into());
+        let ty = db.ty(self.inner.id.into());
         TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args))
     }
 }
@@ -1666,7 +1663,7 @@ impl<'db> InstantiatedEnum<'db> {
         let krate = self.inner.krate(db);
         let interner = DbInterner::new_with(db, Some(krate.base()), None);
 
-        let ty = db.ty_ns(self.inner.id.into());
+        let ty = db.ty(self.inner.id.into());
         TypeNs::new(db, self.inner.id, ty.instantiate(interner, self.args))
     }
 }
@@ -1853,7 +1850,8 @@ impl Adt {
                     ParamKind::Lifetime => error_lifetime().cast(Interner),
                 }
             })
-            .build();
+            .build(DbInterner::conjure())
+            .to_chalk(DbInterner::conjure());
         Type::new(db, id, ty)
     }
 
@@ -2288,7 +2286,13 @@ impl Function {
     pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
@@ -2297,8 +2301,14 @@ impl Function {
     pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -2327,8 +2337,14 @@ impl Function {
             parent_id.map(|id| TyBuilder::subst_for_def(db, id, None).fill(&mut filler).build());
         let substs = TyBuilder::subst_for_def(db, self.id, parent_substs).fill(&mut filler).build();
 
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -2338,8 +2354,14 @@ impl Function {
         }
         let resolver = self.id.resolver(db);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
-        let ret_ty = callable_sig.ret().clone();
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ret_ty = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .output()
+            .to_chalk(interner);
         for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
             if let WhereClause::AliasEq(output_eq) = pred.into_value_and_skipped_binders().0 {
                 return Type::new_with_resolver_inner(db, &resolver, output_eq.ty).into();
@@ -2359,7 +2381,13 @@ impl Function {
     pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         callable_sig
             .params()
             .iter()
@@ -2387,7 +2415,13 @@ impl Function {
     pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
         let environment = db.trait_environment(self.id.into());
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
         callable_sig
             .params()
@@ -2437,7 +2471,13 @@ impl Function {
                 GenericArg::new(Interner, GenericArgData::Ty(ty))
             })
             .build();
-        let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.id.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
         callable_sig
             .params()
@@ -2732,8 +2772,13 @@ impl SelfParam {
 
     pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
         let substs = TyBuilder::placeholder_subst(db, self.func);
-        let callable_sig =
-            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.func.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
         Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
@@ -2765,8 +2810,13 @@ impl SelfParam {
         let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
         let substs =
             TyBuilder::subst_for_def(db, self.func, Some(parent_substs)).fill(&mut filler).build();
-        let callable_sig =
-            db.callable_item_signature(self.func.into()).substitute(Interner, &substs);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let callable_sig = db
+            .callable_item_signature(self.func.into())
+            .instantiate(interner, args)
+            .skip_binder()
+            .to_chalk(interner);
         let environment = db.trait_environment(self.func.into());
         let ty = callable_sig.params()[0].clone();
         Type { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
@@ -3770,7 +3820,7 @@ impl GenericDef {
         push_ty_diagnostics(
             db,
             acc,
-            db.generic_predicates_without_parent_with_diagnostics_ns(def).1,
+            db.generic_predicates_without_parent_with_diagnostics(def).1,
             &source_map,
         );
         for (param_id, param) in generics.iter_type_or_consts() {
@@ -3810,12 +3860,12 @@ impl GenericDef {
 pub struct GenericSubstitution<'db> {
     def: GenericDefId,
     subst: Substitution,
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     _pd: PhantomCovariantLifetime<'db>,
 }
 
 impl<'db> GenericSubstitution<'db> {
-    fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment>) -> Self {
+    fn new(def: GenericDefId, subst: Substitution, env: Arc<TraitEnvironment<'db>>) -> Self {
         Self { def, subst, env, _pd: PhantomCovariantLifetime::new() }
     }
 
@@ -4495,21 +4545,23 @@ impl Impl {
     }
 
     pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
-        let trait_ref = db.impl_trait_ns(self.id)?;
+        let trait_ref = db.impl_trait(self.id)?;
         let id = trait_ref.skip_binder().def_id;
         Some(Trait { id: id.0 })
     }
 
     pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
-        let trait_ref = db.impl_trait_ns(self.id)?.instantiate_identity();
+        let trait_ref = db.impl_trait(self.id)?.instantiate_identity();
         let resolver = self.id.resolver(db);
         Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
     }
 
     pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
         let resolver = self.id.resolver(db);
+        let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
         let substs = TyBuilder::placeholder_subst(db, self.id);
-        let ty = db.impl_self_ty(self.id).substitute(Interner, &substs);
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db.impl_self_ty(self.id).instantiate(interner, args).to_chalk(interner);
         Type::new_with_resolver_inner(db, &resolver, ty)
     }
 
@@ -4569,7 +4621,7 @@ impl Impl {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TraitRef<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     trait_ref: hir_ty::next_solver::TraitRef<'db>,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -4792,7 +4844,7 @@ impl CaptureUsageSource {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct Type<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     ty: Ty,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -4830,32 +4882,40 @@ impl<'db> Type<'db> {
     }
 
     fn from_def(db: &'db dyn HirDatabase, def: impl Into<TyDefId> + HasResolver) -> Self {
+        let interner = DbInterner::new_with(db, None, None);
         let ty = db.ty(def.into());
         let substs = TyBuilder::unknown_subst(
             db,
             match def.into() {
                 TyDefId::AdtId(it) => GenericDefId::AdtId(it),
                 TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
-                TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                TyDefId::BuiltinType(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     fn from_def_placeholders(
         db: &'db dyn HirDatabase,
         def: impl Into<TyDefId> + HasResolver,
     ) -> Self {
+        let interner = DbInterner::new_with(db, None, None);
         let ty = db.ty(def.into());
         let substs = TyBuilder::placeholder_subst(
             db,
             match def.into() {
                 TyDefId::AdtId(it) => GenericDefId::AdtId(it),
                 TyDefId::TypeAliasId(it) => GenericDefId::TypeAliasId(it),
-                TyDefId::BuiltinType(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                TyDefId::BuiltinType(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     fn from_value_def(
@@ -4865,6 +4925,7 @@ impl<'db> Type<'db> {
         let Some(ty) = db.value_ty(def.into()) else {
             return Type::new(db, def, TyKind::Error.intern(Interner));
         };
+        let interner = DbInterner::new_with(db, None, None);
         let substs = TyBuilder::unknown_subst(
             db,
             match def.into() {
@@ -4875,10 +4936,13 @@ impl<'db> Type<'db> {
                 ValueTyDefId::EnumVariantId(it) => {
                     GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
                 }
-                ValueTyDefId::StaticId(_) => return Type::new(db, def, ty.skip_binders().clone()),
+                ValueTyDefId::StaticId(_) => {
+                    return Type::new(db, def, ty.skip_binder().to_chalk(interner));
+                }
             },
         );
-        Type::new(db, def, ty.substitute(Interner, &substs))
+        let args: crate::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        Type::new(db, def, ty.instantiate(interner, args).to_chalk(interner))
     }
 
     pub fn new_slice(ty: Self) -> Self {
@@ -5173,7 +5237,14 @@ impl<'db> Type<'db> {
             .build();
 
         let goal = Canonical {
-            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
+            value: hir_ty::InEnvironment::new(
+                &self.env.env.to_chalk(DbInterner::new_with(
+                    db,
+                    Some(self.env.krate),
+                    self.env.block,
+                )),
+                trait_ref.cast(Interner),
+            ),
             binders: CanonicalVarKinds::empty(Interner),
         };
 
@@ -5947,7 +6018,7 @@ impl<'db> Type<'db> {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TypeNs<'db> {
-    env: Arc<TraitEnvironment>,
+    env: Arc<TraitEnvironment<'db>>,
     ty: hir_ty::next_solver::Ty<'db>,
     _pd: PhantomCovariantLifetime<'db>,
 }
@@ -5965,6 +6036,11 @@ impl<'db> TypeNs<'db> {
         TypeNs { env: environment, ty, _pd: PhantomCovariantLifetime::new() }
     }
 
+    pub fn to_type(&self, db: &'db dyn HirDatabase) -> Type<'db> {
+        let interner = DbInterner::new_with(db, Some(self.env.krate), self.env.block);
+        Type { env: self.env.clone(), ty: convert_ty_for_result(interner, self.ty), _pd: self._pd }
+    }
+
     // FIXME: Find better API that also handles const generics
     pub fn impls_trait(&self, infcx: InferCtxt<'db>, trait_: Trait, args: &[TypeNs<'db>]) -> bool {
         let args = GenericArgs::new_from_iter(
@@ -5988,6 +6064,10 @@ impl<'db> TypeNs<'db> {
         let res = hir_ty::traits::next_trait_solve_in_ctxt(&infcx, goal);
         res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes))
     }
+
+    pub fn is_bool(&self) -> bool {
+        matches!(self.ty.kind(), rustc_type_ir::TyKind::Bool)
+    }
 }
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 539b25387ae..c6b7e84dc20 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -46,6 +46,10 @@ use hir_ty::{
     from_assoc_type_id,
     lang_items::lang_items_for_bin_op,
     method_resolution,
+    next_solver::{
+        DbInterner,
+        mapping::{ChalkToNextSolver, NextSolverToChalk},
+    },
 };
 use intern::sym;
 use itertools::Itertools;
@@ -219,7 +223,7 @@ impl<'db> SourceAnalyzer<'db> {
         })
     }
 
-    fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
+    fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment<'db>> {
         self.body_().map(|(def, ..)| def).map_or_else(
             || TraitEnvironment::empty(self.resolver.krate()),
             |def| db.trait_environment_for_body(def),
@@ -372,8 +376,10 @@ impl<'db> SourceAnalyzer<'db> {
     ) -> Option<Callable<'db>> {
         let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
         let (func, substs) = self.infer()?.method_resolution(expr_id)?;
-        let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
-        let ty = Type::new_with_resolver(db, &self.resolver, ty);
+        let interner = DbInterner::new_with(db, None, None);
+        let args: hir_ty::next_solver::GenericArgs<'_> = substs.to_nextsolver(interner);
+        let ty = db.value_ty(func.into())?.instantiate(interner, args);
+        let ty = Type::new_with_resolver(db, &self.resolver, ty.to_chalk(interner));
         let mut res = ty.as_callable(db)?;
         res.is_bound_method = true;
         Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
index 745ae67f309..5af622eaf28 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_braces.rs
@@ -1,3 +1,4 @@
+use either::Either;
 use syntax::{
     AstNode,
     ast::{self, edit_in_place::Indent, syntax_factory::SyntaxFactory},
@@ -59,7 +60,8 @@ enum ParentType {
 }
 
 fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Expr)> {
-    if let Some(match_arm) = ctx.find_node_at_offset::<ast::MatchArm>() {
+    let node = ctx.find_node_at_offset::<Either<ast::MatchArm, ast::ClosureExpr>>()?;
+    if let Either::Left(match_arm) = &node {
         let match_arm_expr = match_arm.expr()?;
 
         if matches!(match_arm_expr, ast::Expr::BlockExpr(_)) {
@@ -67,7 +69,7 @@ fn get_replacement_node(ctx: &AssistContext<'_>) -> Option<(ParentType, ast::Exp
         }
 
         return Some((ParentType::MatchArmExpr, match_arm_expr));
-    } else if let Some(closure_expr) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
+    } else if let Either::Right(closure_expr) = &node {
         let body = closure_expr.body()?;
 
         if matches!(body, ast::Expr::BlockExpr(_)) {
@@ -106,6 +108,33 @@ fn foo() {
     }
 
     #[test]
+    fn suggest_add_braces_for_closure_in_match() {
+        check_assist(
+            add_braces,
+            r#"
+fn foo() {
+    match () {
+        () => {
+            t(|n|$0 n + 100);
+        }
+    }
+}
+"#,
+            r#"
+fn foo() {
+    match () {
+        () => {
+            t(|n| {
+                n + 100
+            });
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn no_assist_for_closures_with_braces() {
         check_assist_not_applicable(
             add_braces,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 4d3212c515f..3910921fbe0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -521,7 +521,7 @@ fn build_pat(
                 hir::StructKind::Tuple => {
                     let mut name_generator = suggest_name::NameGenerator::default();
                     let pats = fields.into_iter().map(|f| {
-                        let name = name_generator.for_type(&f.ty(db), db, edition);
+                        let name = name_generator.for_type(&f.ty(db).to_type(db), db, edition);
                         match name {
                             Some(name) => make::ext::simple_ident_pat(make.name(&name)).into(),
                             None => make.wildcard_pat().into(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 753a9e56c35..53a0a11998a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -6,7 +6,7 @@ use ide_db::{
     syntax_helpers::node_ext::{for_each_tail_expr, walk_expr},
 };
 use syntax::{
-    SyntaxKind, T,
+    NodeOrToken, SyntaxKind, T,
     ast::{
         self, AstNode,
         Expr::BinExpr,
@@ -38,15 +38,27 @@ use crate::{AssistContext, AssistId, Assists, utils::invert_boolean_expression};
 // }
 // ```
 pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let mut bin_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
+    let mut bin_expr = if let Some(not) = ctx.find_token_syntax_at_offset(T![!])
+        && let Some(NodeOrToken::Node(next)) = not.next_sibling_or_token()
+        && let Some(paren) = ast::ParenExpr::cast(next)
+        && let Some(ast::Expr::BinExpr(bin_expr)) = paren.expr()
+    {
+        bin_expr
+    } else {
+        let bin_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
+        let op_range = bin_expr.op_token()?.text_range();
+
+        // Is the cursor on the expression's logical operator?
+        if !op_range.contains_range(ctx.selection_trimmed()) {
+            return None;
+        }
+
+        bin_expr
+    };
+
     let op = bin_expr.op_kind()?;
     let op_range = bin_expr.op_token()?.text_range();
 
-    // Is the cursor on the expression's logical operator?
-    if !op_range.contains_range(ctx.selection_trimmed()) {
-        return None;
-    }
-
     // Walk up the tree while we have the same binary operator
     while let Some(parent_expr) = bin_expr.syntax().parent().and_then(ast::BinExpr::cast) {
         match parent_expr.op_kind() {
@@ -367,6 +379,15 @@ fn f() { !(S <= S || S < S) }
     }
 
     #[test]
+    fn demorgan_on_not() {
+        check_assist(
+            apply_demorgan,
+            "fn f() { $0!(1 || 3 && 4 || 5) }",
+            "fn f() { !1 && !(3 && 4) && !5 }",
+        )
+    }
+
+    #[test]
     fn demorgan_keep_pars_for_op_precedence() {
         check_assist(
             apply_demorgan,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
index 00c7d25b257..1b24f7fe7ff 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bind_unused_param.rs
@@ -2,7 +2,7 @@ use crate::assist_context::{AssistContext, Assists};
 use ide_db::{LineIndexDatabase, assists::AssistId, defs::Definition};
 use syntax::{
     AstNode,
-    ast::{self, edit_in_place::Indent},
+    ast::{self, HasName, edit_in_place::Indent},
 };
 
 // Assist: bind_unused_param
@@ -22,6 +22,7 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
     let param: ast::Param = ctx.find_node_at_offset()?;
 
     let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None };
+    let name = ident_pat.name().filter(|n| !n.text().starts_with('_'))?;
 
     let param_def = {
         let local = ctx.sema.to_def(&ident_pat)?;
@@ -39,14 +40,14 @@ pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
 
     acc.add(
         AssistId::quick_fix("bind_unused_param"),
-        format!("Bind as `let _ = {ident_pat};`"),
+        format!("Bind as `let _ = {name};`"),
         param.syntax().text_range(),
         |builder| {
             let line_index = ctx.db().line_index(ctx.vfs_file_id());
 
             let indent = func.indent_level();
             let text_indent = indent + 1;
-            let mut text = format!("\n{text_indent}let _ = {ident_pat};");
+            let mut text = format!("\n{text_indent}let _ = {name};");
 
             let left_line = line_index.line_col(l_curly_range.end()).line;
             let right_line = line_index.line_col(r_curly_range.start()).line;
@@ -84,6 +85,22 @@ fn foo(y: i32) {
     }
 
     #[test]
+    fn bind_unused_ref_ident_pat() {
+        cov_mark::check!(single_line);
+        check_assist(
+            bind_unused_param,
+            r#"
+fn foo(ref $0y: i32) {}
+"#,
+            r#"
+fn foo(ref y: i32) {
+    let _ = y;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn bind_unused_empty_block_with_newline() {
         check_assist(
             bind_unused_param,
@@ -152,4 +169,14 @@ fn foo(x: i32, $0y: i32) { y; }
 "#,
         );
     }
+
+    #[test]
+    fn keep_underscore_used() {
+        check_assist_not_applicable(
+            bind_unused_param,
+            r#"
+fn foo($0_x: i32, y: i32) {}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index 2ea032fb62b..82213ae3217 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -1,13 +1,12 @@
 use std::iter::once;
 
-use ide_db::{
-    syntax_helpers::node_ext::{is_pattern_cond, single_let},
-    ty_filter::TryEnum,
-};
+use either::Either;
+use hir::{Semantics, TypeInfo};
+use ide_db::{RootDatabase, ty_filter::TryEnum};
 use syntax::{
     AstNode,
-    SyntaxKind::{FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
-    T,
+    SyntaxKind::{CLOSURE_EXPR, FN, FOR_EXPR, LOOP_EXPR, WHILE_EXPR, WHITESPACE},
+    SyntaxNode, T,
     ast::{
         self,
         edit::{AstNodeEdit, IndentLevel},
@@ -44,12 +43,9 @@ use crate::{
 // }
 // ```
 pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    if let Some(let_stmt) = ctx.find_node_at_offset() {
-        let_stmt_to_guarded_return(let_stmt, acc, ctx)
-    } else if let Some(if_expr) = ctx.find_node_at_offset() {
-        if_expr_to_guarded_return(if_expr, acc, ctx)
-    } else {
-        None
+    match ctx.find_node_at_offset::<Either<ast::LetStmt, ast::IfExpr>>()? {
+        Either::Left(let_stmt) => let_stmt_to_guarded_return(let_stmt, acc, ctx),
+        Either::Right(if_expr) => if_expr_to_guarded_return(if_expr, acc, ctx),
     }
 }
 
@@ -73,13 +69,7 @@ fn if_expr_to_guarded_return(
         return None;
     }
 
-    // Check if there is an IfLet that we can handle.
-    let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) {
-        let let_ = single_let(cond)?;
-        (Some(let_.pat()?), let_.expr()?)
-    } else {
-        (None, cond)
-    };
+    let let_chains = flat_let_chain(cond);
 
     let then_block = if_expr.then_branch()?;
     let then_block = then_block.stmt_list()?;
@@ -106,11 +96,7 @@ fn if_expr_to_guarded_return(
 
     let parent_container = parent_block.syntax().parent()?;
 
-    let early_expression: ast::Expr = match parent_container.kind() {
-        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
-        FN => make::expr_return(None),
-        _ => return None,
-    };
+    let early_expression: ast::Expr = early_expression(parent_container, &ctx.sema)?;
 
     then_block.syntax().first_child_or_token().map(|t| t.kind() == T!['{'])?;
 
@@ -132,32 +118,42 @@ fn if_expr_to_guarded_return(
         target,
         |edit| {
             let if_indent_level = IndentLevel::from_node(if_expr.syntax());
-            let replacement = match if_let_pat {
-                None => {
-                    // If.
-                    let new_expr = {
-                        let then_branch =
-                            make::block_expr(once(make::expr_stmt(early_expression).into()), None);
-                        let cond = invert_boolean_expression_legacy(cond_expr);
-                        make::expr_if(cond, then_branch, None).indent(if_indent_level)
-                    };
-                    new_expr.syntax().clone()
-                }
-                Some(pat) => {
+            let replacement = let_chains.into_iter().map(|expr| {
+                if let ast::Expr::LetExpr(let_expr) = &expr
+                    && let (Some(pat), Some(expr)) = (let_expr.pat(), let_expr.expr())
+                {
                     // If-let.
                     let let_else_stmt = make::let_else_stmt(
                         pat,
                         None,
-                        cond_expr,
-                        ast::make::tail_only_block_expr(early_expression),
+                        expr,
+                        ast::make::tail_only_block_expr(early_expression.clone()),
                     );
                     let let_else_stmt = let_else_stmt.indent(if_indent_level);
                     let_else_stmt.syntax().clone()
+                } else {
+                    // If.
+                    let new_expr = {
+                        let then_branch = make::block_expr(
+                            once(make::expr_stmt(early_expression.clone()).into()),
+                            None,
+                        );
+                        let cond = invert_boolean_expression_legacy(expr);
+                        make::expr_if(cond, then_branch, None).indent(if_indent_level)
+                    };
+                    new_expr.syntax().clone()
                 }
-            };
+            });
 
+            let newline = &format!("\n{if_indent_level}");
             let then_statements = replacement
-                .children_with_tokens()
+                .enumerate()
+                .flat_map(|(i, node)| {
+                    (i != 0)
+                        .then(|| make::tokens::whitespace(newline).into())
+                        .into_iter()
+                        .chain(node.children_with_tokens())
+                })
                 .chain(
                     then_block_items
                         .syntax()
@@ -201,11 +197,7 @@ fn let_stmt_to_guarded_return(
             let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
         let parent_container = parent_block.syntax().parent()?;
 
-        match parent_container.kind() {
-            WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
-            FN => make::expr_return(None),
-            _ => return None,
-        }
+        early_expression(parent_container, &ctx.sema)?
     };
 
     acc.add(
@@ -232,6 +224,54 @@ fn let_stmt_to_guarded_return(
     )
 }
 
+fn early_expression(
+    parent_container: SyntaxNode,
+    sema: &Semantics<'_, RootDatabase>,
+) -> Option<ast::Expr> {
+    let return_none_expr = || {
+        let none_expr = make::expr_path(make::ext::ident_path("None"));
+        make::expr_return(Some(none_expr))
+    };
+    if let Some(fn_) = ast::Fn::cast(parent_container.clone())
+        && let Some(fn_def) = sema.to_def(&fn_)
+        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &fn_def.ret_type(sema.db))
+    {
+        return Some(return_none_expr());
+    }
+    if let Some(body) = ast::ClosureExpr::cast(parent_container.clone()).and_then(|it| it.body())
+        && let Some(ret_ty) = sema.type_of_expr(&body).map(TypeInfo::original)
+        && let Some(TryEnum::Option) = TryEnum::from_ty(sema, &ret_ty)
+    {
+        return Some(return_none_expr());
+    }
+
+    Some(match parent_container.kind() {
+        WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
+        FN | CLOSURE_EXPR => make::expr_return(None),
+        _ => return None,
+    })
+}
+
+fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
+    let mut chains = vec![];
+
+    while let ast::Expr::BinExpr(bin_expr) = &expr
+        && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
+        && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
+    {
+        if let Some(last) = chains.pop_if(|last| !matches!(last, ast::Expr::LetExpr(_))) {
+            chains.push(make::expr_bin_op(rhs, ast::BinaryOp::LogicOp(ast::LogicOp::And), last));
+        } else {
+            chains.push(rhs);
+        }
+        expr = lhs;
+    }
+
+    chains.push(expr);
+    chains.reverse();
+    chains
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -269,6 +309,71 @@ fn main() {
     }
 
     #[test]
+    fn convert_inside_fn_return_option() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn ret_option() -> Option<()> {
+    bar();
+    if$0 true {
+        foo();
+
+        // comment
+        bar();
+    }
+}
+"#,
+            r#"
+fn ret_option() -> Option<()> {
+    bar();
+    if false {
+        return None;
+    }
+    foo();
+
+    // comment
+    bar();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_inside_closure() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    let _f = || {
+        bar();
+        if$0 true {
+            foo();
+
+            // comment
+            bar();
+        }
+    }
+}
+"#,
+            r#"
+fn main() {
+    let _f = || {
+        bar();
+        if false {
+            return;
+        }
+        foo();
+
+        // comment
+        bar();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -317,6 +422,82 @@ fn main() {
     }
 
     #[test]
+    fn convert_if_let_result_inside_let() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    let _x = loop {
+        if$0 let Ok(x) = Err(92) {
+            foo(x);
+        }
+    };
+}
+"#,
+            r#"
+fn main() {
+    let _x = loop {
+        let Ok(x) = Err(92) else { continue };
+        foo(x);
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_if_let_chain_result() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 let Ok(x) = Err(92)
+        && x < 30
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    let Ok(x) = Err(92) else { return };
+    if x >= 30 {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if$0 let Ok(x) = Err(92)
+        && x < 30
+        && y < 20
+        && let Some(y) = Some(8)
+    {
+        foo(x, y);
+    }
+}
+"#,
+            r#"
+fn main() {
+    let Ok(x) = Err(92) else { return };
+    if !(x < 30 && y < 20) {
+        return;
+    }
+    let Some(y) = Some(8) else { return };
+    foo(x, y);
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_ok_inside_fn() {
         check_assist(
             convert_to_guarded_return,
@@ -561,6 +742,32 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_stmt_inside_fn_return_option() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn foo() -> Option<i32> {
+    None
+}
+
+fn ret_option() -> Option<i32> {
+    let x$0 = foo();
+}
+"#,
+            r#"
+fn foo() -> Option<i32> {
+    None
+}
+
+fn ret_option() -> Option<i32> {
+    let Some(x) = foo() else { return None };
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_let_stmt_inside_loop() {
         check_assist(
             convert_to_guarded_return,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index 397327cb4ff..27755db93c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -7,7 +7,7 @@ use ide_db::{
     search::{FileReference, SearchScope},
 };
 use itertools::Itertools;
-use syntax::ast::syntax_factory::SyntaxFactory;
+use syntax::ast::{HasName, syntax_factory::SyntaxFactory};
 use syntax::syntax_editor::SyntaxEditor;
 use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast};
 
@@ -71,13 +71,14 @@ fn destructure_struct_binding_impl(
 
 struct StructEditData {
     ident_pat: ast::IdentPat,
+    name: ast::Name,
     kind: hir::StructKind,
     struct_def_path: hir::ModPath,
     visible_fields: Vec<hir::Field>,
     usages: Vec<FileReference>,
     names_in_scope: FxHashSet<SmolStr>,
     has_private_members: bool,
-    is_nested: bool,
+    need_record_field_name: bool,
     is_ref: bool,
     edition: Edition,
 }
@@ -114,7 +115,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
     }
 
     let is_ref = ty.is_reference();
-    let is_nested = ident_pat.syntax().parent().and_then(ast::RecordPatField::cast).is_some();
+    let need_record_field_name = ident_pat
+        .syntax()
+        .parent()
+        .and_then(ast::RecordPatField::cast)
+        .is_some_and(|field| field.colon_token().is_none());
 
     let usages = ctx
         .sema
@@ -133,6 +138,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
     let names_in_scope = get_names_in_scope(ctx, &ident_pat, &usages).unwrap_or_default();
 
     Some(StructEditData {
+        name: ident_pat.name()?,
         ident_pat,
         kind,
         struct_def_path,
@@ -140,7 +146,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
         has_private_members,
         visible_fields,
         names_in_scope,
-        is_nested,
+        need_record_field_name,
         is_ref,
         edition: module.krate().edition(ctx.db()),
     })
@@ -177,6 +183,7 @@ fn destructure_pat(
     field_names: &[(SmolStr, SmolStr)],
 ) {
     let ident_pat = &data.ident_pat;
+    let name = &data.name;
 
     let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition);
     let is_ref = ident_pat.ref_token().is_some();
@@ -194,9 +201,9 @@ fn destructure_pat(
         hir::StructKind::Record => {
             let fields = field_names.iter().map(|(old_name, new_name)| {
                 // Use shorthand syntax if possible
-                if old_name == new_name && !is_mut {
+                if old_name == new_name {
                     make.record_pat_field_shorthand(
-                        make.ident_pat(false, false, make.name(old_name)).into(),
+                        make.ident_pat(is_ref, is_mut, make.name(old_name)).into(),
                     )
                 } else {
                     make.record_pat_field(
@@ -215,8 +222,8 @@ fn destructure_pat(
 
     // If the binding is nested inside a record, we need to wrap the new
     // destructured pattern in a non-shorthand record field
-    let destructured_pat = if data.is_nested {
-        make.record_pat_field(make.name_ref(&ident_pat.to_string()), new_pat).syntax().clone()
+    let destructured_pat = if data.need_record_field_name {
+        make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone()
     } else {
         new_pat.syntax().clone()
     };
@@ -288,7 +295,7 @@ fn build_usage_edit(
         Some(field_expr) => Some({
             let field_name: SmolStr = field_expr.name_ref()?.to_string().into();
             let new_field_name = field_names.get(&field_name)?;
-            let new_expr = make.expr_path(ast::make::ext::ident_path(new_field_name));
+            let new_expr = ast::make::expr_path(ast::make::ext::ident_path(new_field_name));
 
             // If struct binding is a reference, we might need to deref field usages
             if data.is_ref {
@@ -298,7 +305,7 @@ fn build_usage_edit(
                     ref_data.wrap_expr(new_expr).syntax().clone_for_update(),
                 )
             } else {
-                (field_expr.syntax().clone(), new_expr.syntax().clone())
+                (field_expr.syntax().clone(), new_expr.syntax().clone_for_update())
             }
         }),
         None => Some((
@@ -579,7 +586,7 @@ mod tests {
             struct Foo { bar: i32, baz: i32 }
 
             fn main() {
-                let Foo { bar: mut bar, baz: mut baz } = Foo { bar: 1, baz: 2 };
+                let Foo { mut bar, mut baz } = Foo { bar: 1, baz: 2 };
                 let bar2 = bar;
                 let baz2 = &baz;
             }
@@ -588,6 +595,86 @@ mod tests {
     }
 
     #[test]
+    fn mut_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { mut $0foo }: Bar) {}
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { mut x } }: Bar) {}
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { ref $0foo }: Bar) {
+                let _ = foo.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_mut_record_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { ref mut $0foo }: Bar) {
+                let _ = foo.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_mut_record_renamed_field() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: ref mut $0foo1 }: Bar) {
+                let _ = foo1.x;
+            }
+            "#,
+            r#"
+            struct Foo { x: () }
+            struct Bar { foo: Foo }
+            fn f(Bar { foo: Foo { ref mut x } }: Bar) {
+                let _ = *x;
+            }
+            "#,
+        )
+    }
+
+    #[test]
     fn mut_ref() {
         check_assist(
             destructure_struct_binding,
@@ -611,6 +698,52 @@ mod tests {
     }
 
     #[test]
+    fn ref_not_add_parenthesis_and_deref_record() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo { bar: i32, baz: i32 }
+
+            fn main() {
+                let $0foo = &Foo { bar: 1, baz: 2 };
+                let _ = &foo.bar;
+            }
+            "#,
+            r#"
+            struct Foo { bar: i32, baz: i32 }
+
+            fn main() {
+                let Foo { bar, baz } = &Foo { bar: 1, baz: 2 };
+                let _ = bar;
+            }
+            "#,
+        )
+    }
+
+    #[test]
+    fn ref_not_add_parenthesis_and_deref_tuple() {
+        check_assist(
+            destructure_struct_binding,
+            r#"
+            struct Foo(i32, i32);
+
+            fn main() {
+                let $0foo = &Foo(1, 2);
+                let _ = &foo.0;
+            }
+            "#,
+            r#"
+            struct Foo(i32, i32);
+
+            fn main() {
+                let Foo(_0, _1) = &Foo(1, 2);
+                let _ = _0;
+            }
+            "#,
+        )
+    }
+
+    #[test]
     fn record_struct_name_collision() {
         check_assist(
             destructure_struct_binding,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
index c80b78fd970..b746099e727 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs
@@ -24,7 +24,7 @@ use crate::{AssistContext, AssistId, Assists};
 // struct Bar { y: Y, z: Z }
 //
 // fn foo(bar: Bar) {
-//     let Bar { y, z  } = bar;
+//     let Bar { y, z } = bar;
 // }
 // ```
 fn expand_record_rest_pattern(
@@ -53,18 +53,17 @@ fn expand_record_rest_pattern(
         |builder| {
             let make = SyntaxFactory::with_mappings();
             let mut editor = builder.make_editor(rest_pat.syntax());
-            let new_field_list = make.record_pat_field_list(old_field_list.fields(), None);
-            for (f, _) in missing_fields.iter() {
-                let field = make.record_pat_field_shorthand(
+            let new_fields = old_field_list.fields().chain(missing_fields.iter().map(|(f, _)| {
+                make.record_pat_field_shorthand(
                     make.ident_pat(
                         false,
                         false,
                         make.name(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()),
                     )
                     .into(),
-                );
-                new_field_list.add_field(field);
-            }
+                )
+            }));
+            let new_field_list = make.record_pat_field_list(new_fields, None);
 
             editor.replace(old_field_list.syntax(), new_field_list.syntax());
 
@@ -114,9 +113,7 @@ fn expand_tuple_struct_rest_pattern(
     };
 
     let rest_pat = rest_pat.into();
-    let mut pats = pat.fields();
-    let prefix_count = pats.by_ref().position(|p| p == rest_pat)?;
-    let suffix_count = pats.count();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?;
 
     if fields.len().saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
         cov_mark::hit!(no_missing_fields_tuple_struct);
@@ -142,16 +139,13 @@ fn expand_tuple_struct_rest_pattern(
                 pat.fields()
                     .take(prefix_count)
                     .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| {
-                        make.ident_pat(
-                            false,
-                            false,
-                            match name_gen.for_type(&f.ty(ctx.sema.db), ctx.sema.db, ctx.edition())
-                            {
-                                Some(name) => make.name(&name),
-                                None => make.name(&format!("_{}", f.index())),
-                            },
+                        gen_unnamed_pat(
+                            ctx,
+                            &make,
+                            &mut name_gen,
+                            &f.ty(ctx.db()).to_type(ctx.sema.db),
+                            f.index(),
                         )
-                        .into()
                     }))
                     .chain(pat.fields().skip(prefix_count + 1)),
             );
@@ -164,6 +158,134 @@ fn expand_tuple_struct_rest_pattern(
     )
 }
 
+// Assist: expand_tuple_rest_pattern
+//
+// Fills fields by replacing rest pattern in tuple patterns.
+//
+// ```
+// fn foo(bar: (char, i32, i32)) {
+//     let (ch, ..$0) = bar;
+// }
+// ```
+// ->
+// ```
+// fn foo(bar: (char, i32, i32)) {
+//     let (ch, _1, _2) = bar;
+// }
+// ```
+fn expand_tuple_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    pat: ast::TuplePat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
+    let fields = ctx.sema.type_of_pat(&pat.clone().into())?.original.tuple_fields(ctx.db());
+    let len = fields.len();
+
+    let rest_pat = rest_pat.into();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.fields())?;
+
+    if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
+        cov_mark::hit!(no_missing_fields_tuple);
+        return None;
+    }
+
+    let old_range = ctx.sema.original_range_opt(pat.syntax())?;
+    if old_range.file_id != ctx.file_id() {
+        return None;
+    }
+
+    acc.add(
+        AssistId::refactor_rewrite("expand_tuple_rest_pattern"),
+        "Fill tuple fields",
+        rest_pat.syntax().text_range(),
+        |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(rest_pat.syntax());
+
+            let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax()));
+            let new_pat = make.tuple_pat(
+                pat.fields()
+                    .take(prefix_count)
+                    .chain(fields[prefix_count..len - suffix_count].iter().enumerate().map(
+                        |(index, ty)| {
+                            gen_unnamed_pat(ctx, &make, &mut name_gen, ty, prefix_count + index)
+                        },
+                    ))
+                    .chain(pat.fields().skip(prefix_count + 1)),
+            );
+
+            editor.replace(pat.syntax(), new_pat.syntax());
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
+// Assist: expand_slice_rest_pattern
+//
+// Fills fields by replacing rest pattern in slice patterns.
+//
+// ```
+// fn foo(bar: [i32; 3]) {
+//     let [first, ..$0] = bar;
+// }
+// ```
+// ->
+// ```
+// fn foo(bar: [i32; 3]) {
+//     let [first, _1, _2] = bar;
+// }
+// ```
+fn expand_slice_rest_pattern(
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+    pat: ast::SlicePat,
+    rest_pat: ast::RestPat,
+) -> Option<()> {
+    let (ty, len) = ctx.sema.type_of_pat(&pat.clone().into())?.original.as_array(ctx.db())?;
+
+    let rest_pat = rest_pat.into();
+    let (prefix_count, suffix_count) = calculate_counts(&rest_pat, pat.pats())?;
+
+    if len.saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 {
+        cov_mark::hit!(no_missing_fields_slice);
+        return None;
+    }
+
+    let old_range = ctx.sema.original_range_opt(pat.syntax())?;
+    if old_range.file_id != ctx.file_id() {
+        return None;
+    }
+
+    acc.add(
+        AssistId::refactor_rewrite("expand_slice_rest_pattern"),
+        "Fill slice fields",
+        rest_pat.syntax().text_range(),
+        |builder| {
+            let make = SyntaxFactory::with_mappings();
+            let mut editor = builder.make_editor(rest_pat.syntax());
+
+            let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax()));
+            let new_pat = make.slice_pat(
+                pat.pats()
+                    .take(prefix_count)
+                    .chain(
+                        (prefix_count..len - suffix_count)
+                            .map(|index| gen_unnamed_pat(ctx, &make, &mut name_gen, &ty, index)),
+                    )
+                    .chain(pat.pats().skip(prefix_count + 1)),
+            );
+
+            editor.replace(pat.syntax(), new_pat.syntax());
+
+            editor.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), editor);
+        },
+    )
+}
+
 pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let rest_pat = ctx.find_node_at_offset::<ast::RestPat>()?;
     let parent = rest_pat.syntax().parent()?;
@@ -171,15 +293,40 @@ pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         match parent {
             ast::RecordPatFieldList(it) => expand_record_rest_pattern(acc, ctx, it.syntax().parent().and_then(ast::RecordPat::cast)?, rest_pat),
             ast::TupleStructPat(it) => expand_tuple_struct_rest_pattern(acc, ctx, it, rest_pat),
-            // FIXME
-            // ast::TuplePat(it) => (),
-            // FIXME
-            // ast::SlicePat(it) => (),
+            ast::TuplePat(it) => expand_tuple_rest_pattern(acc, ctx, it, rest_pat),
+            ast::SlicePat(it) => expand_slice_rest_pattern(acc, ctx, it, rest_pat),
             _ => None,
         }
     }
 }
 
+fn gen_unnamed_pat(
+    ctx: &AssistContext<'_>,
+    make: &SyntaxFactory,
+    name_gen: &mut NameGenerator,
+    ty: &hir::Type<'_>,
+    index: usize,
+) -> ast::Pat {
+    make.ident_pat(
+        false,
+        false,
+        match name_gen.for_type(ty, ctx.sema.db, ctx.edition()) {
+            Some(name) => make.name(&name),
+            None => make.name(&format!("_{index}")),
+        },
+    )
+    .into()
+}
+
+fn calculate_counts(
+    rest_pat: &ast::Pat,
+    mut pats: ast::AstChildren<ast::Pat>,
+) -> Option<(usize, usize)> {
+    let prefix_count = pats.by_ref().position(|p| p == *rest_pat)?;
+    let suffix_count = pats.count();
+    Some((prefix_count, suffix_count))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -211,7 +358,7 @@ enum Foo {
 fn bar(foo: Foo) {
     match foo {
         Foo::A(_) => false,
-        Foo::B{ y, z  } => true,
+        Foo::B{ y, z } => true,
     };
 }
 "#,
@@ -272,7 +419,7 @@ struct Bar {
 }
 
 fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
+    let Bar { y, z } = bar;
 }
 "#,
         );
@@ -350,6 +497,79 @@ fn foo(bar: Bar) {
     }
 
     #[test]
+    fn fill_tuple_with_fields() {
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0) = bar;
+}
+"#,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, _2) = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0, end) = bar;
+}
+"#,
+            r#"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, end) = bar;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn fill_array_with_fields() {
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, ..$0] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, _1, _2, _3] = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, ..$0] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, _2, _3] = bar;
+}
+"#,
+        );
+        check_assist(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, ..$0, end] = bar;
+}
+"#,
+            r#"
+fn foo(bar: [i32; 4]) {
+    let [first, second, _2, end] = bar;
+}
+"#,
+        );
+    }
+
+    #[test]
     fn fill_fields_struct_generated_by_macro() {
         check_assist(
             expand_rest_pattern,
@@ -376,7 +596,7 @@ macro_rules! position {
 position!(usize);
 
 fn macro_call(pos: Pos) {
-    let Pos { x, y  } = pos;
+    let Pos { x, y } = pos;
 }
 "#,
         );
@@ -420,7 +640,7 @@ enum_gen!(usize);
 fn macro_call(foo: Foo) {
     match foo {
         Foo::A(_) => false,
-        Foo::B{ x, y  } => true,
+        Foo::B{ x, y } => true,
     }
 }
 "#,
@@ -484,6 +704,8 @@ fn bar(foo: Foo) {
         // This is still possible even though it's meaningless
         cov_mark::check!(no_missing_fields);
         cov_mark::check!(no_missing_fields_tuple_struct);
+        cov_mark::check!(no_missing_fields_tuple);
+        cov_mark::check!(no_missing_fields_slice);
         check_assist_not_applicable(
             expand_rest_pattern,
             r#"
@@ -523,5 +745,21 @@ fn foo(bar: Bar) {
 }
 "#,
         );
+        check_assist_not_applicable(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: (i32, i32)) {
+    let (y, ..$0, z) = bar;
+}
+"#,
+        );
+        check_assist_not_applicable(
+            expand_rest_pattern,
+            r#"
+fn foo(bar: [i32; 2]) {
+    let [y, ..$0, z] = bar;
+}
+"#,
+        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index bd88e8b09ce..da596262962 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -285,7 +285,7 @@ fn peel_parens(mut expr: ast::Expr) -> ast::Expr {
 /// In general that's true for any expression, but in some cases that would produce invalid code.
 fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> {
     match node.kind() {
-        SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR => None,
+        SyntaxKind::PATH_EXPR | SyntaxKind::LOOP_EXPR | SyntaxKind::LET_EXPR => None,
         SyntaxKind::BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()),
         SyntaxKind::BLOCK_EXPR => {
@@ -1404,6 +1404,25 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_let_expr() {
+        check_assist_by_label(
+            extract_variable,
+            r#"
+fn main() {
+    if $0let$0 Some(x) = Some(2+2) {}
+}
+"#,
+            r#"
+fn main() {
+    let $0var_name = Some(2+2);
+    if let Some(x) = var_name {}
+}
+"#,
+            "Extract into variable",
+        );
+    }
+
+    #[test]
     fn extract_var_for_cast() {
         check_assist_by_label(
             extract_variable,
@@ -1739,6 +1758,14 @@ fn main() {
     }
 
     #[test]
+    fn extract_var_for_let_expr_not_applicable() {
+        check_assist_not_applicable(
+            extract_variable,
+            "fn main() { if $0let Some(x) = Some(2+2) {} }",
+        );
+    }
+
+    #[test]
     fn extract_var_unit_expr_not_applicable() {
         check_assist_not_applicable(
             extract_variable,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
index 6198dbc4ed9..056edb00b68 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs
@@ -39,6 +39,9 @@ pub(crate) fn generate_default_from_enum_variant(
         cov_mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
         return None;
     }
+    if !variant.syntax().text_range().contains_range(ctx.selection_trimmed()) {
+        return None;
+    }
 
     if existing_default_impl(&ctx.sema, &variant).is_some() {
         cov_mark::hit!(test_gen_default_impl_already_exists);
@@ -115,6 +118,49 @@ impl Default for Variant {
     }
 
     #[test]
+    fn test_generate_default_selected_variant() {
+        check_assist(
+            generate_default_from_enum_variant,
+            r#"
+//- minicore: default
+enum Variant {
+    Undefined,
+    $0Minor$0,
+    Major,
+}
+"#,
+            r#"
+enum Variant {
+    Undefined,
+    Minor,
+    Major,
+}
+
+impl Default for Variant {
+    fn default() -> Self {
+        Self::Minor
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_generate_default_not_applicable_with_multiple_variant_selection() {
+        check_assist_not_applicable(
+            generate_default_from_enum_variant,
+            r#"
+//- minicore: default
+enum Variant {
+    Undefined,
+    $0Minor,
+    M$0ajor,
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_generate_default_already_implemented() {
         cov_mark::check!(test_gen_default_impl_already_exists);
         check_assist_not_applicable(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
index d198870b023..7576d2fab97 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/invert_if.rs
@@ -125,6 +125,18 @@ mod tests {
     }
 
     #[test]
+    fn invert_if_doesnt_apply_with_if_let_chain() {
+        check_assist_not_applicable(
+            invert_if,
+            "fn f() { i$0f x && let Some(_) = Some(1) { 1 } else { 0 } }",
+        );
+        check_assist_not_applicable(
+            invert_if,
+            "fn f() { i$0f let Some(_) = Some(1) && x { 1 } else { 0 } }",
+        );
+    }
+
+    #[test]
     fn invert_if_option_case() {
         check_assist(
             invert_if,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
index 21debf6745a..00902fafe82 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/pull_assignment_up.rs
@@ -53,6 +53,10 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     };
 
     let tgt: ast::Expr = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() {
+        let if_expr = std::iter::successors(Some(if_expr), |it| {
+            it.syntax().parent().and_then(ast::IfExpr::cast)
+        })
+        .last()?;
         collector.collect_if(&if_expr)?;
         if_expr.into()
     } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() {
@@ -238,6 +242,37 @@ fn foo() {
     }
 
     #[test]
+    fn test_pull_assignment_up_inner_if() {
+        check_assist(
+            pull_assignment_up,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    if true {
+        a = 2;
+    } else if true {
+        $0a = 3;
+    } else {
+        a = 4;
+    }
+}"#,
+            r#"
+fn foo() {
+    let mut a = 1;
+
+    a = if true {
+        2
+    } else if true {
+        3
+    } else {
+        4
+    };
+}"#,
+        );
+    }
+
+    #[test]
     fn test_pull_assignment_up_match() {
         check_assist(
             pull_assignment_up,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 414f6746d44..08779a3ed1f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -83,7 +83,9 @@ fn compute_dbg_replacement(
     let input_expressions = input_expressions
         .into_iter()
         .filter_map(|(is_sep, group)| (!is_sep).then_some(group))
-        .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""), Edition::CURRENT))
+        .map(|tokens| tokens.collect::<Vec<_>>())
+        .filter(|tokens| !tokens.iter().all(|it| it.kind().is_trivia()))
+        .map(|tokens| syntax::hacks::parse_expr_from_str(&tokens.iter().join(""), Edition::CURRENT))
         .collect::<Option<Vec<ast::Expr>>>()?;
 
     let parent = macro_expr.syntax().parent()?;
@@ -268,6 +270,8 @@ fn foo() {
     dbg!('x');
     dbg!(&n);
     dbg!(n);
+    dbg!(n,);
+    dbg!(n, );
     // needless comment
     dbg!("foo");$0
 }
@@ -282,6 +286,17 @@ fn foo() {
     }
 
     #[test]
+    fn test_remove_trailing_comma_dbg() {
+        check("$0dbg!(1 + 1,)", "1 + 1");
+        check("$0dbg!(1 + 1, )", "1 + 1");
+        check("$0dbg!(1 + 1,\n)", "1 + 1");
+        check("$0dbg!(1 + 1, 2 + 3)", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3 )", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3, )", "(1 + 1, 2 + 3)");
+        check("$0dbg!(1 + 1, 2 + 3 ,)", "(1 + 1, 2 + 3)");
+    }
+
+    #[test]
     fn test_remove_dbg_not_applicable() {
         check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}");
         check_assist_not_applicable(remove_dbg, "fn main() {$0dbg(5, 6, 7)}");
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
index 440ab4d4604..a3fb851fb0e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_arith_op.rs
@@ -1,7 +1,7 @@
 use ide_db::assists::{AssistId, GroupLabel};
 use syntax::{
-    AstNode, TextRange,
-    ast::{self, ArithOp, BinaryOp},
+    AstNode,
+    ast::{self, ArithOp, BinaryOp, syntax_factory::SyntaxFactory},
 };
 
 use crate::assist_context::{AssistContext, Assists};
@@ -71,24 +71,31 @@ pub(crate) fn replace_arith_with_wrapping(
 
 fn replace_arith(acc: &mut Assists, ctx: &AssistContext<'_>, kind: ArithKind) -> Option<()> {
     let (lhs, op, rhs) = parse_binary_op(ctx)?;
+    let op_expr = lhs.syntax().parent()?;
 
     if !is_primitive_int(ctx, &lhs) || !is_primitive_int(ctx, &rhs) {
         return None;
     }
 
-    let start = lhs.syntax().text_range().start();
-    let end = rhs.syntax().text_range().end();
-    let range = TextRange::new(start, end);
-
     acc.add_group(
         &GroupLabel("Replace arithmetic...".into()),
         kind.assist_id(),
         kind.label(),
-        range,
+        op_expr.text_range(),
         |builder| {
+            let mut edit = builder.make_editor(rhs.syntax());
+            let make = SyntaxFactory::with_mappings();
             let method_name = kind.method_name(op);
 
-            builder.replace(range, format!("{lhs}.{method_name}({rhs})"))
+            let needs_parentheses =
+                lhs.precedence().needs_parentheses_in(ast::prec::ExprPrecedence::Postfix);
+            let receiver = if needs_parentheses { make.expr_paren(lhs).into() } else { lhs };
+            let arith_expr =
+                make.expr_method_call(receiver, make.name_ref(&method_name), make.arg_list([rhs]));
+            edit.replace(op_expr, arith_expr.syntax());
+
+            edit.add_mappings(make.finish_with_mappings());
+            builder.add_file_edits(ctx.vfs_file_id(), edit);
         },
     )
 }
@@ -228,6 +235,23 @@ fn main() {
     }
 
     #[test]
+    fn replace_arith_with_wrapping_add_add_parenthesis() {
+        check_assist(
+            replace_arith_with_wrapping,
+            r#"
+fn main() {
+    let x = 1*x $0+ 2;
+}
+"#,
+            r#"
+fn main() {
+    let x = (1*x).wrapping_add(2);
+}
+"#,
+        )
+    }
+
+    #[test]
     fn replace_arith_not_applicable_with_non_empty_selection() {
         check_assist_not_applicable(
             replace_arith_with_checked,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index dd244375dc9..3b815a467bc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -328,7 +328,14 @@ fn pick_pattern_and_expr_order(
         (pat, pat2) => match (binds_name(sema, &pat), binds_name(sema, &pat2)) {
             (true, true) => return None,
             (true, false) => (pat, guard, expr, expr2),
-            (false, true) => (pat2, guard2, expr2, expr),
+            (false, true) => {
+                // This pattern triggers an invalid transformation.
+                // See issues #11373, #19443
+                if let ast::Pat::IdentPat(_) = pat2 {
+                    return None;
+                }
+                (pat2, guard2, expr2, expr)
+            }
             _ if is_sad_pat(sema, &pat) => (pat2, guard2, expr2, expr),
             (false, false) => (pat, guard, expr, expr2),
         },
@@ -1892,4 +1899,19 @@ fn main() {
 "#,
         )
     }
+
+    #[test]
+    fn test_replace_match_with_if_let_not_applicable_pat2_is_ident_pat() {
+        check_assist_not_applicable(
+            replace_match_with_if_let,
+            r"
+fn test(a: i32) {
+    match$0 a {
+        1 => code(),
+        other => code(other),
+    }
+}
+",
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
index 5ef8ba46b9e..f507cae1bb0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs
@@ -31,6 +31,9 @@ pub(crate) fn replace_is_method_with_if_let_method(
         ast::Expr::MethodCallExpr(call) => call,
         _ => return None,
     };
+    if ctx.offset() > if_expr.then_branch()?.stmt_list()?.l_curly_token()?.text_range().end() {
+        return None;
+    }
 
     let name_ref = call_expr.name_ref()?;
     match name_ref.text().as_str() {
@@ -191,4 +194,19 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn replace_is_some_with_if_let_some_not_applicable_after_l_curly() {
+        check_assist_not_applicable(
+            replace_is_method_with_if_let_method,
+            r#"
+fn main() {
+    let x = Some(1);
+    if x.is_some() {
+        ()$0
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 91348be97eb..e7f91ff3fbc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1035,7 +1035,41 @@ fn foo(bar: Bar) {
 struct Bar { y: Y, z: Z }
 
 fn foo(bar: Bar) {
-    let Bar { y, z  } = bar;
+    let Bar { y, z } = bar;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_expand_slice_rest_pattern() {
+    check_doc_test(
+        "expand_slice_rest_pattern",
+        r#####"
+fn foo(bar: [i32; 3]) {
+    let [first, ..$0] = bar;
+}
+"#####,
+        r#####"
+fn foo(bar: [i32; 3]) {
+    let [first, _1, _2] = bar;
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_expand_tuple_rest_pattern() {
+    check_doc_test(
+        "expand_tuple_rest_pattern",
+        r#####"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, ..$0) = bar;
+}
+"#####,
+        r#####"
+fn foo(bar: (char, i32, i32)) {
+    let (ch, _1, _2) = bar;
 }
 "#####,
     )
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index e36e0e57045..eb2bb31f963 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -691,6 +691,9 @@ pub(super) fn complete_name(
         NameKind::RecordField => {
             field::complete_field_list_record_variant(acc, ctx);
         }
+        NameKind::TypeParam => {
+            acc.add_keyword_snippet(ctx, "const", "const $1: $0");
+        }
         NameKind::ConstParam
         | NameKind::Enum
         | NameKind::MacroDef
@@ -700,7 +703,6 @@ pub(super) fn complete_name(
         | NameKind::Static
         | NameKind::Struct
         | NameKind::Trait
-        | NameKind::TypeParam
         | NameKind::Union
         | NameKind::Variant => (),
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index c542e140df5..e174b0c8922 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -70,7 +70,7 @@ pub(crate) fn complete_known_attribute_input(
 
             lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
         }
-        ["cfg"] => cfg::complete_cfg(acc, ctx),
+        ["cfg"] | ["cfg_attr"] => cfg::complete_cfg(acc, ctx),
         ["macro_use"] => macro_use::complete_macro_use(
             acc,
             ctx,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
index 1676a8467c8..b2e8efde8be 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -53,15 +53,33 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) {
                 acc.add(item.build(ctx.db));
             }),
         },
-        None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| {
-            let s = s.as_str();
-            let item =
-                CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition);
-            acc.add(item.build(ctx.db));
-        }),
+        None => ctx
+            .krate
+            .potential_cfg(ctx.db)
+            .get_cfg_keys()
+            .unique()
+            .map(|s| (s.as_str(), ""))
+            .chain(CFG_CONDITION.iter().copied())
+            .for_each(|(s, snippet)| {
+                let mut item = CompletionItem::new(
+                    SymbolKind::BuiltinAttr,
+                    ctx.source_range(),
+                    s,
+                    ctx.edition,
+                );
+                if let Some(cap) = ctx.config.snippet_cap
+                    && !snippet.is_empty()
+                {
+                    item.insert_snippet(cap, snippet);
+                }
+                acc.add(item.build(ctx.db));
+            }),
     }
 }
 
+const CFG_CONDITION: &[(&str, &str)] =
+    &[("all", "all($0)"), ("any", "any($0)"), ("not", "not($0)")];
+
 const KNOWN_ARCH: [&str; 20] = [
     "aarch64",
     "arm",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index a7df0ab3863..080875e0163 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -59,6 +59,7 @@ pub(crate) fn complete_expr_path(
         in_block_expr,
         in_breakable,
         after_if_expr,
+        before_else_kw,
         in_condition,
         incomplete_let,
         after_incomplete_let,
@@ -386,7 +387,7 @@ pub(crate) fn complete_expr_path(
                         add_keyword("let", "let $1 = $0;");
                     }
 
-                    if after_if_expr || after_incomplete_let {
+                    if !before_else_kw && (after_if_expr || after_incomplete_let) {
                         add_keyword("else", "else {\n    $0\n}");
                     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index 36f38a70db6..2f5abd18934 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -28,7 +28,11 @@ pub(crate) fn complete_record_pattern_fields(
                     record_pat.record_pat_field_list().and_then(|fl| fl.fields().next()).is_some();
 
                 match were_fields_specified {
-                    false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
+                    false => un
+                        .fields(ctx.db)
+                        .into_iter()
+                        .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
+                        .collect(),
                     true => return,
                 }
             }
@@ -56,7 +60,11 @@ pub(crate) fn complete_record_expr_fields(
                 record_expr.record_expr_field_list().and_then(|fl| fl.fields().next()).is_some();
 
             match were_fields_specified {
-                false => un.fields(ctx.db).into_iter().map(|f| (f, f.ty(ctx.db))).collect(),
+                false => un
+                    .fields(ctx.db)
+                    .into_iter()
+                    .map(|f| (f, f.ty(ctx.db).to_type(ctx.db)))
+                    .collect(),
                 true => return,
             }
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 007475688d2..9deaaf66312 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -144,6 +144,7 @@ pub(crate) struct PathExprCtx<'db> {
     pub(crate) in_block_expr: bool,
     pub(crate) in_breakable: BreakableKind,
     pub(crate) after_if_expr: bool,
+    pub(crate) before_else_kw: bool,
     /// Whether this expression is the direct condition of an if or while expression
     pub(crate) in_condition: bool,
     pub(crate) incomplete_let: bool,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index b33a547dee9..77a94403abb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -1,6 +1,7 @@
 //! Module responsible for analyzing the code surrounding the cursor for completion.
 use std::iter;
 
+use base_db::salsa;
 use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
 use ide_db::{RootDatabase, active_parameter::ActiveParameter};
 use itertools::Either;
@@ -85,9 +86,15 @@ pub(super) fn expand_and_analyze<'db>(
     let original_offset = expansion.original_offset + relative_offset;
     let token = expansion.original_file.token_at_offset(original_offset).left_biased()?;
 
-    analyze(sema, expansion, original_token, &token).map(|(analysis, expected, qualifier_ctx)| {
-        AnalysisResult { analysis, expected, qualifier_ctx, token, original_offset }
-    })
+    salsa::attach(sema.db, || analyze(sema, expansion, original_token, &token)).map(
+        |(analysis, expected, qualifier_ctx)| AnalysisResult {
+            analysis,
+            expected,
+            qualifier_ctx,
+            token,
+            original_offset,
+        },
+    )
 }
 
 fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
@@ -637,6 +644,9 @@ fn expected_type_and_name<'db>(
                             .or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs)))
                             .map(TypeInfo::original);
                         (ty, None)
+                    } else if let Some(ast::BinaryOp::LogicOp(_)) = it.op_kind() {
+                        let ty = sema.type_of_expr(&it.clone().into()).map(TypeInfo::original);
+                        (ty, None)
                     } else {
                         (None, None)
                     }
@@ -707,9 +717,13 @@ fn expected_type_and_name<'db>(
                     (ty, None)
                 },
                 ast::IfExpr(it) => {
-                    let ty = it.condition()
-                        .and_then(|e| sema.type_of_expr(&e))
-                        .map(TypeInfo::original);
+                    let ty = if let Some(body) = it.then_branch()
+                        && token.text_range().end() > body.syntax().text_range().start()
+                    {
+                        sema.type_of_expr(&body.into())
+                    } else {
+                        it.condition().and_then(|e| sema.type_of_expr(&e))
+                    }.map(TypeInfo::original);
                     (ty, None)
                 },
                 ast::IdentPat(it) => {
@@ -1282,11 +1296,12 @@ fn classify_name_ref<'db>(
         let after_incomplete_let = after_incomplete_let(it.clone()).is_some();
         let incomplete_expr_stmt =
             it.parent().and_then(ast::ExprStmt::cast).map(|it| it.semicolon_token().is_none());
+        let before_else_kw = before_else_kw(it);
         let incomplete_let = it
             .parent()
             .and_then(ast::LetStmt::cast)
             .is_some_and(|it| it.semicolon_token().is_none())
-            || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw(it);
+            || after_incomplete_let && incomplete_expr_stmt.unwrap_or(true) && !before_else_kw;
         let in_value = it.parent().and_then(Either::<ast::LetStmt, ast::ArgList>::cast).is_some();
         let impl_ = fetch_immediate_impl(sema, original_file, expr.syntax());
 
@@ -1302,6 +1317,7 @@ fn classify_name_ref<'db>(
                 in_block_expr,
                 in_breakable: in_loop_body,
                 after_if_expr,
+                before_else_kw,
                 in_condition,
                 ref_expr_parent,
                 after_amp,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index 445afa75f3f..d9ec7915e3c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -279,6 +279,62 @@ fn foo() {
 }
 
 #[test]
+fn expected_type_if_let_chain_bool() {
+    check_expected_type_and_name(
+        r#"
+fn foo() {
+    let f = Foo::Quux;
+    if let c = f && $0 { }
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_if_condition() {
+    check_expected_type_and_name(
+        r#"
+fn foo() {
+    if a$0 { }
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
+
+#[test]
+fn expected_type_if_body() {
+    check_expected_type_and_name(
+        r#"
+enum Foo { Bar, Baz, Quux }
+
+fn foo() {
+    let _: Foo = if true {
+        $0
+    };
+}
+"#,
+        expect![[r#"ty: Foo, name: ?"#]],
+    );
+
+    check_expected_type_and_name(
+        r#"
+enum Foo { Bar, Baz, Quux }
+
+fn foo() {
+    let _: Foo = if true {
+        Foo::Bar
+    } else {
+        $0
+    };
+}
+"#,
+        expect![[r#"ty: Foo, name: ?"#]],
+    );
+}
+
+#[test]
 fn expected_type_fn_ret_without_leading_char() {
     cov_mark::check!(expected_type_fn_ret_without_leading_char);
     check_expected_type_and_name(
@@ -526,3 +582,16 @@ fn foo() {
         expect![[r#"ty: State, name: ?"#]],
     );
 }
+
+#[test]
+fn expected_type_logic_op() {
+    check_expected_type_and_name(
+        r#"
+enum State { Stop }
+fn foo() {
+    true && $0;
+}
+"#,
+        expect![[r#"ty: bool, name: ?"#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 60ec1128233..312d3bd426f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -163,6 +163,7 @@ fn render_pat(
         PatternContext {
             param_ctx: Some(ParamContext { kind: ParamKind::Function(_), .. }),
             has_type_ascription: false,
+            parent_pat: None,
             ..
         }
     );
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 809a26bf5de..b20b570c2b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -26,6 +26,7 @@ mod visibility;
 
 use base_db::{SourceDatabase, salsa};
 use expect_test::Expect;
+use hir::db::HirDatabase;
 use hir::{PrefixKind, setup_tracing};
 use ide_db::{
     FilePosition, RootDatabase, SnippetCap,
@@ -306,8 +307,11 @@ pub(crate) fn get_all_items(
     trigger_character: Option<char>,
 ) -> Vec<CompletionItem> {
     let (db, position) = position(code);
-    let res = salsa::attach(&db, || crate::completions(&db, &config, position, trigger_character))
-        .map_or_else(Vec::default, Into::into);
+    let res = salsa::attach(&db, || {
+        HirDatabase::zalsa_register_downcaster(&db);
+        crate::completions(&db, &config, position, trigger_character)
+    })
+    .map_or_else(Vec::default, Into::into);
     // validate
     res.iter().for_each(|it| {
         let sr = it.source_range;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 46a36300459..1d2a9c7c8d3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -815,7 +815,10 @@ mod cfg {
 #[cfg($0)]
 "#,
             expect![[r#"
+                ba all
+                ba any
                 ba dbg
+                ba not
                 ba opt_level
                 ba test
                 ba true
@@ -827,7 +830,74 @@ mod cfg {
 #[cfg(b$0)]
 "#,
             expect![[r#"
+                ba all
+                ba any
                 ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+    }
+
+    #[test]
+    fn inside_cfg_attr() {
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr($0)]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr(b$0)]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr($0, allow(deprecated))]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
+                ba opt_level
+                ba test
+                ba true
+            "#]],
+        );
+        check(
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg_attr(b$0, allow(deprecated))]
+"#,
+            expect![[r#"
+                ba all
+                ba any
+                ba dbg
+                ba not
                 ba opt_level
                 ba test
                 ba true
@@ -852,6 +922,20 @@ mod cfg {
             "#]],
         );
     }
+
+    #[test]
+    fn inside_conditional() {
+        check_edit(
+            "all",
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            r#"
+#[cfg(all($0))]
+"#,
+        );
+    }
 }
 
 mod derive {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 5cc72ef845b..98a6f95f334 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -271,8 +271,6 @@ fn complete_in_block() {
             sn macro_rules
             sn pd
             sn ppd
-            ex false
-            ex true
         "#]],
     )
 }
@@ -1668,12 +1666,138 @@ fn foo() { let x = if foo {} $0; let y = 92; }
 fn foo() { let x = if foo {} $0 else {}; }
 "#,
         expect![[r#"
-            fn foo    fn()
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} $0 else if true {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} el$0 else if true {} else {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
+            lc x        ()
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw else if
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+    check(
+        r#"
+fn foo() { let x = if foo {} $0 else if true {} else {}; }
+"#,
+        expect![[r#"
+            fn foo()  fn()
             bt u32     u32
             kw async
             kw const
             kw crate::
-            kw else
             kw else if
             kw enum
             kw extern
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index 9ec27252fd7..6eb0b818d69 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -399,6 +399,25 @@ fn foo($0) {}
 }
 
 #[test]
+fn completes_in_fn_param_in_nested_pattern() {
+    check(
+        r#"
+struct Foo { num: u32 }
+struct Bar(Foo);
+fn foo(Bar($0)) {}
+"#,
+        expect![[r#"
+            st Bar
+            st Foo
+            bn Bar(…)        Bar($1)$0
+            bn Foo {…} Foo { num$1 }$0
+            kw mut
+            kw ref
+        "#]],
+    )
+}
+
+#[test]
 fn completes_in_closure_param() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index 84ddff8f617..c438ca78806 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1510,3 +1510,28 @@ fn foo<T>() {
         "#]],
     );
 }
+
+#[test]
+fn fn_generic_params_const_param_snippet() {
+    check_edit("const", "fn foo<c$0>() {}", "fn foo<const $1: $0>() {}");
+    check_edit("const", "fn foo<T, c$0>() {}", "fn foo<T, const $1: $0>() {}");
+    check(
+        r#"
+fn foo<T: $0>() {}
+"#,
+        expect![[r#"
+            kw crate::
+            kw self::
+        "#]],
+    );
+    check(
+        r#"
+fn foo<const N: $0>() {}
+"#,
+        expect![[r#"
+            bt u32 u32
+            kw crate::
+            kw self::
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index c7e2d058257..125e11e9e35 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -429,18 +429,18 @@ trait Tr<T> {
 impl Tr<$0
     "#,
         expect![[r#"
-            en Enum                    Enum
-            ma makro!(…) macro_rules! makro
+            en Enum                        Enum
+            ma makro!(…)     macro_rules! makro
             md module
-            sp Self       dyn Tr<{unknown}>
-            st Record                Record
-            st S                          S
-            st Tuple                  Tuple
-            st Unit                    Unit
+            sp Self dyn Tr<{unknown}> + 'static
+            st Record                    Record
+            st S                              S
+            st Tuple                      Tuple
+            st Unit                        Unit
             tt Tr
             tt Trait
-            un Union                  Union
-            bt u32                      u32
+            un Union                      Union
+            bt u32                          u32
             kw crate::
             kw self::
         "#]],
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
index cefd8fd4967..e1d140730ed 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -265,10 +265,7 @@ pub fn is_pattern_cond(expr: ast::Expr) -> bool {
         ast::Expr::BinExpr(expr)
             if expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) =>
         {
-            expr.lhs()
-                .map(is_pattern_cond)
-                .or_else(|| expr.rhs().map(is_pattern_cond))
-                .unwrap_or(false)
+            expr.lhs().map_or(false, is_pattern_cond) || expr.rhs().map_or(false, is_pattern_cond)
         }
         ast::Expr::ParenExpr(expr) => expr.expr().is_some_and(is_pattern_cond),
         ast::Expr::LetExpr(_) => true,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 995bf72dca1..2e03665765f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -473,7 +473,7 @@ mod tests {
             frange.range,
             "selection is not an expression(yet contained in one)"
         );
-        let name = NameGenerator::default().for_variable(&expr, &sema);
+        let name = salsa::attach(sema.db, || NameGenerator::default().for_variable(&expr, &sema));
         assert_eq!(&name, expected);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
index 76b30745a04..b07f9e68f63 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_lifetime.rs
@@ -88,4 +88,16 @@ fn bar<const F: Foo>() {}
         "#,
         );
     }
+
+    #[test]
+    fn fn_traits() {
+        check_diagnostics(
+            r#"
+//- minicore: fn
+struct WithLifetime<'a>(&'a ());
+
+fn foo<T: Fn(WithLifetime) -> WithLifetime>() {}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 4bb64747f5b..029ed18a4d3 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -442,6 +442,49 @@ fn main() {
     }
 
     #[test]
+    fn raw_deref_on_union_field() {
+        check_diagnostics(
+            r#"
+fn main() {
+
+    union U {
+        a: u8
+    }
+    let x = U { a: 3 };
+
+    let a = &raw mut x.a;
+
+    union U1 {
+        a: u8
+    }
+    let x = U1 { a: 3 };
+
+    let a = x.a;
+         // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+
+    let b = &raw const x.a;
+
+    let tmp = Vec::from([1, 2, 3]);
+
+    let c = &raw const tmp[x.a];
+                        // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+    union URef {
+        p: &'static mut i32,
+    }
+
+    fn deref_union_field(u: URef) {
+        // Not an assignment but an access to the union field!
+        *(u.p) = 13;
+       // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
     fn unsafe_expr_as_an_argument_of_a_method_call() {
         check_fix(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
index e6bbff05f7e..84e63acbc04 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs
@@ -6,7 +6,7 @@ use ide_db::{
     label::Label,
     source_change::SourceChange,
 };
-use syntax::{Edition, TextRange};
+use syntax::{AstNode, Edition, TextRange, ToSmolStr};
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -24,15 +24,21 @@ pub(crate) fn unused_variables(
     }
     let diagnostic_range = ctx.sema.diagnostics_display_range(ast);
     // The range for the Actual Name. We don't want to replace the entire declaration. Using the diagnostic range causes issues within in Array Destructuring.
-    let name_range = d
-        .local
-        .primary_source(ctx.sema.db)
+    let primary_source = d.local.primary_source(ctx.sema.db);
+    let name_range = primary_source
         .name()
         .map(|v| v.syntax().original_file_range_rooted(ctx.sema.db))
         .filter(|it| {
             Some(it.file_id) == ast.file_id.file_id()
                 && diagnostic_range.range.contains_range(it.range)
         });
+    let is_shorthand_field = primary_source
+        .source
+        .value
+        .left()
+        .and_then(|name| name.syntax().parent())
+        .and_then(syntax::ast::RecordPatField::cast)
+        .is_some_and(|field| field.colon_token().is_none());
     let var_name = d.local.name(ctx.sema.db);
     Some(
         Diagnostic::new_with_syntax_node_ptr(
@@ -48,6 +54,7 @@ pub(crate) fn unused_variables(
                 it.range,
                 diagnostic_range,
                 ast.file_id.is_macro(),
+                is_shorthand_field,
                 ctx.edition,
             )
         })),
@@ -60,24 +67,24 @@ fn fixes(
     name_range: TextRange,
     diagnostic_range: FileRange,
     is_in_marco: bool,
+    is_shorthand_field: bool,
     edition: Edition,
 ) -> Option<Vec<Assist>> {
     if is_in_marco {
         return None;
     }
+    let name = var_name.display(db, edition).to_smolstr();
+    let name = name.strip_prefix("r#").unwrap_or(&name);
+    let new_name = if is_shorthand_field { format!("{name}: _{name}") } else { format!("_{name}") };
 
     Some(vec![Assist {
         id: AssistId::quick_fix("unscore_unused_variable_name"),
-        label: Label::new(format!(
-            "Rename unused {} to _{}",
-            var_name.display(db, edition),
-            var_name.display(db, edition)
-        )),
+        label: Label::new(format!("Rename unused {name} to {new_name}")),
         group: None,
         target: diagnostic_range.range,
         source_change: Some(SourceChange::from_text_edit(
             diagnostic_range.file_id,
-            TextEdit::replace(name_range, format!("_{}", var_name.display(db, edition))),
+            TextEdit::replace(name_range, new_name),
         )),
         command: None,
     }])
@@ -220,13 +227,26 @@ struct Foo { f1: i32, f2: i64 }
 fn main() {
     let f = Foo { f1: 0, f2: 0 };
     match f {
-        Foo { _f1, f2 } => {
+        Foo { f1: _f1, f2 } => {
             _ = f2;
         }
     }
 }
 "#,
         );
+
+        check_fix(
+            r#"
+fn main() {
+    let $0r#type = 2;
+}
+"#,
+            r#"
+fn main() {
+    let _type = 2;
+}
+"#,
+        );
     }
 
     #[test]
@@ -263,6 +283,46 @@ fn main() {
         );
     }
 
+    #[test]
+    fn unused_variable_in_record_field() {
+        check_fix(
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: $0x } = s
+}
+"#,
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: _x } = s
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn unused_variable_in_shorthand_record_field() {
+        check_fix(
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { $0field } = s
+}
+"#,
+            r#"
+struct S { field : u32 }
+fn main() {
+    let s = S { field : 2 };
+    let S { field: _field } = s
+}
+"#,
+        );
+    }
+
     // regression test as we used to panic in this scenario
     #[test]
     fn unknown_struct_pattern_param_type() {
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index ffd144a827e..ae208fe1b56 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -88,7 +88,7 @@ pub(crate) fn goto_type_definition(
                             ast::Pat(it) => sema.type_of_pat(&it)?.original,
                             ast::SelfParam(it) => sema.type_of_self(&it)?,
                             ast::Type(it) => sema.resolve_type(&it)?,
-                            ast::RecordField(it) => sema.to_def(&it)?.ty(db),
+                            ast::RecordField(it) => sema.to_def(&it)?.ty(db).to_type(db),
                             // can't match on RecordExprField directly as `ast::Expr` will match an iteration too early otherwise
                             ast::NameRef(it) => {
                                 if let Some(record_field) = ast::RecordExprField::for_name_ref(&it) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 03b9b367751..c4fb6d1a5b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -440,7 +440,7 @@ pub(crate) fn hover_for_definition(
         Definition::Local(it) => Some(it.ty(db)),
         Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)),
         Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)),
-        Definition::Field(field) => Some(field.ty(db)),
+        Definition::Field(field) => Some(field.ty(db).to_type(db)),
         Definition::TupleField(it) => Some(it.ty(db)),
         Definition::Function(it) => Some(it.ty(db)),
         Definition::Adt(it) => Some(it.ty(db)),
@@ -602,7 +602,7 @@ fn goto_type_action_for_def(
 
     let ty = match def {
         Definition::Local(it) => Some(it.ty(db)),
-        Definition::Field(field) => Some(field.ty(db)),
+        Definition::Field(field) => Some(field.ty(db).to_type(db)),
         Definition::TupleField(field) => Some(field.ty(db)),
         Definition::Const(it) => Some(it.ty(db)),
         Definition::Static(it) => Some(it.ty(db)),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 65375ed8f78..c5d695ccec3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -692,14 +692,14 @@ pub(super) fn definition(
         }
         let drop_info = match def {
             Definition::Field(field) => {
-                DropInfo { drop_glue: field.ty(db).drop_glue(db), has_dtor: None }
+                DropInfo { drop_glue: field.ty(db).to_type(db).drop_glue(db), has_dtor: None }
             }
             Definition::Adt(Adt::Struct(strukt)) => {
                 let struct_drop_glue = strukt.ty_placeholders(db).drop_glue(db);
                 let mut fields_drop_glue = strukt
                     .fields(db)
                     .iter()
-                    .map(|field| field.ty(db).drop_glue(db))
+                    .map(|field| field.ty(db).to_type(db).drop_glue(db))
                     .max()
                     .unwrap_or(DropGlue::None);
                 let has_dtor = match (fields_drop_glue, struct_drop_glue) {
@@ -727,7 +727,7 @@ pub(super) fn definition(
                         variant
                             .fields(db)
                             .iter()
-                            .map(|field| field.ty(db).drop_glue(db))
+                            .map(|field| field.ty(db).to_type(db).drop_glue(db))
                             .max()
                             .unwrap_or(DropGlue::None)
                     })
@@ -742,7 +742,7 @@ pub(super) fn definition(
                 let fields_drop_glue = variant
                     .fields(db)
                     .iter()
-                    .map(|field| field.ty(db).drop_glue(db))
+                    .map(|field| field.ty(db).to_type(db).drop_glue(db))
                     .max()
                     .unwrap_or(DropGlue::None);
                 DropInfo { drop_glue: fields_drop_glue, has_dtor: None }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 1ea11a215f8..8bc0b3f6ab3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -4797,6 +4797,48 @@ fn main() {
 }
 
 #[test]
+fn const_generic_negative_literal_macro_expansion() {
+    // Test that negative literals work correctly in const generics
+    // when used through macro expansion. This ensures the transcriber
+    // doesn't wrap negative literals in parentheses, which would create
+    // invalid syntax like Foo::<(-1)> instead of Foo::<-1>.
+    check(
+        r#"
+struct Foo<const I: i16> {
+    pub value: i16,
+}
+
+impl<const I: i16> Foo<I> {
+    pub fn new(value: i16) -> Self {
+        Self { value }
+    }
+}
+
+macro_rules! create_foo {
+    ($val:expr) => {
+        Foo::<$val>::new($val)
+    };
+}
+
+fn main() {
+    let v$0alue = create_foo!(-1);
+}
+"#,
+        expect![[r#"
+            *value*
+
+            ```rust
+            let value: Foo<-1>
+            ```
+
+            ---
+
+            size = 2, align = 2, no Drop
+        "#]],
+    );
+}
+
+#[test]
 fn hover_self_param_shows_type() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 104740cbbf7..b7c12413960 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -380,7 +380,7 @@ fn main() {
     let foo = foo4();
      // ^^^ &dyn Fn(f64, f64) -> u32
     let foo = foo5();
-     // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
+     // ^^^ &dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32
     let foo = foo6();
      // ^^^ impl Fn(f64, f64) -> u32
     let foo = foo7();
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index e80c9dc9d47..9d246eda57e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -191,7 +191,7 @@ impl Tr for () {
 //^ impl Tr for ()
 impl dyn Tr {
   }
-//^ impl dyn Tr
+//^ impl dyn Tr + 'static
 
 static S0: () = 0;
 static S1: () = {};
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index f45d096ac19..e74d997e97c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -526,7 +526,7 @@ fn signature_help_for_tuple_struct_pat(
         pat.syntax(),
         token,
         pat.fields(),
-        fields.into_iter().map(|it| it.ty(db)),
+        fields.into_iter().map(|it| it.ty(db).to_type(db)),
         display_target,
     ))
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 8214b4d1de2..9911b85799b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -278,7 +278,7 @@ impl StaticIndex<'_> {
         for token in tokens {
             let range = token.text_range();
             let node = token.parent().unwrap();
-            match get_definitions(&sema, token.clone()) {
+            match salsa::attach(self.db, || get_definitions(&sema, token.clone())) {
                 Some(it) => {
                     for i in it {
                         add_token(i, range, &node);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 828b8f762c5..8339daf3246 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -96,7 +96,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
         <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
         <span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
-        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+        <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
         <span class="comment">// this should be safe!</span>
         <span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="punctuation">_</span> <span class="brace">}</span><span class="semicolon">;</span>
         <span class="comment">// but not these</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index 950f3f6c647..ddd58a0a3c9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -94,14 +94,14 @@ pub(crate) fn view_memory_layout(
     let def = get_definition(&sema, token)?;
 
     let ty = match def {
-        Definition::Adt(it) => it.ty(db),
-        Definition::TypeAlias(it) => it.ty(db),
+        Definition::Adt(it) => salsa::attach(db, || it.ty(db)),
+        Definition::TypeAlias(it) => salsa::attach(db, || it.ty(db)),
         Definition::BuiltinType(it) => it.ty(db),
         Definition::SelfType(it) => it.self_ty(db),
         Definition::Local(it) => it.ty(db),
-        Definition::Field(it) => it.ty(db),
-        Definition::Const(it) => it.ty(db),
-        Definition::Static(it) => it.ty(db),
+        Definition::Field(it) => salsa::attach(db, || it.ty(db).to_type(db)),
+        Definition::Const(it) => salsa::attach(db, || it.ty(db)),
+        Definition::Static(it) => salsa::attach(db, || it.ty(db)),
         _ => return None,
     };
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index 1db4f8ecd6b..920bdd9568f 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -516,4 +516,5 @@ define_symbols! {
     flags,
     precision,
     width,
+    never_type_fallback,
 }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 2c046df10f5..3e4ab8bdc1d 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -401,7 +401,19 @@ fn expand_var(
                     let sub = sub.strip_invisible();
                     let mut span = id;
                     marker(&mut span);
-                    let wrap_in_parens = !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
+
+                    // Check if this is a simple negative literal (MINUS + LITERAL)
+                    // that should not be wrapped in parentheses
+                    let is_negative_literal = matches!(
+                        sub.flat_tokens(),
+                        [
+                            tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
+                            tt::TokenTree::Leaf(tt::Leaf::Literal(_))
+                        ]
+                    );
+
+                    let wrap_in_parens = !is_negative_literal
+                        && !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
                         && sub.try_into_subtree().is_none_or(|it| {
                             it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible
                         });
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
index 203173c11be..5eda5af3ace 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_dependencies.rs
@@ -9,7 +9,7 @@
 use std::{cell::RefCell, io, mem, process::Command};
 
 use base_db::Env;
-use cargo_metadata::{Message, camino::Utf8Path};
+use cargo_metadata::{Message, PackageId, camino::Utf8Path};
 use cfg::CfgAtom;
 use itertools::Itertools;
 use la_arena::ArenaMap;
@@ -18,6 +18,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use serde::Deserialize as _;
 use stdx::never;
 use toolchain::Tool;
+use triomphe::Arc;
 
 use crate::{
     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot,
@@ -284,7 +285,7 @@ impl WorkspaceBuildScripts {
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
         // exactly those from `config`.
-        let mut by_id: FxHashMap<String, Package> = FxHashMap::default();
+        let mut by_id: FxHashMap<Arc<PackageId>, Package> = FxHashMap::default();
         for package in workspace.packages() {
             outputs.insert(package, BuildScriptOutput::default());
             by_id.insert(workspace[package].id.clone(), package);
@@ -323,7 +324,7 @@ impl WorkspaceBuildScripts {
         // ideally this would be something like:
         // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
         // but owned trait objects aren't a thing
-        mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
+        mut with_output_for: impl FnMut(&PackageId, &mut dyn FnMut(&str, &mut BuildScriptOutput)),
         progress: &dyn Fn(String),
     ) -> io::Result<Option<String>> {
         let errors = RefCell::new(String::new());
@@ -346,7 +347,7 @@ impl WorkspaceBuildScripts {
 
                 match message {
                     Message::BuildScriptExecuted(mut message) => {
-                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                        with_output_for(&message.package_id, &mut |name, data| {
                             progress(format!("build script {name} run"));
                             let cfgs = {
                                 let mut acc = Vec::new();
@@ -377,7 +378,7 @@ impl WorkspaceBuildScripts {
                         });
                     }
                     Message::CompilerArtifact(message) => {
-                        with_output_for(&message.package_id.repr, &mut |name, data| {
+                        with_output_for(&message.package_id, &mut |name, data| {
                             progress(format!("proc-macro {name} built"));
                             if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt {
                                 data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro;
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index e613fd590c7..adc0cc50941 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -5,7 +5,7 @@ use std::str::from_utf8;
 
 use anyhow::Context;
 use base_db::Env;
-use cargo_metadata::{CargoOpt, MetadataCommand};
+use cargo_metadata::{CargoOpt, MetadataCommand, PackageId};
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -14,6 +14,7 @@ use serde_json::from_value;
 use span::Edition;
 use stdx::process::spawn_with_streaming_output;
 use toolchain::Tool;
+use triomphe::Arc;
 
 use crate::cargo_config_file::make_lockfile_copy;
 use crate::{CfgOverrides, InvocationStrategy};
@@ -155,8 +156,8 @@ pub struct PackageData {
     pub features: FxHashMap<String, Vec<String>>,
     /// List of features enabled on this package
     pub active_features: Vec<String>,
-    /// String representation of package id
-    pub id: String,
+    /// Package id
+    pub id: Arc<PackageId>,
     /// Authors as given in the `Cargo.toml`
     pub authors: Vec<String>,
     /// Description as given in the `Cargo.toml`
@@ -173,6 +174,10 @@ pub struct PackageData {
     pub rust_version: Option<semver::Version>,
     /// The contents of [package.metadata.rust-analyzer]
     pub metadata: RustAnalyzerPackageMetaData,
+    /// If this package is a member of the workspace, store all direct and transitive
+    /// dependencies as long as they are workspace members, to track dependency relationships
+    /// between members.
+    pub all_member_deps: Option<FxHashSet<Package>>,
 }
 
 #[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
@@ -334,6 +339,8 @@ impl CargoWorkspace {
         let mut is_virtual_workspace = true;
         let mut requires_rustc_private = false;
 
+        let mut members = FxHashSet::default();
+
         meta.packages.sort_by(|a, b| a.id.cmp(&b.id));
         for meta_pkg in meta.packages {
             let cargo_metadata::Package {
@@ -356,6 +363,7 @@ impl CargoWorkspace {
                 rust_version,
                 ..
             } = meta_pkg;
+            let id = Arc::new(id);
             let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default();
             let edition = match edition {
                 cargo_metadata::Edition::E2015 => Edition::Edition2015,
@@ -375,7 +383,7 @@ impl CargoWorkspace {
             let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap();
             is_virtual_workspace &= manifest != ws_manifest_path;
             let pkg = packages.alloc(PackageData {
-                id: id.repr.clone(),
+                id: id.clone(),
                 name: name.to_string(),
                 version,
                 manifest: manifest.clone(),
@@ -395,7 +403,11 @@ impl CargoWorkspace {
                 features: features.into_iter().collect(),
                 active_features: Vec::new(),
                 metadata: meta.rust_analyzer.unwrap_or_default(),
+                all_member_deps: None,
             });
+            if is_member {
+                members.insert(pkg);
+            }
             let pkg_data = &mut packages[pkg];
             requires_rustc_private |= pkg_data.metadata.rustc_private;
             pkg_by_id.insert(id, pkg);
@@ -440,6 +452,43 @@ impl CargoWorkspace {
                 .extend(node.features.into_iter().map(|it| it.to_string()));
         }
 
+        fn saturate_all_member_deps(
+            packages: &mut Arena<PackageData>,
+            to_visit: Package,
+            visited: &mut FxHashSet<Package>,
+            members: &FxHashSet<Package>,
+        ) {
+            let pkg_data = &mut packages[to_visit];
+
+            if !visited.insert(to_visit) {
+                return;
+            }
+
+            let deps: Vec<_> = pkg_data
+                .dependencies
+                .iter()
+                .filter_map(|dep| {
+                    let pkg = dep.pkg;
+                    if members.contains(&pkg) { Some(pkg) } else { None }
+                })
+                .collect();
+
+            let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied());
+            for dep in deps {
+                saturate_all_member_deps(packages, dep, visited, members);
+                if let Some(transitives) = &packages[dep].all_member_deps {
+                    all_member_deps.extend(transitives);
+                }
+            }
+
+            packages[to_visit].all_member_deps = Some(all_member_deps);
+        }
+
+        let mut visited = FxHashSet::default();
+        for member in members.iter() {
+            saturate_all_member_deps(&mut packages, *member, &mut visited, &members);
+        }
+
         CargoWorkspace {
             packages,
             targets,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 6b489d51143..a88d228fcb6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -267,6 +267,8 @@ config_data! {
         inlayHints_lifetimeElisionHints_useParameterNames: bool = false,
 
         /// Maximum length for inlay hints. Set to null to have an unlimited length.
+        ///
+        /// **Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.
         inlayHints_maxLength: Option<usize> = Some(25),
 
         /// Show function parameter name inlay hints at the call site.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index ee50237c405..4bfad98b399 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -120,6 +120,29 @@ impl DiagnosticCollection {
         }
     }
 
+    pub(crate) fn clear_check_older_than_for_package(
+        &mut self,
+        flycheck_id: usize,
+        package_id: Arc<PackageId>,
+        generation: DiagnosticsGeneration,
+    ) {
+        let Some(check) = self.check.get_mut(flycheck_id) else {
+            return;
+        };
+        let package_id = Some(package_id);
+        let Some((_, checks)) = check
+            .per_package
+            .extract_if(|k, v| *k == package_id && v.generation < generation)
+            .next()
+        else {
+            return;
+        };
+        self.changes.extend(checks.per_file.into_keys());
+        if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) {
+            fixes.remove(&package_id);
+        }
+    }
+
     pub(crate) fn clear_native_for(&mut self, file_id: FileId) {
         self.native_syntax.remove(&file_id);
         self.native_semantic.remove(&file_id);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 315c45d5b63..cded34be14a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -180,17 +180,27 @@ impl FlycheckHandle {
     pub(crate) fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) {
         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
         self.sender
-            .send(StateChange::Restart { generation, package: None, saved_file, target: None })
+            .send(StateChange::Restart {
+                generation,
+                scope: FlycheckScope::Workspace,
+                saved_file,
+                target: None,
+            })
             .unwrap();
     }
 
     /// Schedule a re-start of the cargo check worker to do a package wide check.
-    pub(crate) fn restart_for_package(&self, package: String, target: Option<Target>) {
+    pub(crate) fn restart_for_package(
+        &self,
+        package: Arc<PackageId>,
+        target: Option<Target>,
+        workspace_deps: Option<FxHashSet<Arc<PackageId>>>,
+    ) {
         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1;
         self.sender
             .send(StateChange::Restart {
                 generation,
-                package: Some(package),
+                scope: FlycheckScope::Package { package, workspace_deps },
                 saved_file: None,
                 target,
             })
@@ -213,8 +223,13 @@ impl FlycheckHandle {
 
 #[derive(Debug)]
 pub(crate) enum ClearDiagnosticsKind {
-    All,
-    OlderThan(DiagnosticsGeneration),
+    All(ClearScope),
+    OlderThan(DiagnosticsGeneration, ClearScope),
+}
+
+#[derive(Debug)]
+pub(crate) enum ClearScope {
+    Workspace,
     Package(Arc<PackageId>),
 }
 
@@ -275,10 +290,15 @@ pub(crate) enum Progress {
     DidFailToRestart(String),
 }
 
+enum FlycheckScope {
+    Workspace,
+    Package { package: Arc<PackageId>, workspace_deps: Option<FxHashSet<Arc<PackageId>>> },
+}
+
 enum StateChange {
     Restart {
         generation: DiagnosticsGeneration,
-        package: Option<String>,
+        scope: FlycheckScope,
         saved_file: Option<AbsPathBuf>,
         target: Option<Target>,
     },
@@ -298,6 +318,7 @@ struct FlycheckActor {
     /// or the project root of the project.
     root: Arc<AbsPathBuf>,
     sysroot_root: Option<AbsPathBuf>,
+    scope: FlycheckScope,
     /// CargoHandle exists to wrap around the communication needed to be able to
     /// run `cargo check` without blocking. Currently the Rust standard library
     /// doesn't provide a way to read sub-process output without blocking, so we
@@ -343,6 +364,7 @@ impl FlycheckActor {
             config,
             sysroot_root,
             root: Arc::new(workspace_root),
+            scope: FlycheckScope::Workspace,
             manifest_path,
             command_handle: None,
             command_receiver: None,
@@ -376,7 +398,7 @@ impl FlycheckActor {
                 }
                 Event::RequestStateChange(StateChange::Restart {
                     generation,
-                    package,
+                    scope,
                     saved_file,
                     target,
                 }) => {
@@ -389,11 +411,11 @@ impl FlycheckActor {
                         }
                     }
 
+                    let command = self.check_command(&scope, saved_file.as_deref(), target);
+                    self.scope = scope;
                     self.generation = generation;
 
-                    let Some(command) =
-                        self.check_command(package.as_deref(), saved_file.as_deref(), target)
-                    else {
+                    let Some(command) = command else {
                         continue;
                     };
 
@@ -435,19 +457,55 @@ impl FlycheckActor {
                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics");
                         // We finished without receiving any diagnostics.
                         // Clear everything for good measure
-                        self.send(FlycheckMessage::ClearDiagnostics {
-                            id: self.id,
-                            kind: ClearDiagnosticsKind::All,
-                        });
+                        match &self.scope {
+                            FlycheckScope::Workspace => {
+                                self.send(FlycheckMessage::ClearDiagnostics {
+                                    id: self.id,
+                                    kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+                                });
+                            }
+                            FlycheckScope::Package { package, workspace_deps } => {
+                                for pkg in
+                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
+                                {
+                                    self.send(FlycheckMessage::ClearDiagnostics {
+                                        id: self.id,
+                                        kind: ClearDiagnosticsKind::All(ClearScope::Package(
+                                            pkg.clone(),
+                                        )),
+                                    });
+                                }
+                            }
+                        }
                     } else if res.is_ok() {
                         // We clear diagnostics for packages on
                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
                         // cargo may not report an artifact to our runner at all. To handle such
                         // cases, clear stale diagnostics when flycheck completes successfully.
-                        self.send(FlycheckMessage::ClearDiagnostics {
-                            id: self.id,
-                            kind: ClearDiagnosticsKind::OlderThan(self.generation),
-                        });
+                        match &self.scope {
+                            FlycheckScope::Workspace => {
+                                self.send(FlycheckMessage::ClearDiagnostics {
+                                    id: self.id,
+                                    kind: ClearDiagnosticsKind::OlderThan(
+                                        self.generation,
+                                        ClearScope::Workspace,
+                                    ),
+                                });
+                            }
+                            FlycheckScope::Package { package, workspace_deps } => {
+                                for pkg in
+                                    std::iter::once(package).chain(workspace_deps.iter().flatten())
+                                {
+                                    self.send(FlycheckMessage::ClearDiagnostics {
+                                        id: self.id,
+                                        kind: ClearDiagnosticsKind::OlderThan(
+                                            self.generation,
+                                            ClearScope::Package(pkg.clone()),
+                                        ),
+                                    });
+                                }
+                            }
+                        }
                     }
                     self.clear_diagnostics_state();
 
@@ -475,7 +533,7 @@ impl FlycheckActor {
                             );
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
-                                kind: ClearDiagnosticsKind::Package(package_id),
+                                kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
                             });
                         }
                     }
@@ -498,7 +556,9 @@ impl FlycheckActor {
                                 );
                                 self.send(FlycheckMessage::ClearDiagnostics {
                                     id: self.id,
-                                    kind: ClearDiagnosticsKind::Package(package_id.clone()),
+                                    kind: ClearDiagnosticsKind::All(ClearScope::Package(
+                                        package_id.clone(),
+                                    )),
                                 });
                             }
                         } else if self.diagnostics_received
@@ -507,7 +567,7 @@ impl FlycheckActor {
                             self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll;
                             self.send(FlycheckMessage::ClearDiagnostics {
                                 id: self.id,
-                                kind: ClearDiagnosticsKind::All,
+                                kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
                             });
                         }
                         self.send(FlycheckMessage::AddDiagnostic {
@@ -548,7 +608,7 @@ impl FlycheckActor {
     /// return None.
     fn check_command(
         &self,
-        package: Option<&str>,
+        scope: &FlycheckScope,
         saved_file: Option<&AbsPath>,
         target: Option<Target>,
     ) -> Option<Command> {
@@ -564,9 +624,9 @@ impl FlycheckActor {
                 }
                 cmd.arg(command);
 
-                match package {
-                    Some(pkg) => cmd.arg("-p").arg(pkg),
-                    None => cmd.arg("--workspace"),
+                match scope {
+                    FlycheckScope::Workspace => cmd.arg("--workspace"),
+                    FlycheckScope::Package { package, .. } => cmd.arg("-p").arg(&package.repr),
                 };
 
                 if let Some(tgt) = target {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 89d6fb8edc2..ce6644f725c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -9,6 +9,7 @@ use std::{
     time::{Duration, Instant},
 };
 
+use cargo_metadata::PackageId;
 use crossbeam_channel::{Receiver, Sender, unbounded};
 use hir::ChangeWithProcMacros;
 use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
@@ -784,6 +785,7 @@ impl GlobalStateSnapshot {
                         cargo_toml: package_data.manifest.clone(),
                         crate_id,
                         package: cargo.package_flag(package_data),
+                        package_id: package_data.id.clone(),
                         target: target_data.name.clone(),
                         target_kind: target_data.kind,
                         required_features: target_data.required_features.clone(),
@@ -812,6 +814,27 @@ impl GlobalStateSnapshot {
         None
     }
 
+    pub(crate) fn all_workspace_dependencies_for_package(
+        &self,
+        package: &Arc<PackageId>,
+    ) -> Option<FxHashSet<Arc<PackageId>>> {
+        for workspace in self.workspaces.iter() {
+            match &workspace.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. }
+                | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => {
+                    let package = cargo.packages().find(|p| cargo[*p].id == *package)?;
+
+                    return cargo[package]
+                        .all_member_deps
+                        .as_ref()
+                        .map(|deps| deps.iter().map(|dep| cargo[*dep].id.clone()).collect());
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
         self.vfs.read().0.exists(file_id)
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 68c91a65394..87be09dcbd2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -331,7 +331,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                         let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
                             let tgt_kind = it.target_kind();
                             let (tgt_name, root, package) = match it {
-                                TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package),
+                                TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package_id),
                                 _ => return None,
                             };
 
@@ -368,7 +368,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                                         _ => false,
                                     });
                                 if let Some(idx) = package_workspace_idx {
-                                    world.flycheck[idx].restart_for_package(package, target);
+                                    let workspace_deps =
+                                        world.all_workspace_dependencies_for_package(&package);
+                                    world.flycheck[idx].restart_for_package(
+                                        package,
+                                        target,
+                                        workspace_deps,
+                                    );
                                 }
                             }
                         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index c6762f31832..3e80e8b7bdf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -20,7 +20,7 @@ use crate::{
     config::Config,
     diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics},
     discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage},
-    flycheck::{self, ClearDiagnosticsKind, FlycheckMessage},
+    flycheck::{self, ClearDiagnosticsKind, ClearScope, FlycheckMessage},
     global_state::{
         FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState,
         file_id_to_url, url_to_file_id,
@@ -1042,17 +1042,22 @@ impl GlobalState {
                     };
                 }
             }
-            FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => {
-                self.diagnostics.clear_check(id)
-            }
             FlycheckMessage::ClearDiagnostics {
                 id,
-                kind: ClearDiagnosticsKind::OlderThan(generation),
-            } => self.diagnostics.clear_check_older_than(id, generation),
+                kind: ClearDiagnosticsKind::All(ClearScope::Workspace),
+            } => self.diagnostics.clear_check(id),
             FlycheckMessage::ClearDiagnostics {
                 id,
-                kind: ClearDiagnosticsKind::Package(package_id),
+                kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)),
             } => self.diagnostics.clear_check_for_package(id, package_id),
+            FlycheckMessage::ClearDiagnostics {
+                id,
+                kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Workspace),
+            } => self.diagnostics.clear_check_older_than(id, generation),
+            FlycheckMessage::ClearDiagnostics {
+                id,
+                kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Package(package_id)),
+            } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation),
             FlycheckMessage::Progress { id, progress } => {
                 let (state, message) = match progress {
                     flycheck::Progress::DidStart => (Progress::Begin, None),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
index 7132e09146e..e532d155536 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs
@@ -2,12 +2,14 @@
 
 use std::mem;
 
+use cargo_metadata::PackageId;
 use cfg::{CfgAtom, CfgExpr};
 use hir::sym;
 use ide::{Cancellable, Crate, FileId, RunnableKind, TestId};
 use project_model::project_json::Runnable;
 use project_model::{CargoFeatures, ManifestPath, TargetKind};
 use rustc_hash::FxHashSet;
+use triomphe::Arc;
 use vfs::AbsPathBuf;
 
 use crate::global_state::GlobalStateSnapshot;
@@ -52,6 +54,7 @@ pub(crate) struct CargoTargetSpec {
     pub(crate) workspace_root: AbsPathBuf,
     pub(crate) cargo_toml: ManifestPath,
     pub(crate) package: String,
+    pub(crate) package_id: Arc<PackageId>,
     pub(crate) target: String,
     pub(crate) target_kind: TargetKind,
     pub(crate) crate_id: Crate,
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 978c50d807b..5fa00741637 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -187,11 +187,19 @@ pub fn is_upper_snake_case(s: &str) -> bool {
 }
 
 pub fn replace(buf: &mut String, from: char, to: &str) {
-    if !buf.contains(from) {
+    let replace_count = buf.chars().filter(|&ch| ch == from).count();
+    if replace_count == 0 {
         return;
     }
-    // FIXME: do this in place.
-    *buf = buf.replace(from, to);
+    let from_len = from.len_utf8();
+    let additional = to.len().saturating_sub(from_len);
+    buf.reserve(additional * replace_count);
+
+    let mut end = buf.len();
+    while let Some(i) = buf[..end].rfind(from) {
+        buf.replace_range(i..i + from_len, to);
+        end = i;
+    }
 }
 
 #[must_use]
@@ -343,4 +351,34 @@ mod tests {
             "fn main() {\n    return 92;\n}\n"
         );
     }
+
+    #[test]
+    fn test_replace() {
+        #[track_caller]
+        fn test_replace(src: &str, from: char, to: &str, expected: &str) {
+            let mut s = src.to_owned();
+            replace(&mut s, from, to);
+            assert_eq!(s, expected, "from: {from:?}, to: {to:?}");
+        }
+
+        test_replace("", 'a', "b", "");
+        test_replace("", 'a', "😀", "");
+        test_replace("", '😀', "a", "");
+        test_replace("a", 'a', "b", "b");
+        test_replace("aa", 'a', "b", "bb");
+        test_replace("ada", 'a', "b", "bdb");
+        test_replace("a", 'a', "😀", "😀");
+        test_replace("😀", '😀', "a", "a");
+        test_replace("😀x", '😀', "a", "ax");
+        test_replace("y😀x", '😀', "a", "yax");
+        test_replace("a,b,c", ',', ".", "a.b.c");
+        test_replace("a,b,c", ',', "..", "a..b..c");
+        test_replace("a.b.c", '.', "..", "a..b..c");
+        test_replace("a.b.c", '.', "..", "a..b..c");
+        test_replace("a😀b😀c", '😀', ".", "a.b.c");
+        test_replace("a.b.c", '.', "😀", "a😀b😀c");
+        test_replace("a.b.c", '.', "😀😀", "a😀😀b😀😀c");
+        test_replace(".a.b.c.", '.', "()", "()a()b()c()");
+        test_replace(".a.b.c.", '.', "", "abc");
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
index dc6130bd641..1c902893abc 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_error.rs
@@ -42,3 +42,5 @@ impl fmt::Display for SyntaxError {
         self.0.fmt(f)
     }
 }
+
+impl std::error::Error for SyntaxError {}
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 50dacd88f40..e78f1b4ba35 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -1046,6 +1046,8 @@ Default: `25`
 
 Maximum length for inlay hints. Set to null to have an unlimited length.
 
+**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.
+
 
 ## rust-analyzer.inlayHints.parameterHints.enable {#inlayHints.parameterHints.enable}
 
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index ad8708e00c5..e35a159cbc3 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -6405,9 +6405,9 @@
             }
         },
         "node_modules/tar-fs": {
-            "version": "2.1.3",
-            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
-            "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+            "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
             "dev": true,
             "license": "MIT",
             "optional": true,
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1d27a120535..745e0da4efe 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2355,7 +2355,7 @@
                 "title": "Inlay Hints",
                 "properties": {
                     "rust-analyzer.inlayHints.maxLength": {
-                        "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.",
+                        "markdownDescription": "Maximum length for inlay hints. Set to null to have an unlimited length.\n\n**Note:** This is mostly a hint, and we don't guarantee to strictly follow the limit.",
                         "default": 25,
                         "type": [
                             "null",
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 02b217f7d80..1f90d4e5e49 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-21a19c297d4f5a03501d92ca251bd7a17073c08a
+f957826bff7a68b267ce75b1ea56352aed0cca0a
diff --git a/tests/codegen-llvm/autodiff/abi_handling.rs b/tests/codegen-llvm/autodiff/abi_handling.rs
index 454ec698b91..5c8126898a8 100644
--- a/tests/codegen-llvm/autodiff/abi_handling.rs
+++ b/tests/codegen-llvm/autodiff/abi_handling.rs
@@ -1,7 +1,7 @@
 //@ revisions: debug release
 
-//@[debug] compile-flags: -Zautodiff=Enable -C opt-level=0 -Clto=fat
-//@[release] compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
+//@[debug] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat
+//@[release] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat
 //@ no-prefer-dynamic
 //@ needs-enzyme
 
diff --git a/tests/codegen-llvm/autodiff/batched.rs b/tests/codegen-llvm/autodiff/batched.rs
index 306a6ed9d1f..dc82403212f 100644
--- a/tests/codegen-llvm/autodiff/batched.rs
+++ b/tests/codegen-llvm/autodiff/batched.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3  -Clto=fat
 //@ no-prefer-dynamic
 //@ needs-enzyme
 //
diff --git a/tests/codegen-llvm/autodiff/scalar.rs b/tests/codegen-llvm/autodiff/scalar.rs
index 55b989f920d..53672a89230 100644
--- a/tests/codegen-llvm/autodiff/scalar.rs
+++ b/tests/codegen-llvm/autodiff/scalar.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3  -Clto=fat
 //@ no-prefer-dynamic
 //@ needs-enzyme
 #![feature(autodiff)]
diff --git a/tests/codegen-llvm/autodiff/sret.rs b/tests/codegen-llvm/autodiff/sret.rs
index dbc253ce894..498cd3fea01 100644
--- a/tests/codegen-llvm/autodiff/sret.rs
+++ b/tests/codegen-llvm/autodiff/sret.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -Zautodiff=Enable -C opt-level=3  -Clto=fat
+//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3  -Clto=fat
 //@ no-prefer-dynamic
 //@ needs-enzyme
 
diff --git a/tests/codegen-llvm/autodiff/void_ret.rs b/tests/codegen-llvm/autodiff/void_ret.rs
new file mode 100644
index 00000000000..98c6b98eef4
--- /dev/null
+++ b/tests/codegen-llvm/autodiff/void_ret.rs
@@ -0,0 +1,41 @@
+//@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C no-prepopulate-passes -C opt-level=3  -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+
+#![feature(autodiff)]
+use std::autodiff::*;
+
+// Usually we would store the return value of the differentiated function.
+// However, if the return type is void or an empty struct,
+// we don't need to store anything. Verify this, since it caused a bug.
+
+// CHECK:; void_ret::main
+// CHECK-NEXT:    ; Function Attrs:
+// CHECK-NEXT:    define internal
+// CHECK-NOT: store {} undef, ptr undef
+// CHECK: ret void
+
+#[autodiff_reverse(bar, Duplicated, Duplicated)]
+pub fn foo(r: &[f64; 10], res: &mut f64) {
+    let mut output = [0.0; 10];
+    output[0] = r[0];
+    output[1] = r[1] * r[2];
+    output[2] = r[4] * r[5];
+    output[3] = r[2] * r[6];
+    output[4] = r[1] * r[7];
+    output[5] = r[2] * r[8];
+    output[6] = r[1] * r[9];
+    output[7] = r[5] * r[6];
+    output[8] = r[5] * r[7];
+    output[9] = r[4] * r[8];
+    *res = output.iter().sum();
+}
+fn main() {
+    let inputs = Box::new([3.1; 10]);
+    let mut d_inputs = Box::new([0.0; 10]);
+    let mut res = Box::new(0.0);
+    let mut d_res = Box::new(1.0);
+
+    bar(&inputs, &mut d_inputs, &mut res, &mut d_res);
+    dbg!(&d_inputs);
+}
diff --git a/tests/codegen-llvm/debug-fndef-size.rs b/tests/codegen-llvm/debug-fndef-size.rs
index 8f716c34e7b..02629bd748c 100644
--- a/tests/codegen-llvm/debug-fndef-size.rs
+++ b/tests/codegen-llvm/debug-fndef-size.rs
@@ -16,5 +16,5 @@ pub fn main() {
 
 // CHECK: %compare.dbg.spill = alloca [0 x i8], align 1
 // CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression()
-// CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}})
-// CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8)
+// CHECK-DAG: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 8, dwarfAddressSpace: {{.*}})
+// CHECK-DAG: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 8)
diff --git a/tests/codegen-llvm/debuginfo-dse.rs b/tests/codegen-llvm/debuginfo-dse.rs
new file mode 100644
index 00000000000..fd0c9f1c676
--- /dev/null
+++ b/tests/codegen-llvm/debuginfo-dse.rs
@@ -0,0 +1,362 @@
+//@ compile-flags: -Copt-level=3 -g -Zverify-llvm-ir -Zmerge-functions=disabled
+//@ revisions: CODEGEN OPTIMIZED
+//@[CODEGEN] compile-flags: -Cno-prepopulate-passes
+//@ only-64bit
+// ignore-tidy-linelength
+
+#![crate_type = "lib"]
+#![feature(repr_simd, rustc_attrs)]
+
+// The pass mode is direct and the backend represent is scalar.
+type Scalar = i32; // scalar(i32)
+type Scalar_Ref = &'static i32; // scalar(ptr)
+
+// The pass modes are pair and the backend represents are scalar pair.
+type Tuple_Scalar_Scalar = (i32, i32);
+struct Tuple_Ref_Scalar(&'static i32, i32);
+struct Tuple_ArrayRef_Scalar(&'static [i32; 16], i32); // pair(ptr, i32)
+impl Default for Tuple_ArrayRef_Scalar {
+    fn default() -> Tuple_ArrayRef_Scalar {
+        Tuple_ArrayRef_Scalar(&[0; 16], 0)
+    }
+}
+struct Tuple_Scalar_ArrayRef(i32, &'static [i32; 16]); // pair(i32, ptr)
+impl Default for Tuple_Scalar_ArrayRef {
+    fn default() -> Tuple_Scalar_ArrayRef {
+        Tuple_Scalar_ArrayRef(0, &[0; 16])
+    }
+}
+// The pass mode is indirect and the backend represent is memory.
+type Tuple_SliceRef_Scalar = (&'static [i32], i32);
+
+// The pass mode is pair and the backend represent is scalar pair.
+type SliceRef = &'static [i32]; // pair(ptr, i32)
+// The pass mode is indirect and the backend represent is memory.
+type Array = [i32; 16];
+// The pass mode is direct and the backend represent is scalar.
+type ArrayRef = &'static [i32; 16];
+
+// The pass mode is indirect and the backend represent is memory.
+type Typle_i32_i64_i8 = (i32, i64, i8);
+// The pass mode is indirect and the backend represent is memory.
+#[repr(C)]
+struct Aggregate_i32_Array_i8(i32, &'static [i32; 16], i8);
+
+type ZST = ();
+
+impl Default for Aggregate_i32_Array_i8 {
+    fn default() -> Aggregate_i32_Array_i8 {
+        Aggregate_i32_Array_i8(0, &[0; 16], 0)
+    }
+}
+// The pass mode is cast and the backend represent is scalar.
+#[derive(Default)]
+struct Aggregate_4xi8(i8, i8, i8, i8); // scalar(i32)
+
+// The pass mode is indirect and the backend represent is simd vector.
+#[repr(simd)]
+struct Simd_i32x4([i32; 4]);
+
+unsafe extern "Rust" {
+    #[rustc_nounwind]
+    safe fn opaque_fn();
+    #[rustc_nounwind]
+    safe fn opaque_ptr(_: *const core::ffi::c_void);
+}
+
+#[inline(never)]
+#[rustc_nounwind]
+fn opaque_use<T>(p: &T) {
+    opaque_ptr(&raw const p as *const _);
+}
+
+#[inline(never)]
+#[rustc_nounwind]
+fn opaque_read<T: Default>() -> T {
+    core::hint::black_box(T::default())
+}
+
+#[unsafe(no_mangle)]
+fn local_var() {
+    // CHECK-LABEL: define{{( dso_local)?}} void @local_var
+    let local_var_scalar: Scalar = opaque_read();
+    opaque_use(&local_var_scalar);
+    let dead_local_var_scalar: Scalar = opaque_read();
+    let local_var_aggregate_4xi8: Aggregate_4xi8 = opaque_read();
+    opaque_use(&local_var_aggregate_4xi8);
+    let local_var_aggregate_i32_array_i8: Aggregate_i32_Array_i8 = opaque_read();
+    opaque_use(&local_var_aggregate_i32_array_i8);
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr %local_var_scalar, [[ref_local_var_scalar:![0-9]+]], !DIExpression()
+    let ref_local_var_scalar = &local_var_scalar;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_dead_local_var_scalar:![0-9]+]], !DIExpression()
+    let ref_dead_local_var_scalar = &dead_local_var_scalar;
+    // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_local_var_aggregate_4xi8:![0-9]+]], !DIExpression()
+    let ref_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8;
+    // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_0_local_var_aggregate_4xi8:![0-9]+]], !DIExpression()
+    let ref_0_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.0;
+    // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_4xi8, [[ref_2_local_var_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 2, DW_OP_stack_value)
+    let ref_2_local_var_aggregate_4xi8 = &local_var_aggregate_4xi8.2;
+    // This introduces an extra load instruction.
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression()
+    let ref_1_1_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.1[1];
+    // CHECK-NEXT: #dbg_value(ptr %local_var_aggregate_i32_array_i8, [[ref_2_local_var_aggregate_i32_array_i8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value)
+    let ref_2_local_var_aggregate_i32_array_i8 = &local_var_aggregate_i32_array_i8.2;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+#[unsafe(no_mangle)]
+fn zst(zst: ZST, zst_ref: &ZST) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @zst
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst:![0-9]+]], !DIExpression()
+    let ref_zst = &zst;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_zst_ref:![0-9]+]], !DIExpression()
+    let ref_zst_ref = &zst_ref;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+// It only makes sense if the argument is a reference and it refer to projections.
+#[unsafe(no_mangle)]
+fn direct(
+    scalar: Scalar,
+    scalar_ref: Scalar_Ref,
+    array_ref: ArrayRef,
+    aggregate_4xi8_ref: &Aggregate_4xi8,
+) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @direct
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar:![0-9]+]], !DIExpression()
+    let ref_scalar = &scalar;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_scalar_ref:![0-9]+]], !DIExpression()
+    let ref_scalar_ref = &scalar_ref;
+    // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_0_array_ref:![0-9]+]], !DIExpression()
+    let ref_0_array_ref = &array_ref[0];
+    // CHECK-NEXT: #dbg_value(ptr %array_ref, [[ref_1_array_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)
+    let ref_1_array_ref = &array_ref[1];
+    // CHECK-NEXT: #dbg_value(ptr %aggregate_4xi8_ref, [[ref_1_aggregate_4xi8_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)
+    let ref_1_aggregate_4xi8_ref = &aggregate_4xi8_ref.1;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+// Arguments are passed through registers, the final values are poison.
+#[unsafe(no_mangle)]
+fn cast(aggregate_4xi8: Aggregate_4xi8) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @cast(i32 %0)
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // The temporary allocated variable is eliminated.
+    // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression()
+    // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_aggregate_4xi8:![0-9]+]], !DIExpression()
+    let ref_aggregate_4xi8 = &aggregate_4xi8;
+    // CODEGEN-NEXT: #dbg_value(ptr %aggregate_4xi8, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)
+    // OPTIMIZED-NEXT: #dbg_value(ptr undef, [[ref_0_aggregate_4xi8:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 1, DW_OP_stack_value)
+    let ref_0_aggregate_4xi8 = &aggregate_4xi8.1;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+// Arguments are passed indirectly via a pointer.
+// The reference of argument is the pointer itself.
+#[unsafe(no_mangle)]
+fn indirect(
+    tuple_sliceref_scalar: Tuple_SliceRef_Scalar,
+    array: Array,
+    typle_i32_i64_i8: Typle_i32_i64_i8,
+    simd_i32x4: Simd_i32x4,
+) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @indirect
+    // CHECK-SAME: (ptr{{.*}} %tuple_sliceref_scalar, ptr{{.*}} %array, ptr{{.*}} %typle_i32_i64_i8, ptr{{.*}} %simd_i32x4)
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_tuple_sliceref_scalar:![0-9]+]], !DIExpression()
+    let ref_tuple_sliceref_scalar = &tuple_sliceref_scalar;
+    // CHECK-NEXT: #dbg_value(ptr %tuple_sliceref_scalar, [[ref_1_tuple_sliceref_scalar:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 16, DW_OP_stack_value)
+    let ref_1_tuple_sliceref_scalar = &tuple_sliceref_scalar.1;
+    // CHECK-NEXT: #dbg_value(ptr %array, [[ref_1_array:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)
+    let ref_1_array = &array[1];
+    // CHECK-NEXT: #dbg_value(ptr %typle_i32_i64_i8, [[ref_1_typle_i32_i64_i8:![0-9]+]], !DIExpression()
+    let ref_1_typle_i32_i64_i8 = &typle_i32_i64_i8.1;
+    // CHECK-NEXT: #dbg_value(ptr %simd_i32x4, [[ref_simd_i32x4:![0-9]+]], !DIExpression()
+    let ref_simd_i32x4 = &simd_i32x4;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+// They are different MIR statements, but they have the same LLVM IR statement due to the ABI of arguments.
+// Both `direct_ref` and `indirect_byval` are passed as a pointer here.
+#[unsafe(no_mangle)]
+fn direct_ref_and_indirect(
+    direct_ref: &Aggregate_i32_Array_i8,
+    indirect_byval: Aggregate_i32_Array_i8,
+) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @direct_ref_and_indirect
+    // CHECK-SAME: (ptr{{.*}} %direct_ref, ptr{{.*}} %indirect_byval)
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_direct_ref:![0-9]+]], !DIExpression()
+    let ref_direct_ref: &&Aggregate_i32_Array_i8 = &direct_ref;
+    // CHECK-NEXT: #dbg_value(ptr %direct_ref, [[ref_1_direct_ref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)
+    let ref_1_direct_ref = &direct_ref.1;
+    // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_indirect_byval:![0-9]+]], !DIExpression()
+    let ref_indirect_byval: &Aggregate_i32_Array_i8 = &indirect_byval;
+    // CHECK-NEXT: #dbg_value(ptr %indirect_byval, [[ref_1_indirect_byval:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_stack_value)
+    let ref_1_indirect_byval = &indirect_byval.1;
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+#[unsafe(no_mangle)]
+fn pair(
+    tuple_scalar_scalar: Tuple_Scalar_Scalar,
+    tuple_ref_scalar: Tuple_Ref_Scalar,
+    tuple_arrayref_scalar: Tuple_ArrayRef_Scalar,
+    tuple_scalar_arrayref: Tuple_Scalar_ArrayRef,
+    sliceref: SliceRef,
+) {
+    // CHECK-LABEL: define{{( dso_local)?}} void @pair
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_scalar_scalar:![0-9]+]], !DIExpression()
+    let ref_0_tuple_scalar_scalar = &tuple_scalar_scalar.0;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_ref_scalar:![0-9]+]], !DIExpression()
+    let ref_0_tuple_ref_scalar = &tuple_ref_scalar.0;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_ref_scalar:![0-9]+]], !DIExpression()
+    let ref_1_tuple_ref_scalar = &tuple_ref_scalar.1;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_tuple_arrayref_scalar:![0-9]+]], !DIExpression()
+    let ref_0_tuple_arrayref_scalar = &tuple_arrayref_scalar.0;
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression()
+    let ref_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.1;
+    // FIXME: This can be a valid value.
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_0_1_tuple_arrayref_scalar:![0-9]+]], !DIExpression()
+    let ref_0_1_tuple_arrayref_scalar = &tuple_arrayref_scalar.0[1];
+    // FIXME: This can be a valid value.
+    // CHECK-NEXT: #dbg_value(ptr poison, [[ref_1_1_tuple_scalar_arrayref:![0-9]+]], !DIExpression()
+    let ref_1_1_tuple_scalar_arrayref = &tuple_scalar_arrayref.1[1];
+    // CHECK: #dbg_value(ptr %sliceref.0, [[ref_1_sliceref:![0-9]+]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_stack_value)
+    let ref_1_sliceref = &sliceref[1];
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Foo(i32, i64, i32);
+
+#[repr(C)]
+pub struct Bar<'a> {
+    a: i32,
+    b: i64,
+    foo: &'a Foo,
+}
+
+#[unsafe(no_mangle)]
+pub fn dead_first(dead_first_foo: &Foo) -> &i32 {
+    // CHECK-LABEL: def {{.*}} ptr @dead_first
+    // CHECK-SAME: (ptr {{.*}} [[ARG_dead_first_foo:%.*]])
+    // CODEGEN: #dbg_declare(ptr %dead_first_foo.dbg.spill, [[ARG_dead_first_foo:![0-9]+]], !DIExpression()
+    // OPTIMIZED: #dbg_value(ptr %dead_first_foo, [[ARG_dead_first_foo:![0-9]+]], !DIExpression()
+    // CHECK: #dbg_value(ptr %dead_first_foo, [[VAR_dead_first_v0:![0-9]+]], !DIExpression()
+    // CHECK: %dead_first_v0 = getelementptr{{.*}} i8, ptr %dead_first_foo, i64 16
+    // CODEGEN: #dbg_declare(ptr %dead_first_v0.dbg.spill, [[VAR_dead_first_v0]], !DIExpression()
+    // OPTIMIZED: #dbg_value(ptr %dead_first_v0, [[VAR_dead_first_v0]], !DIExpression()
+    let mut dead_first_v0 = &dead_first_foo.0;
+    dead_first_v0 = &dead_first_foo.2;
+    dead_first_v0
+}
+
+#[unsafe(no_mangle)]
+pub fn fragment(fragment_v1: Foo, mut fragment_v2: Foo) -> Foo {
+    // CHECK-LABEL: define{{( dso_local)?}} void @fragment
+    // CHECK-SAME: (ptr {{.*}}, ptr {{.*}} [[ARG_fragment_v1:%.*]], ptr {{.*}} [[ARG_fragment_v2:%.*]])
+    // CHECK: #dbg_declare(ptr [[ARG_fragment_v1]]
+    // CHECK-NEXT: #dbg_declare(ptr [[ARG_fragment_v2]]
+    // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v2]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 0, 64)
+    // CHECK-NEXT: #dbg_value(ptr [[ARG_fragment_v1]], [[VAR_fragment_f:![0-9]+]], !DIExpression(DW_OP_LLVM_fragment, 64, 64)
+    let fragment_f = || {
+        fragment_v2 = fragment_v1;
+    };
+    fragment_v2 = fragment_v1;
+    fragment_v2
+}
+
+#[unsafe(no_mangle)]
+pub fn deref(bar: Bar) -> i32 {
+    // CHECK-LABEL: define{{.*}} i32 @deref
+    // We are unable to represent dereference within this expression.
+    // CHECK: #dbg_value(ptr poison, [[VAR_deref_dead:![0-9]+]], !DIExpression()
+    let deref_dead = &bar.foo.2;
+    bar.a
+}
+
+#[unsafe(no_mangle)]
+fn index(slice: &[i32; 4], idx: usize) -> i32 {
+    // CHECK-LABEL: define{{.*}} i32 @index
+    // CHECK: call void @opaque_fn()
+    opaque_fn();
+    // CHECK: #dbg_value(ptr poison, [[VAR_index_from_var:![0-9]+]], !DIExpression()
+    let index_from_var = &slice[idx];
+    // CHECK: #dbg_value(ptr %slice, [[VAR_const_index_from_start:![0-9]+]], !DIExpression()
+    // CHECK-NEXT: #dbg_value(ptr poison, [[VAR_const_index_from_end:![0-9]+]], !DIExpression()
+    let [ref const_index_from_start, .., ref const_index_from_end] = slice[..] else {
+        return 0;
+    };
+    slice[0]
+}
+
+// CHECK-DAG: [[ref_local_var_scalar]] = !DILocalVariable(name: "ref_local_var_scalar"
+// CHECK-DAG: [[ref_dead_local_var_scalar]] = !DILocalVariable(name: "ref_dead_local_var_scalar"
+// CHECK-DAG: [[ref_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_local_var_aggregate_4xi8"
+// CHECK-DAG: [[ref_0_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_local_var_aggregate_4xi8"
+// CHECK-DAG: [[ref_2_local_var_aggregate_4xi8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_4xi8"
+// CHECK-DAG: [[ref_1_1_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_1_1_local_var_aggregate_i32_array_i8"
+// CHECK-DAG: [[ref_2_local_var_aggregate_i32_array_i8]] = !DILocalVariable(name: "ref_2_local_var_aggregate_i32_array_i8"
+
+// CHECK-DAG: [[ref_zst]] = !DILocalVariable(name: "ref_zst"
+// CHECK-DAG: [[ref_zst_ref]] = !DILocalVariable(name: "ref_zst_ref"
+
+// CHECK-DAG: [[ref_scalar]] = !DILocalVariable(name: "ref_scalar"
+// CHECK-DAG: [[ref_scalar_ref]] = !DILocalVariable(name: "ref_scalar_ref"
+// CHECK-DAG: [[ref_0_array_ref]] = !DILocalVariable(name: "ref_0_array_ref"
+// CHECK-DAG: [[ref_1_array_ref]] = !DILocalVariable(name: "ref_1_array_ref"
+// CHECK-DAG: [[ref_1_aggregate_4xi8_ref]] = !DILocalVariable(name: "ref_1_aggregate_4xi8_ref"
+
+// CHECK-DAG: [[ref_aggregate_4xi8]] = !DILocalVariable(name: "ref_aggregate_4xi8"
+// CHECK-DAG: [[ref_0_aggregate_4xi8]] = !DILocalVariable(name: "ref_0_aggregate_4xi8"
+
+// CHECK-DAG: [[ref_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_tuple_sliceref_scalar"
+// CHECK-DAG: [[ref_1_tuple_sliceref_scalar]] = !DILocalVariable(name: "ref_1_tuple_sliceref_scalar"
+// CHECK-DAG: [[ref_1_array]] = !DILocalVariable(name: "ref_1_array"
+// CHECK-DAG: [[ref_1_typle_i32_i64_i8]] = !DILocalVariable(name: "ref_1_typle_i32_i64_i8"
+// CHECK-DAG: [[ref_simd_i32x4]] = !DILocalVariable(name: "ref_simd_i32x4"
+
+// CHECK-DAG: [[ref_direct_ref]] = !DILocalVariable(name: "ref_direct_ref"
+// CHECK-DAG: [[ref_1_direct_ref]] = !DILocalVariable(name: "ref_1_direct_ref"
+// CHECK-DAG: [[ref_indirect_byval]] = !DILocalVariable(name: "ref_indirect_byval"
+// CHECK-DAG: [[ref_1_indirect_byval]] = !DILocalVariable(name: "ref_1_indirect_byval"
+
+// CHECK-DAG: [[ref_0_tuple_scalar_scalar]] = !DILocalVariable(name: "ref_0_tuple_scalar_scalar"
+// CHECK-DAG: [[ref_0_tuple_ref_scalar]] = !DILocalVariable(name: "ref_0_tuple_ref_scalar"
+// CHECK-DAG: [[ref_1_tuple_ref_scalar]] = !DILocalVariable(name: "ref_1_tuple_ref_scalar"
+// CHECK-DAG: [[ref_0_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_tuple_arrayref_scalar"
+// CHECK-DAG: [[ref_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_1_tuple_arrayref_scalar"
+// CHECK-DAG: [[ref_0_1_tuple_arrayref_scalar]] = !DILocalVariable(name: "ref_0_1_tuple_arrayref_scalar"
+// CHECK-DAG: [[ref_1_1_tuple_scalar_arrayref]] = !DILocalVariable(name: "ref_1_1_tuple_scalar_arrayref"
+// CHECK-DAG: [[ref_1_sliceref]] = !DILocalVariable(name: "ref_1_sliceref"
+
+// CHECK-DAG: [[ARG_dead_first_foo]] = !DILocalVariable(name: "dead_first_foo"
+// CHECK-DAG: [[VAR_dead_first_v0]] = !DILocalVariable(name: "dead_first_v0"
+
+// CHECK-DAG: [[VAR_fragment_f]] = !DILocalVariable(name: "fragment_f"
+
+// CHECK-DAG: [[VAR_deref_dead]] = !DILocalVariable(name: "deref_dead"
+
+// CHECK-DAG: [[VAR_index_from_var]] = !DILocalVariable(name: "index_from_var"
+// CHECK-DAG: [[VAR_const_index_from_start]] = !DILocalVariable(name: "const_index_from_start"
+// CHECK-DAG: [[VAR_const_index_from_end]] = !DILocalVariable(name: "const_index_from_end"
diff --git a/tests/crashes/120016.rs b/tests/crashes/120016.rs
index 7eda330e7ad..12f54dbc3d9 100644
--- a/tests/crashes/120016.rs
+++ b/tests/crashes/120016.rs
@@ -1,19 +1,19 @@
 //@ known-bug: #120016
-//@ compile-flags: -Zcrate-attr=feature(const_async_blocks)
+//@ compile-flags: -Zvalidate-mir
 //@ edition: 2021
 
-#![feature(type_alias_impl_trait, const_async_blocks)]
+#![feature(type_alias_impl_trait)]
 
 struct Bug {
     V1: [(); {
-        type F = impl std::future::Future<Output = impl Sized>;
+        type F = impl Sized;
         #[define_opaque(F)]
         fn concrete_use() -> F {
-            //~^ ERROR to be a future that resolves to `u8`, but it resolves to `()`
-            async {}
+            //~^ ERROR
+            1i32
         }
-        let f: F = async { 1 };
-        //~^ ERROR `async` blocks are not allowed in constants
+        let f: F = 0u32;
+
         1
     }],
 }
diff --git a/tests/debuginfo/opt/dead_refs.rs b/tests/debuginfo/opt/dead_refs.rs
new file mode 100644
index 00000000000..61e74157334
--- /dev/null
+++ b/tests/debuginfo/opt/dead_refs.rs
@@ -0,0 +1,50 @@
+//@ min-lldb-version: 1800
+//@ min-gdb-version: 13.0
+//@ compile-flags: -g -Copt-level=3
+//@ disable-gdb-pretty-printers
+
+// Checks that we still can access dead variables from debuginfos.
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:print *ref_v0
+// gdb-check:$1 = 0
+
+// gdb-command:print *ref_v1
+// gdb-check:$2 = 1
+
+// gdb-command:print *ref_v2
+// gdb-check:$3 = 2
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+// lldb-command:v *ref_v0
+// lldb-check:[...] 0
+
+// lldb-command:v *ref_v1
+// lldb-check:[...] 1
+
+// lldb-command:v *ref_v2
+// lldb-check:[...] 2
+
+#![allow(unused_variables)]
+
+use std::hint::black_box;
+
+pub struct Foo(i32, i64, i32);
+
+#[inline(never)]
+#[no_mangle]
+fn test_ref(ref_foo: &Foo) -> i32 {
+    let ref_v0 = &ref_foo.0;
+    let ref_v1 = &ref_foo.1;
+    let ref_v2 = &ref_foo.2;
+    ref_foo.0 // #break
+}
+
+fn main() {
+    let foo = black_box(Foo(0, 1, 2));
+    black_box(test_ref(&foo));
+}
diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
index a18d7e7478f..a1fe278c652 100644
--- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
@@ -1,30 +1,30 @@
 // MIR for `address_of_reborrow` after SimplifyCfg-initial
 
 | User Type Annotations
-| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
+| 0: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:8:10: 8:18, inferred_ty: *const [i32; 10]
 | 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:10:10: 10:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 2: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10]
 | 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
 | 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10]
 | 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send
 | 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
 | 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
+| 10: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:19:10: 19:18, inferred_ty: *const [i32; 10]
 | 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:21:10: 21:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 12: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { value: Ty(*const ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10]
 | 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
 | 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10]
 | 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send
 | 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
 | 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
+| 20: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:29:10: 29:16, inferred_ty: *mut [i32; 10]
 | 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:31:10: 31:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 22: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { value: Ty(*mut ^c_0), max_universe: U0, variables: [Ty { ui: U0, sub_root: 0 }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10]
 | 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
 | 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10]
 | 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [Region(U0)] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send
diff --git a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff
index ff18df1efcf..d584de6861c 100644
--- a/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff
+++ b/tests/mir-opt/dead-store-elimination/cycle.cycle.DeadStoreElimination-initial.diff
@@ -19,10 +19,6 @@
 -         _3 = copy _2;
 -         _2 = copy _1;
 -         _1 = copy _5;
-+         nop;
-+         nop;
-+         nop;
-+         nop;
           _4 = cond() -> [return: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff
new file mode 100644
index 00000000000..2a793e24990
--- /dev/null
+++ b/tests/mir-opt/dead-store-elimination/ref.dead_first.DeadStoreElimination-initial.diff
@@ -0,0 +1,30 @@
+- // MIR for `dead_first` before DeadStoreElimination-initial
++ // MIR for `dead_first` after DeadStoreElimination-initial
+  
+  fn dead_first(_1: &Foo) -> &i32 {
+      debug v => _1;
+      let mut _0: &i32;
+      let mut _2: &i32;
+      let mut _3: &i32;
+      let _4: &i32;
+      scope 1 {
+          debug a => _2;
+      }
+  
+      bb0: {
+          StorageLive(_2);
+-         _2 = &((*_1).2: i32);
++         // DBG: _2 = &((*_1).2: i32);
+          StorageLive(_3);
+          StorageLive(_4);
+          _4 = &((*_1).0: i32);
+          _3 = &(*_4);
+          _2 = move _3;
+          StorageDead(_3);
+          StorageDead(_4);
+          _0 = &(*_2);
+          StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/dead-store-elimination/ref.rs b/tests/mir-opt/dead-store-elimination/ref.rs
new file mode 100644
index 00000000000..2d3200edab9
--- /dev/null
+++ b/tests/mir-opt/dead-store-elimination/ref.rs
@@ -0,0 +1,31 @@
+//@ test-mir-pass: DeadStoreElimination-initial
+
+pub struct Foo {
+    a: i32,
+    b: i64,
+    c: i32,
+}
+
+// EMIT_MIR ref.tuple.DeadStoreElimination-initial.diff
+pub fn tuple(v: (i32, &Foo)) -> i32 {
+    // CHECK-LABEL: fn tuple
+    // CHECK: debug _dead => [[dead:_[0-9]+]];
+    // CHECK: bb0:
+    // CHECK: DBG: [[dead]] = &((*_3).2: i32)
+    let _dead = &v.1.c;
+    v.1.a
+}
+
+// EMIT_MIR ref.dead_first.DeadStoreElimination-initial.diff
+pub fn dead_first(v: &Foo) -> &i32 {
+    // CHECK-LABEL: fn dead_first
+    // CHECK: debug a => [[var_a:_[0-9]+]];
+    // CHECK: bb0:
+    // CHECK: DBG: [[var_a]] = &((*_1).2: i32)
+    // CHECK: [[tmp_4:_[0-9]+]] = &((*_1).0: i32)
+    // CHECK: [[tmp_3:_[0-9]+]] = &(*[[tmp_4]])
+    // CHECK: [[var_a]] = move [[tmp_3]]
+    let mut a = &v.c;
+    a = &v.a;
+    a
+}
diff --git a/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff
new file mode 100644
index 00000000000..0b96569cbe4
--- /dev/null
+++ b/tests/mir-opt/dead-store-elimination/ref.tuple.DeadStoreElimination-initial.diff
@@ -0,0 +1,25 @@
+- // MIR for `tuple` before DeadStoreElimination-initial
++ // MIR for `tuple` after DeadStoreElimination-initial
+  
+  fn tuple(_1: (i32, &Foo)) -> i32 {
+      debug v => _1;
+      let mut _0: i32;
+      let _2: &i32;
+      let mut _3: &Foo;
+      let mut _4: &Foo;
+      scope 1 {
+          debug _dead => _2;
+      }
+  
+      bb0: {
+-         StorageLive(_2);
+-         _3 = deref_copy (_1.1: &Foo);
+-         _2 = &((*_3).2: i32);
++         // DBG: _2 = &((*_3).2: i32);
+          _4 = deref_copy (_1.1: &Foo);
+          _0 = copy ((*_4).0: i32);
+-         StorageDead(_2);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff
new file mode 100644
index 00000000000..d4a73351ee4
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff
@@ -0,0 +1,26 @@
+- // MIR for `drop_debuginfo` before SimplifyCfg-final
++ // MIR for `drop_debuginfo` after SimplifyCfg-final
+  
+  fn drop_debuginfo(_1: &Foo, _2: bool) -> i32 {
+      debug foo_a => _3;
+      debug foo_b => _4;
+      let mut _0: i32;
+      let mut _3: &i32;
+      let mut _4: &i64;
+  
+      bb0: {
+-         switchInt(copy _2) -> [1: bb1, otherwise: bb2];
+-     }
+- 
+-     bb1: {
+-         // DBG: _3 = &((*_1).0: i32);
+-         goto -> bb2;
+-     }
+- 
+-     bb2: {
+          // DBG: _4 = &((*_1).1: i64);
+          _0 = copy ((*_1).2: i32);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff
new file mode 100644
index 00000000000..1c12358ad89
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff
@@ -0,0 +1,30 @@
+- // MIR for `preserve_debuginfo_1` before SimplifyCfg-final
++ // MIR for `preserve_debuginfo_1` after SimplifyCfg-final
+  
+  fn preserve_debuginfo_1(_1: &Foo, _2: &mut bool) -> i32 {
+      debug foo_a => _3;
+      debug foo_b => _4;
+      debug foo_c => _5;
+      let mut _0: i32;
+      let mut _3: &i32;
+      let mut _4: &i64;
+      let mut _5: &i32;
+  
+      bb0: {
+-         goto -> bb1;
+-     }
+- 
+-     bb1: {
+          (*_2) = const true;
+          // DBG: _3 = &((*_1).0: i32);
+-         goto -> bb2;
+-     }
+- 
+-     bb2: {
+          // DBG: _4 = &((*_1).1: i64);
+          _0 = copy ((*_1).2: i32);
+          // DBG: _5 = &((*_1).2: i32);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff
new file mode 100644
index 00000000000..de8e5612c87
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff
@@ -0,0 +1,29 @@
+- // MIR for `preserve_debuginfo_2` before SimplifyCfg-final
++ // MIR for `preserve_debuginfo_2` after SimplifyCfg-final
+  
+  fn preserve_debuginfo_2(_1: &Foo) -> i32 {
+      debug foo_a => _2;
+      debug foo_b => _3;
+      debug foo_c => _4;
+      let mut _0: i32;
+      let mut _2: &i32;
+      let mut _3: &i64;
+      let mut _4: &i32;
+  
+      bb0: {
+-         goto -> bb1;
+-     }
+- 
+-     bb1: {
+          // DBG: _2 = &((*_1).0: i32);
+-         goto -> bb2;
+-     }
+- 
+-     bb2: {
+          // DBG: _3 = &((*_1).1: i64);
+          _0 = copy ((*_1).2: i32);
+          // DBG: _4 = &((*_1).2: i32);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff
new file mode 100644
index 00000000000..11372a262a7
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff
@@ -0,0 +1,37 @@
+- // MIR for `preserve_debuginfo_3` before SimplifyCfg-final
++ // MIR for `preserve_debuginfo_3` after SimplifyCfg-final
+  
+  fn preserve_debuginfo_3(_1: &Foo, _2: bool) -> i32 {
+      debug foo_a => _3;
+      debug foo_b => _4;
+      debug foo_c => _5;
+      let mut _0: i32;
+      let mut _3: &i32;
+      let mut _4: &i64;
+      let mut _5: &i32;
+  
+      bb0: {
+-         switchInt(copy _2) -> [1: bb1, otherwise: bb2];
++         switchInt(copy _2) -> [1: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+-         // DBG: _3 = &((*_1).0: i32);
+-         goto -> bb3;
+-     }
+- 
+-     bb2: {
+          // DBG: _4 = &((*_1).1: i64);
+          _0 = copy ((*_1).2: i32);
+          return;
+      }
+  
+-     bb3: {
++     bb2: {
++         // DBG: _3 = &((*_1).0: i32);
+          // DBG: _5 = &((*_1).2: i32);
+          _0 = copy ((*_1).0: i32);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff
new file mode 100644
index 00000000000..0c6a75237d8
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff
@@ -0,0 +1,29 @@
+- // MIR for `preserve_debuginfo_identical_succs` before SimplifyCfg-final
++ // MIR for `preserve_debuginfo_identical_succs` after SimplifyCfg-final
+  
+  fn preserve_debuginfo_identical_succs(_1: &Foo, _2: bool) -> i32 {
+      debug foo_a => _3;
+      debug foo_b => _4;
+      debug foo_c => _5;
+      let mut _0: i32;
+      let mut _3: &i32;
+      let mut _4: &i64;
+      let mut _5: &i32;
+  
+      bb0: {
+-         switchInt(copy _2) -> [1: bb1, otherwise: bb1];
+-     }
+- 
+-     bb1: {
+          // DBG: _3 = &((*_1).0: i32);
+-         goto -> bb2;
+-     }
+- 
+-     bb2: {
+          // DBG: _4 = &((*_1).1: i64);
+          _0 = copy ((*_1).2: i32);
+          // DBG: _5 = &((*_1).2: i32);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/debuginfo/simplifycfg.rs b/tests/mir-opt/debuginfo/simplifycfg.rs
new file mode 100644
index 00000000000..2bd510fd3b9
--- /dev/null
+++ b/tests/mir-opt/debuginfo/simplifycfg.rs
@@ -0,0 +1,207 @@
+//@ test-mir-pass: SimplifyCfg-final
+//@ compile-flags: -Zmir-enable-passes=+DeadStoreElimination-initial
+
+#![feature(core_intrinsics, custom_mir)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+pub struct Foo {
+    a: i32,
+    b: i64,
+    c: i32,
+}
+
+// EMIT_MIR simplifycfg.drop_debuginfo.SimplifyCfg-final.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn drop_debuginfo(foo: &Foo, c: bool) -> i32 {
+    // CHECK-LABEL: fn drop_debuginfo
+    // CHECK: debug foo_b => [[foo_b:_[0-9]+]];
+    // CHECK: bb0: {
+    // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64)
+    // CHECK-NEXT: _0 = copy ((*_1).2: i32);
+    // CHECK-NEXT: return;
+    mir! {
+        let _foo_a: &i32;
+        let _foo_b: &i64;
+        debug foo_a => _foo_a;
+        debug foo_b => _foo_b;
+        {
+            match c {
+                true => tmp,
+                _ => ret,
+            }
+        }
+        tmp = {
+            // Because we don't know if `c` is always true, we must drop this debuginfo.
+            _foo_a = &(*foo).a;
+            Goto(ret)
+        }
+        ret = {
+            _foo_b = &(*foo).b;
+            RET = (*foo).c;
+            Return()
+        }
+    }
+}
+
+// EMIT_MIR simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn preserve_debuginfo_1(foo: &Foo, v: &mut bool) -> i32 {
+    // CHECK-LABEL: fn preserve_debuginfo_1
+    // CHECK: debug foo_a => [[foo_a:_[0-9]+]];
+    // CHECK: debug foo_b => [[foo_b:_[0-9]+]];
+    // CHECK: debug foo_c => [[foo_c:_[0-9]+]];
+    // CHECK: bb0: {
+    // CHECK-NEXT: (*_2) = const true;
+    // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32)
+    // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64)
+    // CHECK-NEXT: _0 = copy ((*_1).2: i32);
+    // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32)
+    // CHECK-NEXT: return;
+    mir! {
+        let _foo_a: &i32;
+        let _foo_b: &i64;
+        let _foo_c: &i32;
+        debug foo_a => _foo_a;
+        debug foo_b => _foo_b;
+        debug foo_c => _foo_c;
+        {
+            Goto(tmp)
+        }
+        tmp = {
+            *v = true;
+            _foo_a = &(*foo).a;
+            Goto(ret)
+        }
+        ret = {
+            _foo_b = &(*foo).b;
+            RET = (*foo).c;
+            _foo_c = &(*foo).c;
+            Return()
+        }
+    }
+}
+
+// EMIT_MIR simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn preserve_debuginfo_2(foo: &Foo) -> i32 {
+    // CHECK-LABEL: fn preserve_debuginfo_2
+    // CHECK: debug foo_a => [[foo_a:_[0-9]+]];
+    // CHECK: debug foo_b => [[foo_b:_[0-9]+]];
+    // CHECK: debug foo_c => [[foo_c:_[0-9]+]];
+    // CHECK: bb0: {
+    // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32)
+    // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64)
+    // CHECK-NEXT: _0 = copy ((*_1).2: i32);
+    // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32)
+    // CHECK-NEXT: return;
+    mir! {
+        let _foo_a: &i32;
+        let _foo_b: &i64;
+        let _foo_c: &i32;
+        debug foo_a => _foo_a;
+        debug foo_b => _foo_b;
+        debug foo_c => _foo_c;
+        {
+            Goto(tmp)
+        }
+        tmp = {
+            _foo_a = &(*foo).a;
+            Goto(ret)
+        }
+        ret = {
+            _foo_b = &(*foo).b;
+            RET = (*foo).c;
+            _foo_c = &(*foo).c;
+            Return()
+        }
+    }
+}
+
+// EMIT_MIR simplifycfg.preserve_debuginfo_3.SimplifyCfg-final.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn preserve_debuginfo_3(foo: &Foo, c: bool) -> i32 {
+    // CHECK-LABEL: fn preserve_debuginfo_3
+    // CHECK: debug foo_a => [[foo_a:_[0-9]+]];
+    // CHECK: debug foo_b => [[foo_b:_[0-9]+]];
+    // CHECK: debug foo_c => [[foo_c:_[0-9]+]];
+    // CHECK: bb0: {
+    // CHECK-NEXT: switchInt(copy _2) -> [1: bb2, otherwise: bb1];
+    // CHECK: bb1: {
+    // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64)
+    // CHECK-NEXT: _0 = copy ((*_1).2: i32);
+    // CHECK-NEXT: return;
+    // CHECK: bb2: {
+    // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32)
+    // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32)
+    // CHECK-NEXT: _0 = copy ((*_1).0: i32);
+    // CHECK-NEXT: return;
+    mir! {
+        let _foo_a: &i32;
+        let _foo_b: &i64;
+        let _foo_c: &i32;
+        debug foo_a => _foo_a;
+        debug foo_b => _foo_b;
+        debug foo_c => _foo_c;
+        {
+            match c {
+                true => tmp,
+                _ => ret,
+            }
+        }
+        tmp = {
+            _foo_a = &(*foo).a;
+            Goto(ret_1)
+        }
+        ret = {
+            _foo_b = &(*foo).b;
+            RET = (*foo).c;
+            Return()
+        }
+        ret_1 = {
+            _foo_c = &(*foo).c;
+            RET = (*foo).a;
+            Return()
+        }
+    }
+}
+
+// EMIT_MIR simplifycfg.preserve_debuginfo_identical_succs.SimplifyCfg-final.diff
+#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
+pub fn preserve_debuginfo_identical_succs(foo: &Foo, c: bool) -> i32 {
+    // CHECK-LABEL: fn preserve_debuginfo_identical_succs
+    // CHECK: debug foo_a => [[foo_a:_[0-9]+]];
+    // CHECK: debug foo_b => [[foo_b:_[0-9]+]];
+    // CHECK: debug foo_c => [[foo_c:_[0-9]+]];
+    // CHECK: bb0: {
+    // CHECK-NEXT: DBG: [[foo_a]] = &((*_1).0: i32)
+    // CHECK-NEXT: DBG: [[foo_b]] = &((*_1).1: i64)
+    // CHECK-NEXT: _0 = copy ((*_1).2: i32);
+    // CHECK-NEXT: DBG: [[foo_c]] = &((*_1).2: i32)
+    // CHECK-NEXT: return;
+    mir! {
+        let _foo_a: &i32;
+        let _foo_b: &i64;
+        let _foo_c: &i32;
+        debug foo_a => _foo_a;
+        debug foo_b => _foo_b;
+        debug foo_c => _foo_c;
+        {
+            match c {
+                true => tmp,
+                _ => tmp,
+            }
+        }
+        tmp = {
+            _foo_a = &(*foo).a;
+            Goto(ret)
+        }
+        ret = {
+            _foo_b = &(*foo).b;
+            RET = (*foo).c;
+            _foo_c = &(*foo).c;
+            Return()
+        }
+    }
+}
diff --git a/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..8e03432c2af
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller::{closure#0}` before ForceInline
++ // MIR for `caller::{closure#0}` after ForceInline
+  
+  fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () {
+      let mut _0: ();
+      let _2: ();
++     scope 1 (inlined Foo::callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_2);
+-         _2 = Foo::callee_forced() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_2);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..0e41fd89dac
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure_inherent.caller-{closure#0}.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller::{closure#0}` before ForceInline
++ // MIR for `caller::{closure#0}` after ForceInline
+  
+  fn caller::{closure#0}(_1: &{closure@$DIR/forced_closure_inherent.rs:14:6: 14:8}) -> () {
+      let mut _0: ();
+      let _2: ();
++     scope 1 (inlined Foo::callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_2);
+-         _2 = Foo::callee_forced() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_2);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_closure_inherent.rs b/tests/mir-opt/inline/forced_closure_inherent.rs
new file mode 100644
index 00000000000..949c7d6ecbf
--- /dev/null
+++ b/tests/mir-opt/inline/forced_closure_inherent.rs
@@ -0,0 +1,19 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+#![feature(rustc_attrs)]
+
+struct Foo {}
+
+impl Foo {
+    #[rustc_force_inline]
+    pub fn callee_forced() {}
+}
+
+// EMIT_MIR forced_closure_inherent.caller-{closure#0}.ForceInline.diff
+pub fn caller() {
+    (|| {
+        Foo::callee_forced();
+        // CHECK-LABEL: fn caller::{closure#0}(
+        // CHECK: (inlined Foo::callee_forced)
+    })();
+}
diff --git a/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..6ea1894af98
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::bar) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::bar() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..dd91c338772
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::bar) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::bar() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent.rs b/tests/mir-opt/inline/forced_inherent.rs
new file mode 100644
index 00000000000..24bf8daa644
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent.rs
@@ -0,0 +1,17 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+#![feature(rustc_attrs)]
+
+struct Foo;
+
+impl Foo {
+    #[rustc_force_inline]
+    fn bar() {}
+}
+
+// EMIT_MIR forced_inherent.caller.ForceInline.diff
+fn caller() {
+    Foo::bar();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined Foo::bar)
+}
diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..6ea1894af98
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::bar) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::bar() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..dd91c338772
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_ambiguous.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::bar) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::bar() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_ambiguous.rs b/tests/mir-opt/inline/forced_inherent_ambiguous.rs
new file mode 100644
index 00000000000..e3c5d3e4f9e
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_ambiguous.rs
@@ -0,0 +1,25 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+#![feature(rustc_attrs)]
+
+struct Foo;
+
+impl Foo {
+    #[rustc_force_inline]
+    fn bar() {}
+}
+
+trait Tr {
+    fn bar();
+}
+
+impl Tr for Foo {
+    fn bar() {}
+}
+
+// EMIT_MIR forced_inherent_ambiguous.caller.ForceInline.diff
+fn caller() {
+    Foo::bar();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined Foo::bar)
+}
diff --git a/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..6495ddbafba
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,12 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> {async fn body of caller()} {
+      let mut _0: {async fn body of caller()};
+  
+      bb0: {
+          _0 = {coroutine@$DIR/forced_inherent_async.rs:14:19: 18:2 (#0)};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..6495ddbafba
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_async.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,12 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> {async fn body of caller()} {
+      let mut _0: {async fn body of caller()};
+  
+      bb0: {
+          _0 = {coroutine@$DIR/forced_inherent_async.rs:14:19: 18:2 (#0)};
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_async.rs b/tests/mir-opt/inline/forced_inherent_async.rs
new file mode 100644
index 00000000000..ce58a0ac48f
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_async.rs
@@ -0,0 +1,18 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 --crate-type=lib
+//@ edition: 2021
+#![feature(rustc_attrs)]
+
+struct Foo {}
+
+impl Foo {
+    #[rustc_force_inline]
+    pub fn callee_forced() {}
+}
+
+// EMIT_MIR forced_inherent_async.caller.ForceInline.diff
+async fn caller() {
+    Foo::callee_forced();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined Foo::callee_forced)
+}
diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff
new file mode 100644
index 00000000000..edaf2820d85
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-abort.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::callee_forced() -> [return: bb1, unwind unreachable];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff
new file mode 100644
index 00000000000..22f8b14a724
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_dead_code.caller.ForceInline.panic-unwind.diff
@@ -0,0 +1,21 @@
+- // MIR for `caller` before ForceInline
++ // MIR for `caller` after ForceInline
+  
+  fn caller() -> () {
+      let mut _0: ();
+      let _1: ();
++     scope 1 (inlined Foo::callee_forced) {
++     }
+  
+      bb0: {
+          StorageLive(_1);
+-         _1 = Foo::callee_forced() -> [return: bb1, unwind continue];
+-     }
+- 
+-     bb1: {
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/inline/forced_inherent_dead_code.rs b/tests/mir-opt/inline/forced_inherent_dead_code.rs
new file mode 100644
index 00000000000..057a4cac528
--- /dev/null
+++ b/tests/mir-opt/inline/forced_inherent_dead_code.rs
@@ -0,0 +1,21 @@
+// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
+//@ compile-flags: -Copt-level=0 -Clink-dead-code
+#![feature(rustc_attrs)]
+
+struct Foo {}
+
+impl Foo {
+    #[rustc_force_inline]
+    pub fn callee_forced() {}
+}
+
+// EMIT_MIR forced_inherent_dead_code.caller.ForceInline.diff
+pub fn caller() {
+    Foo::callee_forced();
+    // CHECK-LABEL: fn caller(
+    // CHECK: (inlined Foo::callee_forced)
+}
+
+fn main() {
+    caller();
+}
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index f6c111a2228..9509739413b 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -84,7 +84,6 @@
           _5 = copy _2;
 -         _0 = drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind unreachable];
 +         StorageLive(_15);
-+         StorageLive(_16);
 +         _15 = discriminant((*_5));
 +         switchInt(move _15) -> [0: bb5, otherwise: bb6];
       }
@@ -110,7 +109,6 @@
 +     }
 + 
 +     bb5: {
-+         StorageDead(_16);
 +         StorageDead(_15);
           StorageDead(_5);
           return;
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
index 18324276425..34f89da19f5 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-unwind.diff
@@ -27,13 +27,11 @@
           _5 = copy _2;
 -         _0 = drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind continue];
 +         StorageLive(_6);
-+         StorageLive(_7);
 +         _6 = discriminant((*_5));
 +         switchInt(move _6) -> [0: bb2, otherwise: bb3];
       }
   
       bb2: {
-+         StorageDead(_7);
 +         StorageDead(_6);
           StorageDead(_5);
           return;
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
index 2ae86e2eb8b..0acb33febe5 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff
@@ -129,11 +129,8 @@
           _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
           _9 = &mut (*_10);
 -         _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind unreachable];
-+         StorageLive(_11);
-+         StorageLive(_15);
 +         StorageLive(_16);
 +         StorageLive(_25);
-+         StorageLive(_27);
 +         StorageLive(_30);
 +         StorageLive(_31);
 +         StorageLive(_32);
@@ -166,11 +163,8 @@
 +         StorageDead(_32);
 +         StorageDead(_31);
 +         StorageDead(_30);
-+         StorageDead(_27);
 +         StorageDead(_25);
 +         StorageDead(_16);
-+         StorageDead(_15);
-+         StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -223,23 +217,15 @@
 +         _22 = &mut (*_23);
 +         StorageDead(_24);
 +         StorageLive(_44);
-+         StorageLive(_45);
 +         StorageLive(_49);
 +         StorageLive(_41);
 +         StorageLive(_42);
-+         StorageLive(_43);
-+         _45 = &mut _19;
-+         StorageLive(_46);
-+         _46 = &mut (_19.0: &mut std::future::Ready<()>);
 +         _44 = copy (_19.0: &mut std::future::Ready<()>);
-+         StorageDead(_46);
-+         _43 = &mut ((*_44).0: std::option::Option<()>);
 +         StorageLive(_47);
 +         _47 = Option::<()>::None;
 +         _42 = copy ((*_44).0: std::option::Option<()>);
 +         ((*_44).0: std::option::Option<()>) = copy _47;
 +         StorageDead(_47);
-+         StorageDead(_43);
 +         StorageLive(_48);
 +         _48 = discriminant(_42);
 +         switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5];
@@ -315,7 +301,6 @@
 +         _18 = Poll::<()>::Ready(move _41);
 +         StorageDead(_41);
 +         StorageDead(_49);
-+         StorageDead(_45);
 +         StorageDead(_44);
 +         StorageDead(_22);
 +         StorageDead(_19);
diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
index d7ae931aaae..98ee46c29b1 100644
--- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff
@@ -131,11 +131,8 @@
           _10 = deref_copy (_1.1: &mut std::task::Context<'_>);
           _9 = &mut (*_10);
 -         _7 = <{async fn body of ActionPermit<'_, T>::perform()} as Future>::poll(move _8, move _9) -> [return: bb3, unwind: bb5];
-+         StorageLive(_11);
-+         StorageLive(_15);
 +         StorageLive(_16);
 +         StorageLive(_25);
-+         StorageLive(_27);
 +         StorageLive(_30);
 +         StorageLive(_31);
 +         StorageLive(_32);
@@ -180,11 +177,8 @@
 +         StorageDead(_32);
 +         StorageDead(_31);
 +         StorageDead(_30);
-+         StorageDead(_27);
 +         StorageDead(_25);
 +         StorageDead(_16);
-+         StorageDead(_15);
-+         StorageDead(_11);
           StorageDead(_9);
           StorageDead(_8);
           StorageDead(_7);
@@ -240,23 +234,15 @@
 +         _22 = &mut (*_23);
 +         StorageDead(_24);
 +         StorageLive(_46);
-+         StorageLive(_47);
 +         StorageLive(_51);
 +         StorageLive(_43);
 +         StorageLive(_44);
-+         StorageLive(_45);
-+         _47 = &mut _19;
-+         StorageLive(_48);
-+         _48 = &mut (_19.0: &mut std::future::Ready<()>);
 +         _46 = copy (_19.0: &mut std::future::Ready<()>);
-+         StorageDead(_48);
-+         _45 = &mut ((*_46).0: std::option::Option<()>);
 +         StorageLive(_49);
 +         _49 = Option::<()>::None;
 +         _44 = copy ((*_46).0: std::option::Option<()>);
 +         ((*_46).0: std::option::Option<()>) = copy _49;
 +         StorageDead(_49);
-+         StorageDead(_45);
 +         StorageLive(_50);
 +         _50 = discriminant(_44);
 +         switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7];
@@ -356,7 +342,6 @@
 +         _18 = Poll::<()>::Ready(move _43);
 +         StorageDead(_43);
 +         StorageDead(_51);
-+         StorageDead(_47);
 +         StorageDead(_46);
 +         StorageDead(_22);
 +         StorageDead(_19);
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
index ac88fe67bb8..3ea7387a48d 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-abort.diff
@@ -30,7 +30,6 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = copy _1;
-          nop;
 -         StorageLive(_14);
 -         _14 = BitAnd(copy _5, const 255_u32);
 -         _4 = BitOr(const 0_u32, move _14);
diff --git a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
index 96c3cae2d33..832db856b2c 100644
--- a/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
+++ b/tests/mir-opt/issue_101973.inner.GVN.panic-unwind.diff
@@ -30,7 +30,6 @@
           StorageLive(_4);
           StorageLive(_5);
           _5 = copy _1;
-          nop;
 -         StorageLive(_14);
 -         _14 = BitAnd(copy _5, const 255_u32);
 -         _4 = BitOr(const 0_u32, move _14);
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
index 5cf36b9aebf..614d9ad440d 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff
@@ -33,15 +33,9 @@
       }
   
       bb2: {
-          StorageLive(_5);
-          _5 = &(*_2)[0 of 3];
-          StorageLive(_6);
-          _6 = &(*_2)[1 of 3];
-          StorageLive(_7);
-          _7 = &(*_2)[2 of 3];
-          StorageDead(_7);
-          StorageDead(_6);
-          StorageDead(_5);
+          // DBG: _5 = &(*_2)[0 of 3];
+          // DBG: _6 = &(*_2)[1 of 3];
+          // DBG: _7 = &(*_2)[2 of 3];
           StorageDead(_4);
           return;
       }
diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
index 0598a3aa3f1..57a88cf8984 100644
--- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
+++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff
@@ -33,15 +33,9 @@
       }
   
       bb2: {
-          StorageLive(_5);
-          _5 = &(*_2)[0 of 3];
-          StorageLive(_6);
-          _6 = &(*_2)[1 of 3];
-          StorageLive(_7);
-          _7 = &(*_2)[2 of 3];
-          StorageDead(_7);
-          StorageDead(_6);
-          StorageDead(_5);
+          // DBG: _5 = &(*_2)[0 of 3];
+          // DBG: _6 = &(*_2)[1 of 3];
+          // DBG: _7 = &(*_2)[2 of 3];
           StorageDead(_4);
           return;
       }
diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir
index 34747e5a928..1e6e2ee1b8b 100644
--- a/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/clone_as_copy.clone_as_copy.PreCodegen.after.mir
@@ -12,10 +12,8 @@ fn clone_as_copy(_1: &NestCopy) -> NestCopy {
     }
 
     bb0: {
-        StorageLive(_2);
-        _2 = &((*_1).1: AllCopy);
+        // DBG: _2 = &((*_1).1: AllCopy);
         _0 = copy (*_1);
-        StorageDead(_2);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
index e67f362ee04..76bb49bc9c1 100644
--- a/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
@@ -5,58 +5,28 @@ fn enum_clone_as_copy(_1: &Enum1) -> Enum1 {
     let mut _0: Enum1;
     scope 1 (inlined <Enum1 as Clone>::clone) {
         debug self => _1;
-        let mut _2: isize;
-        let _3: &AllCopy;
-        let _4: &NestCopy;
+        let _2: &AllCopy;
+        let _3: &NestCopy;
         scope 2 {
-            debug __self_0 => _3;
+            debug __self_0 => _2;
             scope 6 (inlined <AllCopy as Clone>::clone) {
-                debug self => _3;
+                debug self => _2;
             }
         }
         scope 3 {
-            debug __self_0 => _4;
+            debug __self_0 => _3;
             scope 4 (inlined <NestCopy as Clone>::clone) {
-                debug self => _4;
-                let _5: &AllCopy;
+                debug self => _3;
+                let _4: &AllCopy;
                 scope 5 (inlined <AllCopy as Clone>::clone) {
-                    debug self => _5;
+                    debug self => _4;
                 }
             }
         }
     }
 
     bb0: {
-        StorageLive(_2);
-        StorageLive(_3);
-        StorageLive(_4);
-        _2 = discriminant((*_1));
-        switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4];
-    }
-
-    bb1: {
-        _3 = &(((*_1) as A).0: AllCopy);
         _0 = copy (*_1);
-        goto -> bb3;
-    }
-
-    bb2: {
-        _4 = &(((*_1) as B).0: NestCopy);
-        StorageLive(_5);
-        _5 = &((((*_1) as B).0: NestCopy).1: AllCopy);
-        StorageDead(_5);
-        _0 = copy (*_1);
-        goto -> bb3;
-    }
-
-    bb3: {
-        StorageDead(_4);
-        StorageDead(_3);
-        StorageDead(_2);
         return;
     }
-
-    bb4: {
-        unreachable;
-    }
 }
diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.rs b/tests/mir-opt/pre-codegen/clone_as_copy.rs
index f5ff1854d38..00f24754d59 100644
--- a/tests/mir-opt/pre-codegen/clone_as_copy.rs
+++ b/tests/mir-opt/pre-codegen/clone_as_copy.rs
@@ -25,19 +25,19 @@ enum Enum1 {
 // EMIT_MIR clone_as_copy.clone_as_copy.PreCodegen.after.mir
 fn clone_as_copy(v: &NestCopy) -> NestCopy {
     // CHECK-LABEL: fn clone_as_copy(
-    // CHECK-NOT: = AllCopy { {{.*}} };
-    // CHECK-NOT: = NestCopy { {{.*}} };
-    // CHECK: _0 = copy (*_1);
-    // CHECK: return;
+    // CHECK: let [[DEAD_VAR:_.*]]: &AllCopy;
+    // CHECK: bb0: {
+    // CHECK-NEXT: DBG: [[DEAD_VAR]] = &((*_1).1: AllCopy)
+    // CHECK-NEXT: _0 = copy (*_1);
+    // CHECK-NEXT: return;
     v.clone()
 }
 
-// FIXME: We can merge into exactly one assignment statement.
 // EMIT_MIR clone_as_copy.enum_clone_as_copy.PreCodegen.after.mir
 fn enum_clone_as_copy(v: &Enum1) -> Enum1 {
     // CHECK-LABEL: fn enum_clone_as_copy(
-    // CHECK-NOT: = Enum1::
-    // CHECK: _0 = copy (*_1);
-    // CHECK: _0 = copy (*_1);
+    // CHECK: bb0: {
+    // CHECK-NEXT: _0 = copy (*_1);
+    // CHECK-NEXT: return;
     v.clone()
 }
diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir
new file mode 100644
index 00000000000..4a2127178fb
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.invalid_place.PreCodegen.after.mir
@@ -0,0 +1,13 @@
+// MIR for `invalid_place` after PreCodegen
+
+fn invalid_place(_1: bool) -> bool {
+    debug c1_ref => _2;
+    let mut _0: bool;
+    let mut _2: &bool;
+
+    bb0: {
+        // DBG: _2 = &?;
+        _0 = copy _1;
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs
new file mode 100644
index 00000000000..5abe9fa43a5
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/dead_on_invalid_place.rs
@@ -0,0 +1,27 @@
+#![feature(core_intrinsics, custom_mir)]
+#![crate_type = "lib"]
+
+use std::intrinsics::mir::*;
+
+// EMIT_MIR dead_on_invalid_place.invalid_place.PreCodegen.after.mir
+#[custom_mir(dialect = "runtime")]
+pub fn invalid_place(c: bool) -> bool {
+    // CHECK-LABEL: fn invalid_place
+    // CHECK: debug c1_ref => [[c1_ref:_[0-9]+]];
+    // CHECK: bb0: {
+    // We cannot read the reference, since `c1` is dead.
+    // CHECK-NEXT: DBG: [[c1_ref]] = &?
+    // CHECK-NEXT: _0 = copy _1;
+    // CHECK-NEXT: return;
+    mir! {
+        let _c1_ref: &bool;
+        let c1: bool;
+        debug c1_ref => _c1_ref;
+        {
+            c1 = c;
+            _c1_ref = &c1;
+            RET = c;
+            Return()
+        }
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
index 75e8cb1d861..8f30ad30fcc 100644
--- a/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.filter_mapped.PreCodegen.after.mir
@@ -6,20 +6,20 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     let mut _0: ();
     let mut _3: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
     let mut _4: std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
-    let mut _5: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
-    let mut _8: std::option::Option<U>;
-    let mut _9: isize;
-    let _11: ();
+    let mut _7: std::option::Option<U>;
+    let mut _8: isize;
+    let _10: ();
+    let mut _11: &mut std::iter::FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>>;
     scope 1 {
         debug iter => _4;
-        let _10: U;
+        let _9: U;
         scope 2 {
-            debug x => _10;
+            debug x => _9;
         }
         scope 4 (inlined <FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>> as Iterator>::next) {
-            debug self => _5;
-            let mut _6: &mut impl Iterator<Item = T>;
-            let mut _7: &mut impl Fn(T) -> Option<U>;
+            debug self => _11;
+            let mut _5: &mut impl Iterator<Item = T>;
+            let mut _6: &mut impl Fn(T) -> Option<U>;
         }
     }
     scope 3 (inlined <FilterMap<impl Iterator<Item = T>, impl Fn(T) -> Option<U>> as IntoIterator>::into_iter) {
@@ -37,24 +37,24 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     }
 
     bb2: {
-        StorageLive(_8);
-        _5 = &mut _4;
-        StorageLive(_6);
-        _6 = &mut (_4.0: impl Iterator<Item = T>);
         StorageLive(_7);
-        _7 = &mut (_4.1: impl Fn(T) -> Option<U>);
-        _8 = <impl Iterator<Item = T> as Iterator>::find_map::<U, &mut impl Fn(T) -> Option<U>>(move _6, move _7) -> [return: bb3, unwind: bb9];
+        // DBG: _11 = &_4;
+        StorageLive(_5);
+        _5 = &mut (_4.0: impl Iterator<Item = T>);
+        StorageLive(_6);
+        _6 = &mut (_4.1: impl Fn(T) -> Option<U>);
+        _7 = <impl Iterator<Item = T> as Iterator>::find_map::<U, &mut impl Fn(T) -> Option<U>>(move _5, move _6) -> [return: bb3, unwind: bb9];
     }
 
     bb3: {
-        StorageDead(_7);
         StorageDead(_6);
-        _9 = discriminant(_8);
-        switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb8];
+        StorageDead(_5);
+        _8 = discriminant(_7);
+        switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb8];
     }
 
     bb4: {
-        StorageDead(_8);
+        StorageDead(_7);
         drop(_4) -> [return: bb5, unwind continue];
     }
 
@@ -64,12 +64,12 @@ fn filter_mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> Option<U>) -> ()
     }
 
     bb6: {
-        _10 = move ((_8 as Some).0: U);
-        _11 = opaque::<U>(move _10) -> [return: bb7, unwind: bb9];
+        _9 = move ((_7 as Some).0: U);
+        _10 = opaque::<U>(move _9) -> [return: bb7, unwind: bb9];
     }
 
     bb7: {
-        StorageDead(_8);
+        StorageDead(_7);
         goto -> bb2;
     }
 
diff --git a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
index 154cbd3791c..beb7b936ccf 100644
--- a/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.int_range.PreCodegen.after.mir
@@ -5,32 +5,31 @@ fn int_range(_1: usize, _2: usize) -> () {
     debug end => _2;
     let mut _0: ();
     let mut _3: std::ops::Range<usize>;
-    let mut _4: std::ops::Range<usize>;
-    let mut _5: &mut std::ops::Range<usize>;
-    let mut _13: std::option::Option<usize>;
-    let _15: ();
+    let mut _9: std::option::Option<usize>;
+    let _11: ();
+    let mut _12: &mut std::ops::Range<usize>;
     scope 1 {
-        debug iter => _4;
-        let _14: usize;
+        debug iter => _3;
+        let _10: usize;
         scope 2 {
-            debug i => _14;
+            debug i => _10;
         }
         scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) {
-            debug self => _5;
+            debug self => _12;
             scope 5 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) {
-                debug self => _5;
-                let mut _6: &usize;
-                let mut _7: &usize;
-                let mut _10: bool;
-                let _11: usize;
-                let mut _12: usize;
+                debug self => _12;
+                let mut _6: bool;
+                let _7: usize;
+                let mut _8: usize;
+                let mut _13: &usize;
+                let mut _14: &usize;
                 scope 6 {
-                    debug old => _11;
+                    debug old => _7;
                     scope 8 (inlined <usize as Step>::forward_unchecked) {
-                        debug start => _11;
+                        debug start => _7;
                         debug n => const 1_usize;
                         scope 9 (inlined #[track_caller] core::num::<impl usize>::unchecked_add) {
-                            debug self => _11;
+                            debug self => _7;
                             debug rhs => const 1_usize;
                             scope 10 (inlined core::ub_checks::check_language_ub) {
                                 scope 11 (inlined core::ub_checks::check_language_ub::runtime) {
@@ -40,10 +39,10 @@ fn int_range(_1: usize, _2: usize) -> () {
                     }
                 }
                 scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::lt) {
-                    debug self => _6;
-                    debug other => _7;
-                    let mut _8: usize;
-                    let mut _9: usize;
+                    debug self => _13;
+                    debug other => _14;
+                    let mut _4: usize;
+                    let mut _5: usize;
                 }
             }
         }
@@ -54,54 +53,45 @@ fn int_range(_1: usize, _2: usize) -> () {
 
     bb0: {
         _3 = std::ops::Range::<usize> { start: copy _1, end: copy _2 };
-        StorageLive(_4);
-        _4 = copy _3;
         goto -> bb1;
     }
 
     bb1: {
-        StorageLive(_13);
-        _5 = &mut _4;
-        StorageLive(_10);
-        StorageLive(_6);
-        _6 = &(_4.0: usize);
-        StorageLive(_7);
-        _7 = &(_4.1: usize);
-        StorageLive(_8);
-        _8 = copy (_4.0: usize);
         StorageLive(_9);
-        _9 = copy (_4.1: usize);
-        _10 = Lt(move _8, move _9);
-        StorageDead(_9);
-        StorageDead(_8);
-        switchInt(move _10) -> [0: bb2, otherwise: bb3];
+        // DBG: _12 = &_3;
+        StorageLive(_6);
+        // DBG: _13 = &(_3.0: usize);
+        // DBG: _14 = &(_3.1: usize);
+        StorageLive(_4);
+        _4 = copy (_3.0: usize);
+        StorageLive(_5);
+        _5 = copy (_3.1: usize);
+        _6 = Lt(move _4, move _5);
+        StorageDead(_5);
+        StorageDead(_4);
+        switchInt(move _6) -> [0: bb2, otherwise: bb3];
     }
 
     bb2: {
-        StorageDead(_7);
         StorageDead(_6);
-        StorageDead(_10);
-        StorageDead(_13);
-        StorageDead(_4);
+        StorageDead(_9);
         return;
     }
 
     bb3: {
-        StorageDead(_7);
+        _7 = copy (_3.0: usize);
+        StorageLive(_8);
+        _8 = AddUnchecked(copy _7, const 1_usize);
+        (_3.0: usize) = move _8;
+        StorageDead(_8);
+        _9 = Option::<usize>::Some(copy _7);
         StorageDead(_6);
-        _11 = copy (_4.0: usize);
-        StorageLive(_12);
-        _12 = AddUnchecked(copy _11, const 1_usize);
-        (_4.0: usize) = move _12;
-        StorageDead(_12);
-        _13 = Option::<usize>::Some(copy _11);
-        StorageDead(_10);
-        _14 = copy ((_13 as Some).0: usize);
-        _15 = opaque::<usize>(move _14) -> [return: bb4, unwind continue];
+        _10 = copy ((_9 as Some).0: usize);
+        _11 = opaque::<usize>(move _10) -> [return: bb4, unwind continue];
     }
 
     bb4: {
-        StorageDead(_13);
+        StorageDead(_9);
         goto -> bb1;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
index d22ea54004c..406c96fc32f 100644
--- a/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.mapped.PreCodegen.after.mir
@@ -6,32 +6,32 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     let mut _0: ();
     let mut _3: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
     let mut _4: std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
-    let mut _5: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
-    let mut _13: std::option::Option<U>;
-    let _15: ();
+    let mut _12: std::option::Option<U>;
+    let _14: ();
+    let mut _15: &mut std::iter::Map<impl Iterator<Item = T>, impl Fn(T) -> U>;
     scope 1 {
         debug iter => _4;
-        let _14: U;
+        let _13: U;
         scope 2 {
-            debug x => _14;
+            debug x => _13;
         }
         scope 4 (inlined <Map<impl Iterator<Item = T>, impl Fn(T) -> U> as Iterator>::next) {
-            debug self => _5;
-            let mut _6: &mut impl Iterator<Item = T>;
-            let mut _7: std::option::Option<T>;
-            let mut _8: &mut impl Fn(T) -> U;
+            debug self => _15;
+            let mut _5: &mut impl Iterator<Item = T>;
+            let mut _6: std::option::Option<T>;
+            let mut _7: &mut impl Fn(T) -> U;
             scope 5 (inlined Option::<T>::map::<U, &mut impl Fn(T) -> U>) {
-                debug self => _7;
-                debug f => _8;
-                let mut _9: isize;
-                let _10: T;
-                let mut _11: (T,);
-                let mut _12: U;
+                debug self => _6;
+                debug f => _7;
+                let mut _8: isize;
+                let _9: T;
+                let mut _10: (T,);
+                let mut _11: U;
                 scope 6 {
-                    debug x => _10;
+                    debug x => _9;
                     scope 7 (inlined ops::function::impls::<impl FnOnce<(T,)> for &mut impl Fn(T) -> U>::call_once) {
-                        debug self => _8;
-                        debug args => _11;
+                        debug self => _7;
+                        debug args => _10;
                     }
                 }
             }
@@ -52,30 +52,30 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     }
 
     bb2: {
-        StorageLive(_13);
-        _5 = &mut _4;
-        StorageLive(_8);
+        StorageLive(_12);
+        // DBG: _15 = &_4;
         StorageLive(_7);
         StorageLive(_6);
-        _6 = &mut (_4.0: impl Iterator<Item = T>);
-        _7 = <impl Iterator<Item = T> as Iterator>::next(move _6) -> [return: bb3, unwind: bb10];
+        StorageLive(_5);
+        _5 = &mut (_4.0: impl Iterator<Item = T>);
+        _6 = <impl Iterator<Item = T> as Iterator>::next(move _5) -> [return: bb3, unwind: bb10];
     }
 
     bb3: {
-        StorageDead(_6);
-        _8 = &mut (_4.1: impl Fn(T) -> U);
+        StorageDead(_5);
+        _7 = &mut (_4.1: impl Fn(T) -> U);
+        StorageLive(_8);
         StorageLive(_9);
-        StorageLive(_10);
-        _9 = discriminant(_7);
-        switchInt(move _9) -> [0: bb4, 1: bb6, otherwise: bb9];
+        _8 = discriminant(_6);
+        switchInt(move _8) -> [0: bb4, 1: bb6, otherwise: bb9];
     }
 
     bb4: {
-        StorageDead(_10);
         StorageDead(_9);
-        StorageDead(_7);
         StorageDead(_8);
-        StorageDead(_13);
+        StorageDead(_6);
+        StorageDead(_7);
+        StorageDead(_12);
         drop(_4) -> [return: bb5, unwind continue];
     }
 
@@ -85,27 +85,27 @@ fn mapped(_1: impl Iterator<Item = T>, _2: impl Fn(T) -> U) -> () {
     }
 
     bb6: {
-        _10 = move ((_7 as Some).0: T);
-        StorageLive(_12);
+        _9 = move ((_6 as Some).0: T);
         StorageLive(_11);
-        _11 = (copy _10,);
-        _12 = <impl Fn(T) -> U as FnMut<(T,)>>::call_mut(move _8, move _11) -> [return: bb7, unwind: bb10];
+        StorageLive(_10);
+        _10 = (copy _9,);
+        _11 = <impl Fn(T) -> U as FnMut<(T,)>>::call_mut(move _7, move _10) -> [return: bb7, unwind: bb10];
     }
 
     bb7: {
-        StorageDead(_11);
-        _13 = Option::<U>::Some(move _12);
-        StorageDead(_12);
         StorageDead(_10);
+        _12 = Option::<U>::Some(move _11);
+        StorageDead(_11);
         StorageDead(_9);
-        StorageDead(_7);
         StorageDead(_8);
-        _14 = move ((_13 as Some).0: U);
-        _15 = opaque::<U>(move _14) -> [return: bb8, unwind: bb10];
+        StorageDead(_6);
+        StorageDead(_7);
+        _13 = move ((_12 as Some).0: U);
+        _14 = opaque::<U>(move _13) -> [return: bb8, unwind: bb10];
     }
 
     bb8: {
-        StorageDead(_13);
+        StorageDead(_12);
         goto -> bb2;
     }
 
diff --git a/tests/mir-opt/pre-codegen/loops.rs b/tests/mir-opt/pre-codegen/loops.rs
index d0b8cc8db7a..952dd8cac60 100644
--- a/tests/mir-opt/pre-codegen/loops.rs
+++ b/tests/mir-opt/pre-codegen/loops.rs
@@ -1,5 +1,6 @@
 // skip-filecheck
 //@ compile-flags: -O -Zmir-opt-level=2 -g
+//@ ignore-std-debug-assertions (debug assertions result in different inlines)
 //@ needs-unwind
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
index e537dd6a28e..66eb1bcfaa6 100644
--- a/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/loops.vec_move.PreCodegen.after.mir
@@ -3,72 +3,320 @@
 fn vec_move(_1: Vec<impl Sized>) -> () {
     debug v => _1;
     let mut _0: ();
-    let mut _2: std::vec::IntoIter<impl Sized>;
-    let mut _3: std::vec::IntoIter<impl Sized>;
-    let mut _4: &mut std::vec::IntoIter<impl Sized>;
-    let mut _5: std::option::Option<impl Sized>;
-    let mut _6: isize;
-    let _8: ();
+    let mut _22: std::vec::IntoIter<impl Sized>;
+    let mut _23: std::vec::IntoIter<impl Sized>;
+    let mut _24: &mut std::vec::IntoIter<impl Sized>;
+    let mut _25: std::option::Option<impl Sized>;
+    let mut _26: isize;
+    let _28: ();
     scope 1 {
-        debug iter => _3;
-        let _7: impl Sized;
+        debug iter => _23;
+        let _27: impl Sized;
         scope 2 {
-            debug x => _7;
+            debug x => _27;
+        }
+    }
+    scope 3 (inlined <Vec<impl Sized> as IntoIterator>::into_iter) {
+        debug self => _1;
+        let _2: std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        let mut _3: *const std::alloc::Global;
+        let mut _8: usize;
+        let mut _10: *mut impl Sized;
+        let mut _11: *const impl Sized;
+        let mut _12: usize;
+        let _29: &std::vec::Vec<impl Sized>;
+        let mut _30: &std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        let mut _31: &alloc::raw_vec::RawVec<impl Sized>;
+        let mut _32: &std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        let _33: &std::vec::Vec<impl Sized>;
+        let mut _34: &std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        let _35: &std::vec::Vec<impl Sized>;
+        let mut _36: &std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        let mut _37: &alloc::raw_vec::RawVec<impl Sized>;
+        let mut _38: &std::mem::ManuallyDrop<std::vec::Vec<impl Sized>>;
+        scope 4 {
+            debug me => _2;
+            scope 5 {
+                debug alloc => const ManuallyDrop::<std::alloc::Global> {{ value: std::alloc::Global }};
+                let _6: std::ptr::NonNull<impl Sized>;
+                scope 6 {
+                    debug buf => _6;
+                    let _7: *mut impl Sized;
+                    scope 7 {
+                        debug begin => _7;
+                        scope 8 {
+                            debug end => _11;
+                            let _20: usize;
+                            scope 9 {
+                                debug cap => _20;
+                            }
+                            scope 39 (inlined <ManuallyDrop<Vec<impl Sized>> as Deref>::deref) {
+                                debug self => _38;
+                            }
+                            scope 40 (inlined alloc::raw_vec::RawVec::<impl Sized>::capacity) {
+                                debug self => _37;
+                                let mut _19: usize;
+                                let mut _39: &alloc::raw_vec::RawVecInner;
+                                scope 41 (inlined std::mem::size_of::<impl Sized>) {
+                                }
+                                scope 42 (inlined alloc::raw_vec::RawVecInner::capacity) {
+                                    debug self => _39;
+                                    debug elem_size => _19;
+                                    let mut _21: core::num::niche_types::UsizeNoHighBit;
+                                    scope 43 (inlined core::num::niche_types::UsizeNoHighBit::as_inner) {
+                                        debug self => _21;
+                                    }
+                                }
+                            }
+                        }
+                        scope 25 (inlined <ManuallyDrop<Vec<impl Sized>> as Deref>::deref) {
+                            debug self => _34;
+                        }
+                        scope 26 (inlined Vec::<impl Sized>::len) {
+                            debug self => _33;
+                            let mut _13: bool;
+                            scope 27 {
+                            }
+                        }
+                        scope 28 (inlined std::ptr::mut_ptr::<impl *mut impl Sized>::wrapping_byte_add) {
+                            debug self => _7;
+                            debug count => _12;
+                            let mut _14: *mut u8;
+                            let mut _18: *mut u8;
+                            scope 29 (inlined std::ptr::mut_ptr::<impl *mut impl Sized>::cast::<u8>) {
+                                debug self => _7;
+                            }
+                            scope 30 (inlined std::ptr::mut_ptr::<impl *mut u8>::wrapping_add) {
+                                debug self => _14;
+                                debug count => _12;
+                                let mut _15: isize;
+                                scope 31 (inlined std::ptr::mut_ptr::<impl *mut u8>::wrapping_offset) {
+                                    debug self => _14;
+                                    debug count => _15;
+                                    let mut _16: *const u8;
+                                    let mut _17: *const u8;
+                                }
+                            }
+                            scope 32 (inlined std::ptr::mut_ptr::<impl *mut u8>::with_metadata_of::<impl Sized>) {
+                                debug self => _18;
+                                debug meta => _5;
+                                scope 33 (inlined std::ptr::metadata::<impl Sized>) {
+                                    debug ptr => _5;
+                                }
+                                scope 34 (inlined std::ptr::from_raw_parts_mut::<impl Sized, ()>) {
+                                }
+                            }
+                        }
+                        scope 35 (inlined <ManuallyDrop<Vec<impl Sized>> as Deref>::deref) {
+                            debug self => _36;
+                        }
+                        scope 36 (inlined Vec::<impl Sized>::len) {
+                            debug self => _35;
+                            let mut _9: bool;
+                            scope 37 {
+                            }
+                        }
+                        scope 38 (inlined #[track_caller] std::ptr::mut_ptr::<impl *mut impl Sized>::add) {
+                            debug self => _7;
+                            debug count => _8;
+                        }
+                    }
+                    scope 24 (inlined NonNull::<impl Sized>::as_ptr) {
+                        debug self => _6;
+                    }
+                }
+                scope 17 (inlined <ManuallyDrop<Vec<impl Sized>> as Deref>::deref) {
+                    debug self => _32;
+                }
+                scope 18 (inlined alloc::raw_vec::RawVec::<impl Sized>::non_null) {
+                    debug self => _31;
+                    scope 19 (inlined alloc::raw_vec::RawVecInner::non_null::<impl Sized>) {
+                        let mut _4: std::ptr::NonNull<u8>;
+                        scope 20 (inlined Unique::<u8>::cast::<impl Sized>) {
+                            scope 21 (inlined NonNull::<u8>::cast::<impl Sized>) {
+                                let mut _5: *const impl Sized;
+                                scope 22 (inlined NonNull::<u8>::as_ptr) {
+                                }
+                            }
+                        }
+                        scope 23 (inlined Unique::<impl Sized>::as_non_null_ptr) {
+                        }
+                    }
+                }
+            }
+            scope 11 (inlined <ManuallyDrop<Vec<impl Sized>> as Deref>::deref) {
+                debug self => _30;
+            }
+            scope 12 (inlined Vec::<impl Sized>::allocator) {
+                debug self => _29;
+                scope 13 (inlined alloc::raw_vec::RawVec::<impl Sized>::allocator) {
+                    scope 14 (inlined alloc::raw_vec::RawVecInner::allocator) {
+                    }
+                }
+            }
+            scope 15 (inlined #[track_caller] std::ptr::read::<std::alloc::Global>) {
+                debug src => _3;
+            }
+            scope 16 (inlined ManuallyDrop::<std::alloc::Global>::new) {
+                debug value => const std::alloc::Global;
+            }
+        }
+        scope 10 (inlined ManuallyDrop::<Vec<impl Sized>>::new) {
+            debug value => _1;
         }
     }
 
     bb0: {
+        StorageLive(_22);
+        StorageLive(_6);
+        StorageLive(_7);
+        StorageLive(_11);
+        StorageLive(_20);
+        StorageLive(_5);
+        StorageLive(_4);
+        StorageLive(_17);
         StorageLive(_2);
-        _2 = <Vec<impl Sized> as IntoIterator>::into_iter(move _1) -> [return: bb1, unwind continue];
+        _2 = ManuallyDrop::<Vec<impl Sized>> { value: copy _1 };
+        StorageLive(_3);
+        // DBG: _30 = &_2;
+        // DBG: _29 = &(_2.0: std::vec::Vec<impl Sized>);
+        _3 = &raw const ((((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner).2: std::alloc::Global);
+        StorageDead(_3);
+        // DBG: _32 = &_2;
+        // DBG: _31 = &((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>);
+        _4 = copy (((((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
+        _5 = copy _4 as *const impl Sized (Transmute);
+        _6 = NonNull::<impl Sized> { pointer: copy _5 };
+        _7 = copy _4 as *mut impl Sized (Transmute);
+        switchInt(const <impl Sized as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageLive(_3);
-        _3 = move _2;
-        goto -> bb2;
+        StorageLive(_10);
+        StorageLive(_8);
+        // DBG: _36 = &_2;
+        // DBG: _35 = &(_2.0: std::vec::Vec<impl Sized>);
+        _8 = copy ((_2.0: std::vec::Vec<impl Sized>).1: usize);
+        StorageLive(_9);
+        _9 = Le(copy _8, const <impl Sized as std::mem::SizedTypeProperties>::MAX_SLICE_LEN);
+        assume(move _9);
+        StorageDead(_9);
+        _10 = Offset(copy _7, copy _8);
+        _11 = copy _10 as *const impl Sized (PtrToPtr);
+        StorageDead(_8);
+        StorageDead(_10);
+        goto -> bb4;
     }
 
     bb2: {
-        StorageLive(_5);
-        _4 = &mut _3;
-        _5 = <std::vec::IntoIter<impl Sized> as Iterator>::next(move _4) -> [return: bb3, unwind: bb9];
+        StorageLive(_12);
+        // DBG: _34 = &_2;
+        // DBG: _33 = &(_2.0: std::vec::Vec<impl Sized>);
+        _12 = copy ((_2.0: std::vec::Vec<impl Sized>).1: usize);
+        StorageLive(_13);
+        _13 = Le(copy _12, const <impl Sized as std::mem::SizedTypeProperties>::MAX_SLICE_LEN);
+        assume(move _13);
+        StorageDead(_13);
+        StorageLive(_18);
+        StorageLive(_14);
+        _14 = copy _4 as *mut u8 (Transmute);
+        StorageLive(_15);
+        _15 = copy _12 as isize (IntToInt);
+        StorageLive(_16);
+        _16 = copy _4 as *const u8 (Transmute);
+        _17 = arith_offset::<u8>(move _16, move _15) -> [return: bb3, unwind unreachable];
     }
 
     bb3: {
-        _6 = discriminant(_5);
-        switchInt(move _6) -> [0: bb4, 1: bb6, otherwise: bb8];
+        StorageDead(_16);
+        _18 = copy _17 as *mut u8 (PtrToPtr);
+        StorageDead(_15);
+        StorageDead(_14);
+        StorageDead(_18);
+        StorageDead(_12);
+        _11 = copy _17 as *const impl Sized (PtrToPtr);
+        goto -> bb4;
     }
 
     bb4: {
-        StorageDead(_5);
-        drop(_3) -> [return: bb5, unwind continue];
+        // DBG: _38 = &_2;
+        // DBG: _37 = &((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>);
+        // DBG: _39 = &(((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner);
+        StorageLive(_19);
+        _19 = SizeOf(impl Sized);
+        switchInt(move _19) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
-        StorageDead(_3);
-        StorageDead(_2);
-        return;
+        _20 = const usize::MAX;
+        goto -> bb7;
     }
 
     bb6: {
-        _7 = move ((_5 as Some).0: impl Sized);
-        _8 = opaque::<impl Sized>(move _7) -> [return: bb7, unwind: bb9];
+        StorageLive(_21);
+        _21 = copy ((((_2.0: std::vec::Vec<impl Sized>).0: alloc::raw_vec::RawVec<impl Sized>).0: alloc::raw_vec::RawVecInner).1: core::num::niche_types::UsizeNoHighBit);
+        _20 = copy _21 as usize (Transmute);
+        StorageDead(_21);
+        goto -> bb7;
     }
 
     bb7: {
+        StorageDead(_19);
+        _22 = std::vec::IntoIter::<impl Sized> { buf: copy _6, phantom: const ZeroSized: PhantomData<impl Sized>, cap: move _20, alloc: const ManuallyDrop::<std::alloc::Global> {{ value: std::alloc::Global }}, ptr: copy _6, end: copy _11 };
+        StorageDead(_2);
+        StorageDead(_17);
+        StorageDead(_4);
         StorageDead(_5);
-        goto -> bb2;
+        StorageDead(_20);
+        StorageDead(_11);
+        StorageDead(_7);
+        StorageDead(_6);
+        StorageLive(_23);
+        _23 = move _22;
+        goto -> bb8;
     }
 
     bb8: {
+        StorageLive(_25);
+        _24 = &mut _23;
+        _25 = <std::vec::IntoIter<impl Sized> as Iterator>::next(move _24) -> [return: bb9, unwind: bb15];
+    }
+
+    bb9: {
+        _26 = discriminant(_25);
+        switchInt(move _26) -> [0: bb10, 1: bb12, otherwise: bb14];
+    }
+
+    bb10: {
+        StorageDead(_25);
+        drop(_23) -> [return: bb11, unwind continue];
+    }
+
+    bb11: {
+        StorageDead(_23);
+        StorageDead(_22);
+        return;
+    }
+
+    bb12: {
+        _27 = move ((_25 as Some).0: impl Sized);
+        _28 = opaque::<impl Sized>(move _27) -> [return: bb13, unwind: bb15];
+    }
+
+    bb13: {
+        StorageDead(_25);
+        goto -> bb8;
+    }
+
+    bb14: {
         unreachable;
     }
 
-    bb9 (cleanup): {
-        drop(_3) -> [return: bb10, unwind terminate(cleanup)];
+    bb15 (cleanup): {
+        drop(_23) -> [return: bb16, unwind terminate(cleanup)];
     }
 
-    bb10 (cleanup): {
+    bb16 (cleanup): {
         resume;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index cbdd194afd3..2cab8818296 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -3,183 +3,134 @@
 fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2: &&(usize, usize, usize, usize)) -> bool {
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
-    let _4: &usize;
-    let _5: &usize;
-    let _6: &usize;
-    let _7: &usize;
-    let mut _8: &&usize;
-    let _9: &usize;
-    let mut _10: &&usize;
-    let mut _13: bool;
-    let mut _14: &&usize;
+    let mut _6: bool;
+    let mut _9: bool;
+    let mut _10: bool;
+    let _13: &usize;
+    let _14: &usize;
     let _15: &usize;
-    let mut _16: &&usize;
-    let mut _19: bool;
+    let _16: &usize;
+    let mut _17: &&usize;
+    let mut _18: &&usize;
+    let mut _19: &&usize;
     let mut _20: &&usize;
-    let _21: &usize;
+    let mut _21: &&usize;
     let mut _22: &&usize;
-    let mut _23: bool;
+    let mut _23: &&usize;
     let mut _24: &&usize;
-    let _25: &usize;
-    let mut _26: &&usize;
     scope 1 {
-        debug a => _4;
-        debug b => _5;
-        debug c => _6;
-        debug d => _7;
+        debug a => _13;
+        debug b => _14;
+        debug c => _15;
+        debug d => _16;
         scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _8;
-            debug other => _10;
+            debug self => _17;
+            debug other => _18;
             scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _4;
-                debug other => _6;
-                let mut _11: usize;
-                let mut _12: usize;
+                debug self => _13;
+                debug other => _15;
+                let mut _4: usize;
+                let mut _5: usize;
             }
         }
         scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _14;
-            debug other => _16;
+            debug self => _19;
+            debug other => _20;
             scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _7;
-                debug other => _5;
-                let mut _17: usize;
-                let mut _18: usize;
+                debug self => _16;
+                debug other => _14;
+                let mut _7: usize;
+                let mut _8: usize;
             }
         }
         scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _20;
+            debug self => _21;
             debug other => _22;
             scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _6;
-                debug other => _4;
+                debug self => _15;
+                debug other => _13;
             }
         }
         scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _24;
-            debug other => _26;
+            debug self => _23;
+            debug other => _24;
             scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _5;
-                debug other => _7;
-                let mut _27: usize;
-                let mut _28: usize;
+                debug self => _14;
+                debug other => _16;
+                let mut _11: usize;
+                let mut _12: usize;
             }
         }
     }
 
     bb0: {
         _3 = copy (*_2);
-        _4 = &((*_3).0: usize);
-        _5 = &((*_3).1: usize);
-        _6 = &((*_3).2: usize);
-        _7 = &((*_3).3: usize);
-        StorageLive(_13);
-        StorageLive(_8);
-        _8 = &_4;
-        StorageLive(_10);
-        StorageLive(_9);
-        _9 = copy _6;
-        _10 = &_9;
-        _11 = copy ((*_3).0: usize);
-        _12 = copy ((*_3).2: usize);
-        _13 = Le(copy _11, copy _12);
-        switchInt(move _13) -> [0: bb1, otherwise: bb2];
+        // DBG: _13 = &((*_3).0: usize);
+        // DBG: _14 = &((*_3).1: usize);
+        // DBG: _15 = &((*_3).2: usize);
+        // DBG: _16 = &((*_3).3: usize);
+        StorageLive(_6);
+        // DBG: _17 = &_13;
+        // DBG: _18 = &?;
+        _4 = copy ((*_3).0: usize);
+        _5 = copy ((*_3).2: usize);
+        _6 = Le(copy _4, copy _5);
+        switchInt(move _6) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
-        StorageDead(_9);
-        StorageDead(_10);
+        StorageLive(_9);
+        // DBG: _19 = &_16;
+        // DBG: _20 = &?;
+        StorageLive(_7);
+        _7 = copy ((*_3).3: usize);
+        StorageLive(_8);
+        _8 = copy ((*_3).1: usize);
+        _9 = Le(move _7, move _8);
         StorageDead(_8);
-        goto -> bb4;
+        StorageDead(_7);
+        switchInt(move _9) -> [0: bb2, otherwise: bb6];
     }
 
     bb2: {
-        StorageDead(_9);
-        StorageDead(_10);
-        StorageDead(_8);
-        StorageLive(_19);
-        StorageLive(_14);
-        _14 = &_7;
-        StorageLive(_16);
-        StorageLive(_15);
-        _15 = copy _5;
-        _16 = &_15;
-        StorageLive(_17);
-        _17 = copy ((*_3).3: usize);
-        StorageLive(_18);
-        _18 = copy ((*_3).1: usize);
-        _19 = Le(move _17, move _18);
-        StorageDead(_18);
-        StorageDead(_17);
-        switchInt(move _19) -> [0: bb3, otherwise: bb8];
+        StorageLive(_10);
+        // DBG: _21 = &_15;
+        // DBG: _22 = &?;
+        _10 = Le(copy _5, copy _4);
+        switchInt(move _10) -> [0: bb3, otherwise: bb4];
     }
 
     bb3: {
-        StorageDead(_15);
-        StorageDead(_16);
-        StorageDead(_14);
-        goto -> bb4;
+        _0 = const false;
+        goto -> bb5;
     }
 
     bb4: {
-        StorageLive(_23);
-        StorageLive(_20);
-        _20 = &_6;
-        StorageLive(_22);
-        StorageLive(_21);
-        _21 = copy _4;
-        _22 = &_21;
-        _23 = Le(copy _12, copy _11);
-        switchInt(move _23) -> [0: bb5, otherwise: bb6];
+        // DBG: _23 = &_14;
+        // DBG: _24 = &?;
+        StorageLive(_11);
+        _11 = copy ((*_3).1: usize);
+        StorageLive(_12);
+        _12 = copy ((*_3).3: usize);
+        _0 = Le(move _11, move _12);
+        StorageDead(_12);
+        StorageDead(_11);
+        goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_21);
-        StorageDead(_22);
-        StorageDead(_20);
-        _0 = const false;
+        StorageDead(_10);
         goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_21);
-        StorageDead(_22);
-        StorageDead(_20);
-        StorageLive(_24);
-        _24 = &_5;
-        StorageLive(_26);
-        StorageLive(_25);
-        _25 = copy _7;
-        _26 = &_25;
-        StorageLive(_27);
-        _27 = copy ((*_3).1: usize);
-        StorageLive(_28);
-        _28 = copy ((*_3).3: usize);
-        _0 = Le(move _27, move _28);
-        StorageDead(_28);
-        StorageDead(_27);
-        StorageDead(_25);
-        StorageDead(_26);
-        StorageDead(_24);
+        _0 = const true;
         goto -> bb7;
     }
 
     bb7: {
-        StorageDead(_23);
-        goto -> bb9;
-    }
-
-    bb8: {
-        StorageDead(_15);
-        StorageDead(_16);
-        StorageDead(_14);
-        _0 = const true;
-        goto -> bb9;
-    }
-
-    bb9: {
-        StorageDead(_19);
-        StorageDead(_13);
+        StorageDead(_9);
+        StorageDead(_6);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
index 0adf268d766..3009be3f9dc 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir
@@ -7,19 +7,87 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _10: std::slice::Iter<'_, T>;
     let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _14: std::option::Option<&T>;
-    let mut _15: isize;
-    let mut _17: &impl Fn(&T);
-    let mut _18: (&T,);
-    let _19: ();
+    let mut _33: std::option::Option<&T>;
+    let mut _35: &impl Fn(&T);
+    let mut _36: (&T,);
+    let _37: ();
     scope 1 {
         debug iter => _12;
-        let _16: &T;
+        let _34: &T;
         scope 2 {
-            debug x => _16;
+            debug x => _34;
         }
         scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            let mut _13: &mut std::slice::Iter<'_, T>;
+            scope 19 (inlined <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back) {
+                let mut _13: *const T;
+                let mut _18: bool;
+                let mut _19: *const T;
+                let _32: &T;
+                scope 20 {
+                    let _14: std::ptr::NonNull<T>;
+                    let _20: usize;
+                    scope 21 {
+                    }
+                    scope 22 {
+                        scope 25 (inlined <NonNull<T> as PartialEq>::eq) {
+                            let mut _15: std::ptr::NonNull<T>;
+                            let mut _16: *mut T;
+                            let mut _17: *mut T;
+                            scope 26 (inlined NonNull::<T>::as_ptr) {
+                            }
+                            scope 27 (inlined NonNull::<T>::as_ptr) {
+                            }
+                        }
+                    }
+                    scope 23 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
+                        scope 24 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
+                        }
+                    }
+                }
+                scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) {
+                    let _26: std::ptr::NonNull<T>;
+                    scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) {
+                        let mut _21: *mut *const T;
+                        let mut _22: *mut std::ptr::NonNull<T>;
+                        let mut _23: std::ptr::NonNull<T>;
+                        let mut _27: *mut *const T;
+                        let mut _28: *mut usize;
+                        let mut _29: usize;
+                        let mut _30: usize;
+                        scope 30 {
+                            scope 31 {
+                            }
+                            scope 32 {
+                                scope 35 (inlined NonNull::<T>::sub) {
+                                    scope 36 (inlined #[track_caller] core::num::<impl isize>::unchecked_neg) {
+                                        scope 37 (inlined core::ub_checks::check_language_ub) {
+                                            scope 38 (inlined core::ub_checks::check_language_ub::runtime) {
+                                            }
+                                        }
+                                    }
+                                    scope 39 (inlined NonNull::<T>::offset) {
+                                        let mut _24: *const T;
+                                        let mut _25: *const T;
+                                        scope 40 (inlined NonNull::<T>::as_ptr) {
+                                        }
+                                    }
+                                }
+                            }
+                            scope 33 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<usize>) {
+                            }
+                            scope 34 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<NonNull<T>>) {
+                            }
+                        }
+                    }
+                    scope 41 (inlined NonNull::<T>::as_ref::<'_>) {
+                        let _31: *const T;
+                        scope 42 (inlined NonNull::<T>::as_ptr) {
+                        }
+                        scope 43 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
+                        }
+                    }
+                }
+            }
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -105,45 +173,136 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
+        StorageLive(_33);
+        StorageLive(_20);
+        StorageLive(_19);
         StorageLive(_14);
-        StorageLive(_13);
-        _13 = &mut (_12.0: std::slice::Iter<'_, T>);
-        _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind unreachable];
+        StorageLive(_32);
+        StorageLive(_18);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
+        StorageLive(_13);
+        _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _14 = copy _13 as std::ptr::NonNull<T> (Transmute);
         StorageDead(_13);
-        _15 = discriminant(_14);
-        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageLive(_16);
+        StorageLive(_15);
+        _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
+        _16 = copy _15 as *mut T (Transmute);
+        StorageDead(_15);
+        StorageLive(_17);
+        _17 = copy _14 as *mut T (Transmute);
+        _18 = Eq(copy _16, copy _17);
+        StorageDead(_17);
+        StorageDead(_16);
+        goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_14);
-        StorageDead(_12);
-        drop(_2) -> [return: bb7, unwind unreachable];
+        _19 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _20 = copy _19 as usize (Transmute);
+        _18 = Eq(copy _20, const 0_usize);
+        goto -> bb7;
     }
 
     bb7: {
-        return;
+        switchInt(move _18) -> [0: bb8, otherwise: bb15];
     }
 
     bb8: {
-        _16 = copy ((_14 as Some).0: &T);
-        StorageLive(_17);
-        _17 = &_2;
-        StorageLive(_18);
-        _18 = (copy _16,);
-        _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable];
+        StorageLive(_26);
+        StorageLive(_28);
+        StorageLive(_22);
+        StorageLive(_23);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb9, otherwise: bb12];
     }
 
     bb9: {
+        StorageLive(_21);
+        _21 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _22 = copy _21 as *mut std::ptr::NonNull<T> (PtrToPtr);
+        StorageDead(_21);
+        _23 = copy (*_22);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb10, otherwise: bb11];
+    }
+
+    bb10: {
+        StorageLive(_25);
+        StorageLive(_24);
+        _24 = copy _23 as *const T (Transmute);
+        _25 = Offset(copy _24, const -1_isize);
+        StorageDead(_24);
+        _23 = NonNull::<T> { pointer: copy _25 };
+        StorageDead(_25);
+        goto -> bb11;
+    }
+
+    bb11: {
+        (*_22) = move _23;
+        _26 = copy (*_22);
+        goto -> bb13;
+    }
+
+    bb12: {
+        StorageLive(_27);
+        _27 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _28 = copy _27 as *mut usize (PtrToPtr);
+        StorageDead(_27);
+        StorageLive(_30);
+        StorageLive(_29);
+        _29 = copy (*_28);
+        _30 = SubUnchecked(move _29, const 1_usize);
+        StorageDead(_29);
+        (*_28) = move _30;
+        StorageDead(_30);
+        _26 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
+        goto -> bb13;
+    }
+
+    bb13: {
+        StorageDead(_23);
+        StorageDead(_22);
+        StorageDead(_28);
+        StorageLive(_31);
+        _31 = copy _26 as *const T (Transmute);
+        _32 = &(*_31);
+        StorageDead(_31);
+        StorageDead(_26);
+        _33 = Option::<&T>::Some(copy _32);
         StorageDead(_18);
-        StorageDead(_17);
+        StorageDead(_32);
         StorageDead(_14);
+        StorageDead(_19);
+        StorageDead(_20);
+        _34 = copy ((_33 as Some).0: &T);
+        StorageLive(_35);
+        _35 = &_2;
+        StorageLive(_36);
+        _36 = (copy _34,);
+        _37 = <impl Fn(&T) as Fn<(&T,)>>::call(move _35, move _36) -> [return: bb14, unwind unreachable];
+    }
+
+    bb14: {
+        StorageDead(_36);
+        StorageDead(_35);
+        StorageDead(_33);
         goto -> bb4;
     }
 
-    bb10: {
-        unreachable;
+    bb15: {
+        StorageDead(_18);
+        StorageDead(_32);
+        StorageDead(_14);
+        StorageDead(_19);
+        StorageDead(_20);
+        StorageDead(_33);
+        StorageDead(_12);
+        drop(_2) -> [return: bb16, unwind unreachable];
+    }
+
+    bb16: {
+        return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
index cb0d640d445..e40bff5ea35 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir
@@ -7,19 +7,87 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     let mut _10: std::slice::Iter<'_, T>;
     let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>;
     let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>;
-    let mut _14: std::option::Option<&T>;
-    let mut _15: isize;
-    let mut _17: &impl Fn(&T);
-    let mut _18: (&T,);
-    let _19: ();
+    let mut _33: std::option::Option<&T>;
+    let mut _35: &impl Fn(&T);
+    let mut _36: (&T,);
+    let _37: ();
     scope 1 {
         debug iter => _12;
-        let _16: &T;
+        let _34: &T;
         scope 2 {
-            debug x => _16;
+            debug x => _34;
         }
         scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) {
-            let mut _13: &mut std::slice::Iter<'_, T>;
+            scope 19 (inlined <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back) {
+                let mut _13: *const T;
+                let mut _18: bool;
+                let mut _19: *const T;
+                let _32: &T;
+                scope 20 {
+                    let _14: std::ptr::NonNull<T>;
+                    let _20: usize;
+                    scope 21 {
+                    }
+                    scope 22 {
+                        scope 25 (inlined <NonNull<T> as PartialEq>::eq) {
+                            let mut _15: std::ptr::NonNull<T>;
+                            let mut _16: *mut T;
+                            let mut _17: *mut T;
+                            scope 26 (inlined NonNull::<T>::as_ptr) {
+                            }
+                            scope 27 (inlined NonNull::<T>::as_ptr) {
+                            }
+                        }
+                    }
+                    scope 23 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
+                        scope 24 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
+                        }
+                    }
+                }
+                scope 28 (inlined std::slice::Iter::<'_, T>::next_back_unchecked) {
+                    let _26: std::ptr::NonNull<T>;
+                    scope 29 (inlined std::slice::Iter::<'_, T>::pre_dec_end) {
+                        let mut _21: *mut *const T;
+                        let mut _22: *mut std::ptr::NonNull<T>;
+                        let mut _23: std::ptr::NonNull<T>;
+                        let mut _27: *mut *const T;
+                        let mut _28: *mut usize;
+                        let mut _29: usize;
+                        let mut _30: usize;
+                        scope 30 {
+                            scope 31 {
+                            }
+                            scope 32 {
+                                scope 35 (inlined NonNull::<T>::sub) {
+                                    scope 36 (inlined #[track_caller] core::num::<impl isize>::unchecked_neg) {
+                                        scope 37 (inlined core::ub_checks::check_language_ub) {
+                                            scope 38 (inlined core::ub_checks::check_language_ub::runtime) {
+                                            }
+                                        }
+                                    }
+                                    scope 39 (inlined NonNull::<T>::offset) {
+                                        let mut _24: *const T;
+                                        let mut _25: *const T;
+                                        scope 40 (inlined NonNull::<T>::as_ptr) {
+                                        }
+                                    }
+                                }
+                            }
+                            scope 33 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<usize>) {
+                            }
+                            scope 34 (inlined std::ptr::mut_ptr::<impl *mut *const T>::cast::<NonNull<T>>) {
+                            }
+                        }
+                    }
+                    scope 41 (inlined NonNull::<T>::as_ref::<'_>) {
+                        let _31: *const T;
+                        scope 42 (inlined NonNull::<T>::as_ptr) {
+                        }
+                        scope 43 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) {
+                        }
+                    }
+                }
+            }
         }
     }
     scope 3 (inlined core::slice::<impl [T]>::iter) {
@@ -105,53 +173,144 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () {
     }
 
     bb4: {
+        StorageLive(_33);
+        StorageLive(_20);
+        StorageLive(_19);
         StorageLive(_14);
-        StorageLive(_13);
-        _13 = &mut (_12.0: std::slice::Iter<'_, T>);
-        _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind: bb11];
+        StorageLive(_32);
+        StorageLive(_18);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
+        StorageLive(_13);
+        _13 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _14 = copy _13 as std::ptr::NonNull<T> (Transmute);
         StorageDead(_13);
-        _15 = discriminant(_14);
-        switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10];
+        StorageLive(_16);
+        StorageLive(_15);
+        _15 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
+        _16 = copy _15 as *mut T (Transmute);
+        StorageDead(_15);
+        StorageLive(_17);
+        _17 = copy _14 as *mut T (Transmute);
+        _18 = Eq(copy _16, copy _17);
+        StorageDead(_17);
+        StorageDead(_16);
+        goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_14);
-        StorageDead(_12);
-        drop(_2) -> [return: bb7, unwind continue];
+        _19 = copy ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _20 = copy _19 as usize (Transmute);
+        _18 = Eq(copy _20, const 0_usize);
+        goto -> bb7;
     }
 
     bb7: {
-        return;
+        switchInt(move _18) -> [0: bb8, otherwise: bb17];
     }
 
     bb8: {
-        _16 = copy ((_14 as Some).0: &T);
-        StorageLive(_17);
-        _17 = &_2;
-        StorageLive(_18);
-        _18 = (copy _16,);
-        _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11];
+        StorageLive(_26);
+        StorageLive(_28);
+        StorageLive(_22);
+        StorageLive(_23);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb9, otherwise: bb12];
     }
 
     bb9: {
+        StorageLive(_21);
+        _21 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _22 = copy _21 as *mut std::ptr::NonNull<T> (PtrToPtr);
+        StorageDead(_21);
+        _23 = copy (*_22);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb10, otherwise: bb11];
+    }
+
+    bb10: {
+        StorageLive(_25);
+        StorageLive(_24);
+        _24 = copy _23 as *const T (Transmute);
+        _25 = Offset(copy _24, const -1_isize);
+        StorageDead(_24);
+        _23 = NonNull::<T> { pointer: copy _25 };
+        StorageDead(_25);
+        goto -> bb11;
+    }
+
+    bb11: {
+        (*_22) = move _23;
+        _26 = copy (*_22);
+        goto -> bb13;
+    }
+
+    bb12: {
+        StorageLive(_27);
+        _27 = &raw mut ((_12.0: std::slice::Iter<'_, T>).1: *const T);
+        _28 = copy _27 as *mut usize (PtrToPtr);
+        StorageDead(_27);
+        StorageLive(_30);
+        StorageLive(_29);
+        _29 = copy (*_28);
+        _30 = SubUnchecked(move _29, const 1_usize);
+        StorageDead(_29);
+        (*_28) = move _30;
+        StorageDead(_30);
+        _26 = copy ((_12.0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>);
+        goto -> bb13;
+    }
+
+    bb13: {
+        StorageDead(_23);
+        StorageDead(_22);
+        StorageDead(_28);
+        StorageLive(_31);
+        _31 = copy _26 as *const T (Transmute);
+        _32 = &(*_31);
+        StorageDead(_31);
+        StorageDead(_26);
+        _33 = Option::<&T>::Some(copy _32);
         StorageDead(_18);
-        StorageDead(_17);
+        StorageDead(_32);
         StorageDead(_14);
-        goto -> bb4;
+        StorageDead(_19);
+        StorageDead(_20);
+        _34 = copy ((_33 as Some).0: &T);
+        StorageLive(_35);
+        _35 = &_2;
+        StorageLive(_36);
+        _36 = (copy _34,);
+        _37 = <impl Fn(&T) as Fn<(&T,)>>::call(move _35, move _36) -> [return: bb14, unwind: bb15];
     }
 
-    bb10: {
-        unreachable;
+    bb14: {
+        StorageDead(_36);
+        StorageDead(_35);
+        StorageDead(_33);
+        goto -> bb4;
     }
 
-    bb11 (cleanup): {
-        drop(_2) -> [return: bb12, unwind terminate(cleanup)];
+    bb15 (cleanup): {
+        drop(_2) -> [return: bb16, unwind terminate(cleanup)];
     }
 
-    bb12 (cleanup): {
+    bb16 (cleanup): {
         resume;
     }
+
+    bb17: {
+        StorageDead(_18);
+        StorageDead(_32);
+        StorageDead(_14);
+        StorageDead(_19);
+        StorageDead(_20);
+        StorageDead(_33);
+        StorageDead(_12);
+        drop(_2) -> [return: bb18, unwind continue];
+    }
+
+    bb18: {
+        return;
+    }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
index 78f96bf4195..62b738c36bf 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-abort.mir
@@ -3,12 +3,187 @@
 fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> {
     debug it => _1;
     let mut _0: std::option::Option<&mut T>;
+    scope 1 (inlined <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back) {
+        let mut _2: *mut T;
+        let mut _7: bool;
+        let mut _8: *mut T;
+        let mut _21: &mut T;
+        scope 2 {
+            let _3: std::ptr::NonNull<T>;
+            let _9: usize;
+            scope 3 {
+            }
+            scope 4 {
+                scope 7 (inlined <NonNull<T> as PartialEq>::eq) {
+                    let mut _4: std::ptr::NonNull<T>;
+                    let mut _5: *mut T;
+                    let mut _6: *mut T;
+                    scope 8 (inlined NonNull::<T>::as_ptr) {
+                    }
+                    scope 9 (inlined NonNull::<T>::as_ptr) {
+                    }
+                }
+            }
+            scope 5 (inlined std::ptr::mut_ptr::<impl *mut T>::addr) {
+                scope 6 (inlined std::ptr::mut_ptr::<impl *mut T>::cast::<()>) {
+                }
+            }
+        }
+        scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) {
+            let mut _15: std::ptr::NonNull<T>;
+            scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) {
+                let mut _10: *mut *mut T;
+                let mut _11: *mut std::ptr::NonNull<T>;
+                let mut _12: std::ptr::NonNull<T>;
+                let mut _16: *mut *mut T;
+                let mut _17: *mut usize;
+                let mut _18: usize;
+                let mut _19: usize;
+                scope 12 {
+                    scope 13 {
+                    }
+                    scope 14 {
+                        scope 17 (inlined NonNull::<T>::sub) {
+                            scope 18 (inlined #[track_caller] core::num::<impl isize>::unchecked_neg) {
+                                scope 19 (inlined core::ub_checks::check_language_ub) {
+                                    scope 20 (inlined core::ub_checks::check_language_ub::runtime) {
+                                    }
+                                }
+                            }
+                            scope 21 (inlined NonNull::<T>::offset) {
+                                let mut _13: *const T;
+                                let mut _14: *const T;
+                                scope 22 (inlined NonNull::<T>::as_ptr) {
+                                }
+                            }
+                        }
+                    }
+                    scope 15 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<usize>) {
+                    }
+                    scope 16 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<NonNull<T>>) {
+                    }
+                }
+            }
+            scope 23 (inlined NonNull::<T>::as_mut::<'_>) {
+                let mut _20: *mut T;
+                scope 24 (inlined NonNull::<T>::as_ptr) {
+                }
+            }
+        }
+    }
 
     bb0: {
-        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind unreachable];
+        StorageLive(_9);
+        StorageLive(_8);
+        StorageLive(_3);
+        StorageLive(_2);
+        StorageLive(_21);
+        StorageLive(_7);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
+        _2 = copy ((*_1).1: *mut T);
+        _3 = copy _2 as std::ptr::NonNull<T> (Transmute);
+        StorageLive(_5);
+        StorageLive(_4);
+        _4 = copy ((*_1).0: std::ptr::NonNull<T>);
+        _5 = copy _4 as *mut T (Transmute);
+        StorageDead(_4);
+        StorageLive(_6);
+        _6 = copy _3 as *mut T (Transmute);
+        _7 = Eq(copy _5, copy _6);
+        StorageDead(_6);
+        StorageDead(_5);
+        goto -> bb3;
+    }
+
+    bb2: {
+        _8 = copy ((*_1).1: *mut T);
+        _9 = copy _8 as usize (Transmute);
+        _7 = Eq(copy _9, const 0_usize);
+        goto -> bb3;
+    }
+
+    bb3: {
+        switchInt(move _7) -> [0: bb4, otherwise: bb10];
+    }
+
+    bb4: {
+        StorageLive(_15);
+        StorageLive(_17);
+        StorageLive(_11);
+        StorageLive(_12);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
+    }
+
+    bb5: {
+        StorageLive(_10);
+        _10 = &raw mut ((*_1).1: *mut T);
+        _11 = copy _10 as *mut std::ptr::NonNull<T> (PtrToPtr);
+        StorageDead(_10);
+        _12 = copy (*_11);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb6, otherwise: bb7];
+    }
+
+    bb6: {
+        StorageLive(_14);
+        StorageLive(_13);
+        _13 = copy _12 as *const T (Transmute);
+        _14 = Offset(copy _13, const -1_isize);
+        StorageDead(_13);
+        _12 = NonNull::<T> { pointer: copy _14 };
+        StorageDead(_14);
+        goto -> bb7;
+    }
+
+    bb7: {
+        (*_11) = move _12;
+        _15 = copy (*_11);
+        goto -> bb9;
+    }
+
+    bb8: {
+        StorageLive(_16);
+        _16 = &raw mut ((*_1).1: *mut T);
+        _17 = copy _16 as *mut usize (PtrToPtr);
+        StorageDead(_16);
+        StorageLive(_19);
+        StorageLive(_18);
+        _18 = copy (*_17);
+        _19 = SubUnchecked(move _18, const 1_usize);
+        StorageDead(_18);
+        (*_17) = move _19;
+        StorageDead(_19);
+        _15 = copy ((*_1).0: std::ptr::NonNull<T>);
+        goto -> bb9;
+    }
+
+    bb9: {
+        StorageDead(_12);
+        StorageDead(_11);
+        StorageDead(_17);
+        StorageLive(_20);
+        _20 = copy _15 as *mut T (Transmute);
+        _21 = &mut (*_20);
+        StorageDead(_20);
+        StorageDead(_15);
+        _0 = Option::<&mut T>::Some(copy _21);
+        goto -> bb11;
+    }
+
+    bb10: {
+        _0 = const {transmute(0x0000000000000000): Option<&mut T>};
+        goto -> bb11;
+    }
+
+    bb11: {
+        StorageDead(_7);
+        StorageDead(_21);
+        StorageDead(_2);
+        StorageDead(_3);
+        StorageDead(_8);
+        StorageDead(_9);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
index dfe5e206fad..62b738c36bf 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_mut_next_back.PreCodegen.after.panic-unwind.mir
@@ -3,12 +3,187 @@
 fn slice_iter_mut_next_back(_1: &mut std::slice::IterMut<'_, T>) -> Option<&mut T> {
     debug it => _1;
     let mut _0: std::option::Option<&mut T>;
+    scope 1 (inlined <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back) {
+        let mut _2: *mut T;
+        let mut _7: bool;
+        let mut _8: *mut T;
+        let mut _21: &mut T;
+        scope 2 {
+            let _3: std::ptr::NonNull<T>;
+            let _9: usize;
+            scope 3 {
+            }
+            scope 4 {
+                scope 7 (inlined <NonNull<T> as PartialEq>::eq) {
+                    let mut _4: std::ptr::NonNull<T>;
+                    let mut _5: *mut T;
+                    let mut _6: *mut T;
+                    scope 8 (inlined NonNull::<T>::as_ptr) {
+                    }
+                    scope 9 (inlined NonNull::<T>::as_ptr) {
+                    }
+                }
+            }
+            scope 5 (inlined std::ptr::mut_ptr::<impl *mut T>::addr) {
+                scope 6 (inlined std::ptr::mut_ptr::<impl *mut T>::cast::<()>) {
+                }
+            }
+        }
+        scope 10 (inlined std::slice::IterMut::<'_, T>::next_back_unchecked) {
+            let mut _15: std::ptr::NonNull<T>;
+            scope 11 (inlined std::slice::IterMut::<'_, T>::pre_dec_end) {
+                let mut _10: *mut *mut T;
+                let mut _11: *mut std::ptr::NonNull<T>;
+                let mut _12: std::ptr::NonNull<T>;
+                let mut _16: *mut *mut T;
+                let mut _17: *mut usize;
+                let mut _18: usize;
+                let mut _19: usize;
+                scope 12 {
+                    scope 13 {
+                    }
+                    scope 14 {
+                        scope 17 (inlined NonNull::<T>::sub) {
+                            scope 18 (inlined #[track_caller] core::num::<impl isize>::unchecked_neg) {
+                                scope 19 (inlined core::ub_checks::check_language_ub) {
+                                    scope 20 (inlined core::ub_checks::check_language_ub::runtime) {
+                                    }
+                                }
+                            }
+                            scope 21 (inlined NonNull::<T>::offset) {
+                                let mut _13: *const T;
+                                let mut _14: *const T;
+                                scope 22 (inlined NonNull::<T>::as_ptr) {
+                                }
+                            }
+                        }
+                    }
+                    scope 15 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<usize>) {
+                    }
+                    scope 16 (inlined std::ptr::mut_ptr::<impl *mut *mut T>::cast::<NonNull<T>>) {
+                    }
+                }
+            }
+            scope 23 (inlined NonNull::<T>::as_mut::<'_>) {
+                let mut _20: *mut T;
+                scope 24 (inlined NonNull::<T>::as_ptr) {
+                }
+            }
+        }
+    }
 
     bb0: {
-        _0 = <std::slice::IterMut<'_, T> as DoubleEndedIterator>::next_back(move _1) -> [return: bb1, unwind continue];
+        StorageLive(_9);
+        StorageLive(_8);
+        StorageLive(_3);
+        StorageLive(_2);
+        StorageLive(_21);
+        StorageLive(_7);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
+        _2 = copy ((*_1).1: *mut T);
+        _3 = copy _2 as std::ptr::NonNull<T> (Transmute);
+        StorageLive(_5);
+        StorageLive(_4);
+        _4 = copy ((*_1).0: std::ptr::NonNull<T>);
+        _5 = copy _4 as *mut T (Transmute);
+        StorageDead(_4);
+        StorageLive(_6);
+        _6 = copy _3 as *mut T (Transmute);
+        _7 = Eq(copy _5, copy _6);
+        StorageDead(_6);
+        StorageDead(_5);
+        goto -> bb3;
+    }
+
+    bb2: {
+        _8 = copy ((*_1).1: *mut T);
+        _9 = copy _8 as usize (Transmute);
+        _7 = Eq(copy _9, const 0_usize);
+        goto -> bb3;
+    }
+
+    bb3: {
+        switchInt(move _7) -> [0: bb4, otherwise: bb10];
+    }
+
+    bb4: {
+        StorageLive(_15);
+        StorageLive(_17);
+        StorageLive(_11);
+        StorageLive(_12);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8];
+    }
+
+    bb5: {
+        StorageLive(_10);
+        _10 = &raw mut ((*_1).1: *mut T);
+        _11 = copy _10 as *mut std::ptr::NonNull<T> (PtrToPtr);
+        StorageDead(_10);
+        _12 = copy (*_11);
+        switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb6, otherwise: bb7];
+    }
+
+    bb6: {
+        StorageLive(_14);
+        StorageLive(_13);
+        _13 = copy _12 as *const T (Transmute);
+        _14 = Offset(copy _13, const -1_isize);
+        StorageDead(_13);
+        _12 = NonNull::<T> { pointer: copy _14 };
+        StorageDead(_14);
+        goto -> bb7;
+    }
+
+    bb7: {
+        (*_11) = move _12;
+        _15 = copy (*_11);
+        goto -> bb9;
+    }
+
+    bb8: {
+        StorageLive(_16);
+        _16 = &raw mut ((*_1).1: *mut T);
+        _17 = copy _16 as *mut usize (PtrToPtr);
+        StorageDead(_16);
+        StorageLive(_19);
+        StorageLive(_18);
+        _18 = copy (*_17);
+        _19 = SubUnchecked(move _18, const 1_usize);
+        StorageDead(_18);
+        (*_17) = move _19;
+        StorageDead(_19);
+        _15 = copy ((*_1).0: std::ptr::NonNull<T>);
+        goto -> bb9;
+    }
+
+    bb9: {
+        StorageDead(_12);
+        StorageDead(_11);
+        StorageDead(_17);
+        StorageLive(_20);
+        _20 = copy _15 as *mut T (Transmute);
+        _21 = &mut (*_20);
+        StorageDead(_20);
+        StorageDead(_15);
+        _0 = Option::<&mut T>::Some(copy _21);
+        goto -> bb11;
+    }
+
+    bb10: {
+        _0 = const {transmute(0x0000000000000000): Option<&mut T>};
+        goto -> bb11;
+    }
+
+    bb11: {
+        StorageDead(_7);
+        StorageDead(_21);
+        StorageDead(_2);
+        StorageDead(_3);
+        StorageDead(_8);
+        StorageDead(_9);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
index fe4e2deab87..79aa9c5ae1e 100644
--- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-abort.mir
@@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 {
     }
 
     bb0: {
-        _2 = &_1;                        // scope 0 at $DIR/spans.rs:11:11: 11:13
+        // DBG: _2 = &_1;
         _0 = copy _1;                    // scope 1 at $DIR/spans.rs:15:5: 15:7
         return;                          // scope 0 at $DIR/spans.rs:12:2: 12:2
     }
diff --git a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
index fe4e2deab87..79aa9c5ae1e 100644
--- a/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/spans.outer.PreCodegen.after.panic-unwind.mir
@@ -9,7 +9,7 @@ fn outer(_1: u8) -> u8 {
     }
 
     bb0: {
-        _2 = &_1;                        // scope 0 at $DIR/spans.rs:11:11: 11:13
+        // DBG: _2 = &_1;
         _0 = copy _1;                    // scope 1 at $DIR/spans.rs:15:5: 15:7
         return;                          // scope 0 at $DIR/spans.rs:12:2: 12:2
     }
diff --git a/tests/run-make/panic-abort-eh_frame/rmake.rs b/tests/run-make/panic-abort-eh_frame/rmake.rs
index 23d95dc5774..2eccde62795 100644
--- a/tests/run-make/panic-abort-eh_frame/rmake.rs
+++ b/tests/run-make/panic-abort-eh_frame/rmake.rs
@@ -1,9 +1,11 @@
 // An `.eh_frame` section in an object file is a symptom of an UnwindAction::Terminate
 // being inserted, useful for determining whether or not unwinding is necessary.
-// This is useless when panics would NEVER unwind due to -C panic=abort. This section should
-// therefore never appear in the emit file of a -C panic=abort compilation, and this test
-// checks that this is respected.
-// See https://github.com/rust-lang/rust/pull/112403
+// This is useless when panics would NEVER unwind due to -C panic=abort and when we don't need
+// being able to generate backtraces (which depend on unwind tables on linux). This section should
+// therefore never appear in the emit file of a -C panic=abort compilation
+// with -C force-unwind-tables=no, and this test checks that this is respected.
+// See https://github.com/rust-lang/rust/pull/112403 and
+// https://github.com/rust-lang/rust/pull/143613.
 
 //@ only-linux
 // FIXME(Oneirical): the DW_CFA symbol appears on Windows-gnu, because uwtable
@@ -19,6 +21,7 @@ fn main() {
         .panic("abort")
         .edition("2021")
         .arg("-Zvalidate-mir")
+        .arg("-Cforce-unwind-tables=no")
         .run();
     llvm_objdump().arg("--dwarf=frames").input("foo.o").run().assert_stdout_not_contains("DW_CFA");
 }
diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml
index fe0f6401089..e5c11651bd2 100644
--- a/tests/rustdoc-gui/search-result-color.goml
+++ b/tests/rustdoc-gui/search-result-color.goml
@@ -5,7 +5,7 @@ include: "utils.goml"
 define-function: (
     "check-search-color",
     [
-        theme, count_color, desc_color, path_color, bottom_border_color, keyword_color,
+        theme, count_color, path_color, bottom_border_color, keyword_color,
         struct_color, associatedtype_color, tymethod_color, method_color, structfield_color,
         structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background,
         attribute_color, grey
@@ -22,10 +22,6 @@ define-function: (
             ALL,
         )
         assert-css: (
-            "//*[@class='desc'][normalize-space()='Just a normal struct.']",
-            {"color": |desc_color|},
-        )
-        assert-css: (
             "//*[@class='result-name']//*[normalize-space()='test_docs::']",
             {"color": |path_color|},
         )
@@ -97,16 +93,6 @@ define-function: (
             ALL,
         )
 
-        // Checking color and background on hover.
-        move-cursor-to: "//*[@class='desc'][normalize-space()='Just a normal struct.']"
-        assert-css: (
-            "//*[@class='result-name']//*[normalize-space()='test_docs::']",
-            {"color": |hover_path_color|},
-        )
-        assert-css: (
-            "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a",
-            {"color": |hover_path_color|, "background-color": |hover_background|},
-        )
     }
 )
 
@@ -157,7 +143,6 @@ show-text: true
 call-function: ("check-search-color", {
     "theme": "ayu",
     "count_color": "#888",
-    "desc_color": "#c5c5c5",
     "path_color": "#0096cf",
     "bottom_border_color": "#aaa3",
     "keyword_color": "#39afd7",
@@ -179,7 +164,6 @@ call-function: ("check-search-color", {
 call-function: ("check-search-color", {
     "theme": "dark",
     "count_color": "#888",
-    "desc_color": "#ddd",
     "path_color": "#ddd",
     "bottom_border_color": "#aaa3",
     "keyword_color": "#d2991d",
@@ -201,7 +185,6 @@ call-function: ("check-search-color", {
 call-function: ("check-search-color", {
     "theme": "light",
     "count_color": "#888",
-    "desc_color": "#000",
     "path_color": "#000",
     "bottom_border_color": "#aaa3",
     "keyword_color": "#3873ad",
@@ -226,12 +209,27 @@ call-function: ("perform-search", {"query": "thisisanalias"})
 
 define-function: (
     "check-alias",
-    [theme, alias, grey],
+    [theme, alias, grey, desc_color, hover_path_color, hover_background],
     block {
         call-function: ("switch-theme", {"theme": |theme|})
         // Checking that the colors for the alias element are the ones expected.
         assert-css: (".result-name .path .alias", {"color": |alias|})
         assert-css: (".result-name .path .alias > .grey", {"color": |grey|})
+        assert-css: (
+            "//*[@class='desc'][normalize-space()='Just a normal enum.']",
+            {"color": |desc_color|},
+        )
+        // Checking color and background on hover.
+        move-cursor-to: "//*[@class='desc'][normalize-space()='Just a normal enum.']"
+        assert-css: (
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']",
+            {"color": |hover_path_color|},
+        )
+        assert-css: (
+            "//*[@class='result-name']//*[normalize-space()='test_docs::']/ancestor::a",
+            {"color": |hover_path_color|, "background-color": |hover_background|},
+        )
+
     },
 )
 
@@ -239,14 +237,23 @@ call-function: ("check-alias", {
     "theme": "ayu",
     "alias": "#c5c5c5",
     "grey": "#999",
+    "desc_color": "#c5c5c5",
+    "hover_path_color": "#fff",
+    "hover_background": "#3c3c3c",
 })
 call-function: ("check-alias", {
     "theme": "dark",
     "alias": "#fff",
     "grey": "#ccc",
+    "desc_color": "#ddd",
+    "hover_path_color": "#ddd",
+    "hover_background": "#616161",
 })
 call-function: ("check-alias", {
     "theme": "light",
     "alias": "#000",
     "grey": "#999",
+    "desc_color": "#000",
+    "hover_path_color": "#000",
+    "hover_background": "#ccc",
 })
diff --git a/tests/rustdoc-gui/search-tab.goml b/tests/rustdoc-gui/search-tab.goml
index 00ca952033d..0a3cfc231e5 100644
--- a/tests/rustdoc-gui/search-tab.goml
+++ b/tests/rustdoc-gui/search-tab.goml
@@ -79,7 +79,7 @@ call-function: ("check-colors", {
 set-window-size: (851, 600)
 
 // Check the size and count in tabs
-assert-text: ("#search-tabs > button:nth-child(1) > .count", " (27) ")
+assert-text: ("#search-tabs > button:nth-child(1) > .count", " (25) ")
 assert-text: ("#search-tabs > button:nth-child(2) > .count", " (7)  ")
 assert-text: ("#search-tabs > button:nth-child(3) > .count", " (0)  ")
 store-property: ("#search-tabs > button:nth-child(1)", {"offsetWidth": buttonWidth})
diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml
index 5ec0008ad8a..0d371c8c6a4 100644
--- a/tests/rustdoc-gui/sidebar.goml
+++ b/tests/rustdoc-gui/sidebar.goml
@@ -1,5 +1,7 @@
 // Checks multiple things on the sidebar display (width of its elements, colors, etc).
 include: "utils.goml"
+// Disable animations so they don't mess up color assertions later.
+emulate-media-features: { "prefers-reduced-motion": "reduce" }
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-property: (".sidebar", {"clientWidth": "199"})
 show-text: true
diff --git a/tests/rustdoc-js-std/asrawfd.js b/tests/rustdoc-js-std/asrawfd.js
index 5dbc4ba95d9..da08eeb8a53 100644
--- a/tests/rustdoc-js-std/asrawfd.js
+++ b/tests/rustdoc-js-std/asrawfd.js
@@ -1,12 +1,10 @@
 // ignore-order
 
 const EXPECTED = {
-    'query': 'RawFd::as_raw_fd',
+    'query': 'method:RawFd::as_raw_fd',
     'others': [
         // Reproduction test for https://github.com/rust-lang/rust/issues/78724
         // Validate that type alias methods get the correct path.
-        { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
-        { 'path': 'std::os::fd::AsRawFd', 'name': 'as_raw_fd' },
         { 'path': 'std::os::fd::RawFd', 'name': 'as_raw_fd' },
     ],
 };
diff --git a/tests/rustdoc-js-std/quoted.js b/tests/rustdoc-js-std/quoted.js
index 8a927501925..a8ca6521208 100644
--- a/tests/rustdoc-js-std/quoted.js
+++ b/tests/rustdoc-js-std/quoted.js
@@ -1,21 +1,21 @@
+// make sure quoted search works both for items and and without generics
 // ignore-order
 
 const FILTER_CRATE = 'std';
 
 const EXPECTED = {
-    'query': '"error"',
+    'query': '"result"',
     'others': [
-        { 'path': 'std', 'name': 'error' },
-        { 'path': 'std::fmt', 'name': 'Error' },
-        { 'path': 'std::io', 'name': 'Error' },
+        { 'path': 'std', 'name': 'result' },
+        { 'path': 'std::result', 'name': 'Result' },
+        { 'path': 'std::fmt', 'name': 'Result' },
     ],
     'in_args': [
-        { 'path': 'std::fmt::Error', 'name': 'eq' },
-        { 'path': 'std::fmt::Error', 'name': 'cmp' },
-        { 'path': 'std::fmt::Error', 'name': 'partial_cmp' },
-
+        { 'path': 'std::result::Result', 'name': 'branch' },
+        { 'path': 'std::result::Result', 'name': 'ok' },
+        { 'path': 'std::result::Result', 'name': 'unwrap' },
     ],
     'returned': [
-        { 'path': 'std::fmt::LowerExp', 'name': 'fmt' },
+        { 'path': 'std::bool', 'name': 'try_into' },
     ],
 };
diff --git a/tests/rustdoc-js-std/bufread-fill-buf.js b/tests/rustdoc-js-std/trait-unbox.js
index 6b9309f6864..44ddc0c1e75 100644
--- a/tests/rustdoc-js-std/bufread-fill-buf.js
+++ b/tests/rustdoc-js-std/trait-unbox.js
@@ -1,10 +1,10 @@
-// ignore-order
+// make sure type-based searches with traits get unboxed too
 
 const EXPECTED = [
     {
-        'query': 'bufread -> result<[u8]>',
+        'query': 'any -> result<box>',
         'others': [
-            { 'path': 'std::boxed::Box', 'name': 'fill_buf' },
+            { 'path': 'std::boxed::Box', 'name': 'downcast' },
         ],
     },
     {
diff --git a/tests/rustdoc-js/trait-methods.js b/tests/rustdoc-js/trait-methods.js
index dafad5e4378..083e52439f4 100644
--- a/tests/rustdoc-js/trait-methods.js
+++ b/tests/rustdoc-js/trait-methods.js
@@ -9,4 +9,24 @@ const EXPECTED = [
             { 'path': 'trait_methods::MyTrait', 'name': 'next' },
         ],
     },
+    // the traitParent deduplication pass should remove
+    // Empty::next, as it would be redundant
+    {
+        'query': 'next',
+        'correction': null,
+        'in_args': [],
+        'others': [
+            { 'path': 'trait_methods::MyTrait', 'name': 'next' },
+        ],
+    },
+    // if the trait does not match, no deduplication happens
+    {
+        'query': '-> option<()>',
+        'correction': null,
+        'in_args': [],
+        'others': [
+            { 'path': 'trait_methods::Empty', 'name': 'next' },
+                    { 'path': 'trait_methods::Void', 'name': 'next' },
+        ],
+    },
 ];
diff --git a/tests/rustdoc-js/trait-methods.rs b/tests/rustdoc-js/trait-methods.rs
index c88f5edfd55..a741b361a33 100644
--- a/tests/rustdoc-js/trait-methods.rs
+++ b/tests/rustdoc-js/trait-methods.rs
@@ -2,3 +2,21 @@ pub trait MyTrait {
     type Item;
     fn next(&mut self) -> Option<Self::Item>;
 }
+
+pub struct Empty;
+
+impl MyTrait for Empty {
+    type Item = ();
+    fn next(&mut self) -> Option<()> {
+        None
+    }
+}
+
+pub struct Void;
+
+impl MyTrait for Void {
+    type Item = ();
+    fn next(&mut self) -> Option<()> {
+        Some(())
+    }
+}
diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
index df5f29e35fe..86f2d5f5954 100644
--- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
+++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs
@@ -2,7 +2,6 @@
 // Testing that a librustc_ast can parse modules with canonicalized base path
 //@ ignore-cross-compile
 //@ ignore-remote
-// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled.
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.rs b/tests/ui/associated-type-bounds/duplicate-bound-err.rs
new file mode 100644
index 00000000000..01cc05f2545
--- /dev/null
+++ b/tests/ui/associated-type-bounds/duplicate-bound-err.rs
@@ -0,0 +1,114 @@
+//@ edition: 2024
+
+#![feature(associated_const_equality, type_alias_impl_trait, return_type_notation)]
+#![allow(refining_impl_trait_internal)]
+
+use std::iter;
+
+fn rpit1() -> impl Iterator<Item: Copy, Item: Send> {
+    iter::empty()
+    //~^ ERROR type annotations needed
+}
+fn rpit2() -> impl Iterator<Item: Copy, Item: Copy> {
+    iter::empty()
+    //~^ ERROR type annotations needed
+}
+fn rpit3() -> impl Iterator<Item: 'static, Item: 'static> {
+    iter::empty()
+    //~^ ERROR type annotations needed
+}
+
+type Tait1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
+//~^ ERROR unconstrained opaque type
+type Tait2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
+//~^ ERROR unconstrained opaque type
+type Tait3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
+//~^ ERROR unconstrained opaque type
+
+type Tait4 = impl Iterator<Item: Copy, Item: Send>;
+//~^ ERROR unconstrained opaque type
+type Tait5 = impl Iterator<Item: Copy, Item: Copy>;
+//~^ ERROR unconstrained opaque type
+type Tait6 = impl Iterator<Item: 'static, Item: 'static>;
+//~^ ERROR unconstrained opaque type
+
+fn mismatch() -> impl Iterator<Item: Copy, Item: Send> {
+    //~^ ERROR [E0277]
+    iter::empty::<*const ()>()
+}
+
+fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
+    //~^ ERROR [E0277]
+    iter::empty::<String>()
+}
+
+trait Trait {
+    type Gat<T>;
+
+    const ASSOC: i32;
+
+    fn foo() -> impl Sized;
+}
+
+impl Trait for () {
+    type Gat<T> = ();
+
+    const ASSOC: i32 = 3;
+
+    fn foo() {}
+}
+
+impl Trait for u32 {
+    type Gat<T> = ();
+
+    const ASSOC: i32 = 4;
+
+    fn foo() -> u32 {
+        42
+    }
+}
+
+fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
+
+fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
+
+fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
+
+type MustFail = dyn Iterator<Item = i32, Item = u32>;
+//~^ ERROR [E0719]
+//~| ERROR conflicting associated type bounds
+
+trait Trait2 {
+    const ASSOC: u32;
+}
+
+type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
+//~^ ERROR [E0719]
+//~| ERROR conflicting associated type bounds
+
+type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
+//~^ ERROR [E0719]
+
+type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
+//~^ ERROR [E0719]
+
+trait Trait3 {
+    fn foo() -> impl Iterator<Item = i32, Item = u32>;
+}
+
+impl Trait3 for () {
+    fn foo() -> impl Iterator<Item = i32, Item = u32> {
+        //~^ ERROR[E0271]
+        //~| ERROR[E0271]
+        [2u32].into_iter()
+    }
+}
+
+fn main() {
+    uncallable(iter::empty::<u32>()); //~ ERROR [E0271]
+    uncallable(iter::empty::<i32>()); //~ ERROR [E0271]
+    uncallable_const(()); //~ ERROR [E0271]
+    uncallable_const(4u32); //~ ERROR [E0271]
+    uncallable_rtn(()); //~ ERROR [E0271]
+    uncallable_rtn(17u32); //~ ERROR [E0271]
+}
diff --git a/tests/ui/associated-type-bounds/duplicate-bound-err.stderr b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr
new file mode 100644
index 00000000000..1737d0dc5a3
--- /dev/null
+++ b/tests/ui/associated-type-bounds/duplicate-bound-err.stderr
@@ -0,0 +1,268 @@
+error[E0282]: type annotations needed
+  --> $DIR/duplicate-bound-err.rs:9:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
+error[E0282]: type annotations needed
+  --> $DIR/duplicate-bound-err.rs:13:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
+error[E0282]: type annotations needed
+  --> $DIR/duplicate-bound-err.rs:17:5
+   |
+LL |     iter::empty()
+   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
+   |
+help: consider specifying the generic argument
+   |
+LL |     iter::empty::<T>()
+   |                +++++
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:21:51
+   |
+LL | type Tait1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
+   |                                                   ^^^^^^^^^
+   |
+   = note: `Tait1` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:23:51
+   |
+LL | type Tait2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
+   |                                                   ^^^^^^^^^
+   |
+   = note: `Tait2` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:25:57
+   |
+LL | type Tait3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
+   |                                                         ^^^^^^^^^
+   |
+   = note: `Tait3` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:28:14
+   |
+LL | type Tait4 = impl Iterator<Item: Copy, Item: Send>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Tait4` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:30:14
+   |
+LL | type Tait5 = impl Iterator<Item: Copy, Item: Copy>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Tait5` must be used in combination with a concrete type within the same crate
+
+error: unconstrained opaque type
+  --> $DIR/duplicate-bound-err.rs:32:14
+   |
+LL | type Tait6 = impl Iterator<Item: 'static, Item: 'static>;
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `Tait6` must be used in combination with a concrete type within the same crate
+
+error[E0277]: `*const ()` cannot be sent between threads safely
+  --> $DIR/duplicate-bound-err.rs:35:18
+   |
+LL | fn mismatch() -> impl Iterator<Item: Copy, Item: Send> {
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
+LL |
+LL |     iter::empty::<*const ()>()
+   |     -------------------------- return type was inferred to be `std::iter::Empty<*const ()>` here
+   |
+   = help: the trait `Send` is not implemented for `*const ()`
+
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/duplicate-bound-err.rs:40:20
+   |
+LL | fn mismatch_2() -> impl Iterator<Item: Copy, Item: Send> {
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+LL |
+LL |     iter::empty::<String>()
+   |     ----------------------- return type was inferred to be `std::iter::Empty<String>` here
+
+error[E0271]: expected `IntoIter<u32, 1>` to be an iterator that yields `i32`, but it yields `u32`
+  --> $DIR/duplicate-bound-err.rs:100:17
+   |
+LL |     fn foo() -> impl Iterator<Item = i32, Item = u32> {
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
+...
+LL |         [2u32].into_iter()
+   |         ------------------ return type was inferred to be `std::array::IntoIter<u32, 1>` here
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate-bound-err.rs:77:42
+   |
+LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
+   |                              ----------  ^^^^^^^^^^ re-bound here
+   |                              |
+   |                              `Item` bound here first
+
+error: conflicting associated type bounds for `Item`
+  --> $DIR/duplicate-bound-err.rs:77:17
+   |
+LL | type MustFail = dyn Iterator<Item = i32, Item = u32>;
+   |                 ^^^^^^^^^^^^^----------^^----------^
+   |                              |           |
+   |                              |           `Item` is specified to be `u32` here
+   |                              `Item` is specified to be `i32` here
+
+error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
+  --> $DIR/duplicate-bound-err.rs:85:43
+   |
+LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
+   |                             ------------  ^^^^^^^^^^^^ re-bound here
+   |                             |
+   |                             `ASSOC` bound here first
+
+error: conflicting associated type bounds for `ASSOC`
+  --> $DIR/duplicate-bound-err.rs:85:18
+   |
+LL | type MustFail2 = dyn Trait2<ASSOC = 3u32, ASSOC = 4u32>;
+   |                  ^^^^^^^^^^^------------^^------------^
+   |                             |             |
+   |                             |             `ASSOC` is specified to be `4` here
+   |                             `ASSOC` is specified to be `3` here
+
+error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
+  --> $DIR/duplicate-bound-err.rs:89:43
+   |
+LL | type MustFail3 = dyn Iterator<Item = i32, Item = i32>;
+   |                               ----------  ^^^^^^^^^^ re-bound here
+   |                               |
+   |                               `Item` bound here first
+
+error[E0719]: the value of the associated type `ASSOC` in trait `Trait2` is already specified
+  --> $DIR/duplicate-bound-err.rs:92:43
+   |
+LL | type MustFail4 = dyn Trait2<ASSOC = 3u32, ASSOC = 3u32>;
+   |                             ------------  ^^^^^^^^^^^^ re-bound here
+   |                             |
+   |                             `ASSOC` bound here first
+
+error[E0271]: expected `impl Iterator<Item = u32>` to be an iterator that yields `i32`, but it yields `u32`
+  --> $DIR/duplicate-bound-err.rs:100:17
+   |
+LL |     fn foo() -> impl Iterator<Item = i32, Item = u32> {
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
+   |
+note: required by a bound in `Trait3::foo::{anon_assoc#0}`
+  --> $DIR/duplicate-bound-err.rs:96:31
+   |
+LL |     fn foo() -> impl Iterator<Item = i32, Item = u32>;
+   |                               ^^^^^^^^^^ required by this bound in `Trait3::foo::{anon_assoc#0}`
+
+error[E0271]: expected `Empty<u32>` to be an iterator that yields `i32`, but it yields `u32`
+  --> $DIR/duplicate-bound-err.rs:108:16
+   |
+LL |     uncallable(iter::empty::<u32>());
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `uncallable`
+  --> $DIR/duplicate-bound-err.rs:71:32
+   |
+LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
+   |                                ^^^^^^^^^^ required by this bound in `uncallable`
+
+error[E0271]: expected `Empty<i32>` to be an iterator that yields `u32`, but it yields `i32`
+  --> $DIR/duplicate-bound-err.rs:109:16
+   |
+LL |     uncallable(iter::empty::<i32>());
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found `i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `uncallable`
+  --> $DIR/duplicate-bound-err.rs:71:44
+   |
+LL | fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
+   |                                            ^^^^^^^^^^ required by this bound in `uncallable`
+
+error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4`
+  --> $DIR/duplicate-bound-err.rs:110:22
+   |
+LL |     uncallable_const(());
+   |     ---------------- ^^ expected `4`, found `3`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected constant `4`
+              found constant `3`
+note: required by a bound in `uncallable_const`
+  --> $DIR/duplicate-bound-err.rs:73:46
+   |
+LL | fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
+   |                                              ^^^^^^^^^ required by this bound in `uncallable_const`
+
+error[E0271]: type mismatch resolving `<u32 as Trait>::ASSOC == 3`
+  --> $DIR/duplicate-bound-err.rs:111:22
+   |
+LL |     uncallable_const(4u32);
+   |     ---------------- ^^^^ expected `3`, found `4`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected constant `3`
+              found constant `4`
+note: required by a bound in `uncallable_const`
+  --> $DIR/duplicate-bound-err.rs:73:35
+   |
+LL | fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
+   |                                   ^^^^^^^^^ required by this bound in `uncallable_const`
+
+error[E0271]: type mismatch resolving `<() as Trait>::ASSOC == 4`
+  --> $DIR/duplicate-bound-err.rs:112:20
+   |
+LL |     uncallable_rtn(());
+   |     -------------- ^^ expected `4`, found `3`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected constant `4`
+              found constant `3`
+note: required by a bound in `uncallable_rtn`
+  --> $DIR/duplicate-bound-err.rs:75:75
+   |
+LL | fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
+   |                                                                           ^^^^^^^^^ required by this bound in `uncallable_rtn`
+
+error[E0271]: type mismatch resolving `<u32 as Trait>::ASSOC == 3`
+  --> $DIR/duplicate-bound-err.rs:113:20
+   |
+LL |     uncallable_rtn(17u32);
+   |     -------------- ^^^^^ expected `3`, found `4`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: expected constant `3`
+              found constant `4`
+note: required by a bound in `uncallable_rtn`
+  --> $DIR/duplicate-bound-err.rs:75:48
+   |
+LL | fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
+   |                                                ^^^^^^^^^ required by this bound in `uncallable_rtn`
+
+error: aborting due to 25 previous errors
+
+Some errors have detailed explanations: E0271, E0277, E0282, E0719.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/associated-type-bounds/duplicate-bound.rs b/tests/ui/associated-type-bounds/duplicate-bound.rs
new file mode 100644
index 00000000000..696710d76f6
--- /dev/null
+++ b/tests/ui/associated-type-bounds/duplicate-bound.rs
@@ -0,0 +1,240 @@
+//@ edition: 2024
+//@ run-pass
+
+#![feature(associated_const_equality, return_type_notation)]
+#![allow(dead_code, refining_impl_trait_internal, type_alias_bounds)]
+
+use std::iter;
+use std::mem::ManuallyDrop;
+
+struct Si1<T: Iterator<Item: Copy, Item: Send>> {
+    f: T,
+}
+struct Si2<T: Iterator<Item: Copy, Item: Copy>> {
+    f: T,
+}
+struct Si3<T: Iterator<Item: 'static, Item: 'static>> {
+    f: T,
+}
+struct Sw1<T>
+where
+    T: Iterator<Item: Copy, Item: Send>,
+{
+    f: T,
+}
+struct Sw2<T>
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+{
+    f: T,
+}
+struct Sw3<T>
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+{
+    f: T,
+}
+
+enum Ei1<T: Iterator<Item: Copy, Item: Send>> {
+    V(T),
+}
+enum Ei2<T: Iterator<Item: Copy, Item: Copy>> {
+    V(T),
+}
+enum Ei3<T: Iterator<Item: 'static, Item: 'static>> {
+    V(T),
+}
+enum Ew1<T>
+where
+    T: Iterator<Item: Copy, Item: Send>,
+{
+    V(T),
+}
+enum Ew2<T>
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+{
+    V(T),
+}
+enum Ew3<T>
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+{
+    V(T),
+}
+
+union Ui1<T: Iterator<Item: Copy, Item: Send>> {
+    f: ManuallyDrop<T>,
+}
+union Ui2<T: Iterator<Item: Copy, Item: Copy>> {
+    f: ManuallyDrop<T>,
+}
+union Ui3<T: Iterator<Item: 'static, Item: 'static>> {
+    f: ManuallyDrop<T>,
+}
+union Uw1<T>
+where
+    T: Iterator<Item: Copy, Item: Send>,
+{
+    f: ManuallyDrop<T>,
+}
+union Uw2<T>
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+{
+    f: ManuallyDrop<T>,
+}
+union Uw3<T>
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+{
+    f: ManuallyDrop<T>,
+}
+
+fn fi1<T: Iterator<Item: Copy, Item: Send>>() {}
+fn fi2<T: Iterator<Item: Copy, Item: Copy>>() {}
+fn fi3<T: Iterator<Item: 'static, Item: 'static>>() {}
+fn fw1<T>()
+where
+    T: Iterator<Item: Copy, Item: Send>,
+{
+}
+fn fw2<T>()
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+{
+}
+fn fw3<T>()
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+{
+}
+
+fn rpit1() -> impl Iterator<Item: Copy, Item: Send> {
+    iter::empty::<u32>()
+}
+fn rpit2() -> impl Iterator<Item: Copy, Item: Copy> {
+    iter::empty::<u32>()
+}
+fn rpit3() -> impl Iterator<Item: 'static, Item: 'static> {
+    iter::empty::<u32>()
+}
+fn apit1(_: impl Iterator<Item: Copy, Item: Send>) {}
+fn apit2(_: impl Iterator<Item: Copy, Item: Copy>) {}
+fn apit3(_: impl Iterator<Item: 'static, Item: 'static>) {}
+
+type Tait1<T: Iterator<Item: Copy, Item: Send>> = T;
+type Tait2<T: Iterator<Item: Copy, Item: Copy>> = T;
+type Tait3<T: Iterator<Item: 'static, Item: 'static>> = T;
+type Taw1<T>
+where
+    T: Iterator<Item: Copy, Item: Send>,
+= T;
+type Taw2<T>
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+= T;
+type Taw3<T>
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+= T;
+
+trait Tri1<T: Iterator<Item: Copy, Item: Send>> {}
+trait Tri2<T: Iterator<Item: Copy, Item: Copy>> {}
+trait Tri3<T: Iterator<Item: 'static, Item: 'static>> {}
+trait Trs1: Iterator<Item: Copy, Item: Send> {}
+trait Trs2: Iterator<Item: Copy, Item: Copy> {}
+trait Trs3: Iterator<Item: 'static, Item: 'static> {}
+trait Trw1<T>
+where
+    T: Iterator<Item: Copy, Item: Send>,
+{
+}
+trait Trw2<T>
+where
+    T: Iterator<Item: Copy, Item: Copy>,
+{
+}
+trait Trw3<T>
+where
+    T: Iterator<Item: 'static, Item: 'static>,
+{
+}
+trait Trsw1
+where
+    Self: Iterator<Item: Copy, Item: Send>,
+{
+}
+trait Trsw2
+where
+    Self: Iterator<Item: Copy, Item: Copy>,
+{
+}
+trait Trsw3
+where
+    Self: Iterator<Item: 'static, Item: 'static>,
+{
+}
+trait Tra1 {
+    type A: Iterator<Item: Copy, Item: Send>;
+}
+trait Tra2 {
+    type A: Iterator<Item: Copy, Item: Copy>;
+}
+trait Tra3 {
+    type A: Iterator<Item: 'static, Item: 'static>;
+}
+
+trait Trait {
+    type Gat<T>;
+
+    const ASSOC: i32;
+
+    fn foo() -> impl Sized;
+}
+
+impl Trait for () {
+    type Gat<T> = ();
+
+    const ASSOC: i32 = 3;
+
+    fn foo() {}
+}
+
+trait Subtrait: Trait<Gat<u32> = u32, Gat<u64> = u64> {}
+
+fn f<T: Trait<Gat<i32> = (), Gat<i64> = ()>>() {
+    let _: T::Gat<i32> = ();
+    let _: T::Gat<i64> = ();
+}
+
+fn g<T: Trait<Gat<i32> = (), Gat<i64> = &'static str>>() {
+    let _: T::Gat<i32> = ();
+    let _: T::Gat<i64> = "";
+}
+
+fn uncallable(_: impl Iterator<Item = i32, Item = u32>) {}
+
+fn callable(_: impl Iterator<Item = i32, Item = i32>) {}
+
+fn uncallable_const(_: impl Trait<ASSOC = 3, ASSOC = 4>) {}
+
+fn callable_const(_: impl Trait<ASSOC = 3, ASSOC = 3>) {}
+
+fn uncallable_rtn(_: impl Trait<foo(..): Trait<ASSOC = 3>, foo(..): Trait<ASSOC = 4>>) {}
+
+fn callable_rtn(_: impl Trait<foo(..): Send, foo(..): Send, foo(..): Eq>) {}
+
+trait Trait2 {
+    const ASSOC: u32;
+}
+
+trait Trait3 {
+    fn foo() -> impl Iterator<Item = i32, Item = u32>;
+}
+
+fn main() {
+    callable(iter::empty::<i32>());
+    callable_const(());
+    callable_rtn(());
+}
diff --git a/tests/ui/associated-type-bounds/duplicate.rs b/tests/ui/associated-type-bounds/duplicate.rs
deleted file mode 100644
index e9d94787e98..00000000000
--- a/tests/ui/associated-type-bounds/duplicate.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-#![feature(type_alias_impl_trait)]
-
-use std::iter;
-use std::mem::ManuallyDrop;
-
-struct SI1<T: Iterator<Item: Copy, Item: Send>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: T,
-}
-struct SI2<T: Iterator<Item: Copy, Item: Copy>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: T,
-}
-struct SI3<T: Iterator<Item: 'static, Item: 'static>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: T,
-}
-struct SW1<T>
-where
-    T: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: T,
-}
-struct SW2<T>
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: T,
-}
-struct SW3<T>
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: T,
-}
-
-enum EI1<T: Iterator<Item: Copy, Item: Send>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    V(T),
-}
-enum EI2<T: Iterator<Item: Copy, Item: Copy>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    V(T),
-}
-enum EI3<T: Iterator<Item: 'static, Item: 'static>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    V(T),
-}
-enum EW1<T>
-where
-    T: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    V(T),
-}
-enum EW2<T>
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    V(T),
-}
-enum EW3<T>
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    V(T),
-}
-
-union UI1<T: Iterator<Item: Copy, Item: Send>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: ManuallyDrop<T>,
-}
-union UI2<T: Iterator<Item: Copy, Item: Copy>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: ManuallyDrop<T>,
-}
-union UI3<T: Iterator<Item: 'static, Item: 'static>> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    f: ManuallyDrop<T>,
-}
-union UW1<T>
-where
-    T: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: ManuallyDrop<T>,
-}
-union UW2<T>
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: ManuallyDrop<T>,
-}
-union UW3<T>
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-    f: ManuallyDrop<T>,
-}
-
-fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-fn FW1<T>()
-where
-    T: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-fn FW2<T>()
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-fn FW3<T>()
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-
-fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    iter::empty()
-    //~^ ERROR type annotations needed
-}
-fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    iter::empty()
-    //~^ ERROR type annotations needed
-}
-fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    iter::empty()
-    //~^ ERROR type annotations needed
-}
-fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-
-type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-type TAW1<T>
-where
-    T: Iterator<Item: Copy, Item: Send>,
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-= T;
-type TAW2<T>
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-= T;
-type TAW3<T>
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-= T;
-
-type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR unconstrained opaque type
-
-trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRS1: Iterator<Item: Copy, Item: Send> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRS2: Iterator<Item: Copy, Item: Copy> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRS3: Iterator<Item: 'static, Item: 'static> {}
-//~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-//~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-trait TRW1<T>
-where
-    T: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRW2<T>
-where
-    T: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRW3<T>
-where
-    T: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRSW1
-where
-    Self: Iterator<Item: Copy, Item: Send>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRSW2
-where
-    Self: Iterator<Item: Copy, Item: Copy>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRSW3
-where
-    Self: Iterator<Item: 'static, Item: 'static>,
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-{
-}
-trait TRA1 {
-    type A: Iterator<Item: Copy, Item: Send>;
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-}
-trait TRA2 {
-    type A: Iterator<Item: Copy, Item: Copy>;
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-}
-trait TRA3 {
-    type A: Iterator<Item: 'static, Item: 'static>;
-    //~^ ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-    //~| ERROR the value of the associated type `Item` in trait `Iterator` is already specified [E0719]
-}
-
-fn main() {}
diff --git a/tests/ui/associated-type-bounds/duplicate.stderr b/tests/ui/associated-type-bounds/duplicate.stderr
deleted file mode 100644
index 68fbb345f6f..00000000000
--- a/tests/ui/associated-type-bounds/duplicate.stderr
+++ /dev/null
@@ -1,751 +0,0 @@
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:6:36
-   |
-LL | struct SI1<T: Iterator<Item: Copy, Item: Send>> {
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:10:36
-   |
-LL | struct SI2<T: Iterator<Item: Copy, Item: Copy>> {
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:14:39
-   |
-LL | struct SI3<T: Iterator<Item: 'static, Item: 'static>> {
-   |                        -------------  ^^^^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:20:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:27:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:34:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:40:34
-   |
-LL | enum EI1<T: Iterator<Item: Copy, Item: Send>> {
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:44:34
-   |
-LL | enum EI2<T: Iterator<Item: Copy, Item: Copy>> {
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:48:37
-   |
-LL | enum EI3<T: Iterator<Item: 'static, Item: 'static>> {
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:54:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:61:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:68:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:74:35
-   |
-LL | union UI1<T: Iterator<Item: Copy, Item: Send>> {
-   |                       ----------  ^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:78:35
-   |
-LL | union UI2<T: Iterator<Item: Copy, Item: Copy>> {
-   |                       ----------  ^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:82:38
-   |
-LL | union UI3<T: Iterator<Item: 'static, Item: 'static>> {
-   |                       -------------  ^^^^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:88:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:95:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:102:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:108:32
-   |
-LL | fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:110:32
-   |
-LL | fn FI2<T: Iterator<Item: Copy, Item: Copy>>() {}
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:112:35
-   |
-LL | fn FI3<T: Iterator<Item: 'static, Item: 'static>>() {}
-   |                    -------------  ^^^^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:116:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:122:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:128:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:133:42
-   |
-LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:139:42
-   |
-LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:145:45
-   |
-LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
-   |                              -------------  ^^^^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:151:40
-   |
-LL | fn FAPIT1(_: impl Iterator<Item: Copy, Item: Send>) {}
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:153:40
-   |
-LL | fn FAPIT2(_: impl Iterator<Item: Copy, Item: Copy>) {}
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:155:43
-   |
-LL | fn FAPIT3(_: impl Iterator<Item: 'static, Item: 'static>) {}
-   |                            -------------  ^^^^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:158:35
-   |
-LL | type TAI1<T: Iterator<Item: Copy, Item: Send>> = T;
-   |                       ----------  ^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:160:35
-   |
-LL | type TAI2<T: Iterator<Item: Copy, Item: Copy>> = T;
-   |                       ----------  ^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:162:38
-   |
-LL | type TAI3<T: Iterator<Item: 'static, Item: 'static>> = T;
-   |                       -------------  ^^^^^^^^^^^^^ re-bound here
-   |                       |
-   |                       `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:166:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:171:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:176:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:180:36
-   |
-LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:183:36
-   |
-LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:186:39
-   |
-LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
-   |                        -------------  ^^^^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:202:36
-   |
-LL | trait TRI1<T: Iterator<Item: Copy, Item: Send>> {}
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:204:36
-   |
-LL | trait TRI2<T: Iterator<Item: Copy, Item: Copy>> {}
-   |                        ----------  ^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:206:39
-   |
-LL | trait TRI3<T: Iterator<Item: 'static, Item: 'static>> {}
-   |                        -------------  ^^^^^^^^^^^^^ re-bound here
-   |                        |
-   |                        `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:208:34
-   |
-LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:208:34
-   |
-LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:208:34
-   |
-LL | trait TRS1: Iterator<Item: Copy, Item: Send> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:212:34
-   |
-LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:212:34
-   |
-LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:212:34
-   |
-LL | trait TRS2: Iterator<Item: Copy, Item: Copy> {}
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:216:37
-   |
-LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:216:37
-   |
-LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:216:37
-   |
-LL | trait TRS3: Iterator<Item: 'static, Item: 'static> {}
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:222:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Send>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:228:29
-   |
-LL |     T: Iterator<Item: Copy, Item: Copy>,
-   |                 ----------  ^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:234:32
-   |
-LL |     T: Iterator<Item: 'static, Item: 'static>,
-   |                 -------------  ^^^^^^^^^^^^^ re-bound here
-   |                 |
-   |                 `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:240:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Send>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:240:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Send>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:240:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Send>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:248:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Copy>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:248:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Copy>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:248:32
-   |
-LL |     Self: Iterator<Item: Copy, Item: Copy>,
-   |                    ----------  ^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:256:35
-   |
-LL |     Self: Iterator<Item: 'static, Item: 'static>,
-   |                    -------------  ^^^^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:256:35
-   |
-LL |     Self: Iterator<Item: 'static, Item: 'static>,
-   |                    -------------  ^^^^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:256:35
-   |
-LL |     Self: Iterator<Item: 'static, Item: 'static>,
-   |                    -------------  ^^^^^^^^^^^^^ re-bound here
-   |                    |
-   |                    `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:263:34
-   |
-LL |     type A: Iterator<Item: Copy, Item: Send>;
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:263:34
-   |
-LL |     type A: Iterator<Item: Copy, Item: Send>;
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:268:34
-   |
-LL |     type A: Iterator<Item: Copy, Item: Copy>;
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:268:34
-   |
-LL |     type A: Iterator<Item: Copy, Item: Copy>;
-   |                      ----------  ^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:273:37
-   |
-LL |     type A: Iterator<Item: 'static, Item: 'static>;
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:273:37
-   |
-LL |     type A: Iterator<Item: 'static, Item: 'static>;
-   |                      -------------  ^^^^^^^^^^^^^ re-bound here
-   |                      |
-   |                      `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:133:42
-   |
-LL | fn FRPIT1() -> impl Iterator<Item: Copy, Item: Send> {
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:136:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:139:42
-   |
-LL | fn FRPIT2() -> impl Iterator<Item: Copy, Item: Copy> {
-   |                              ----------  ^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:142:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:145:45
-   |
-LL | fn FRPIT3() -> impl Iterator<Item: 'static, Item: 'static> {
-   |                              -------------  ^^^^^^^^^^^^^ re-bound here
-   |                              |
-   |                              `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0282]: type annotations needed
-  --> $DIR/duplicate.rs:148:5
-   |
-LL |     iter::empty()
-   |     ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `empty`
-   |
-help: consider specifying the generic argument
-   |
-LL |     iter::empty::<T>()
-   |                +++++
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:180:51
-   |
-LL | type ETAI1<T: Iterator<Item: Copy, Item: Send>> = impl Copy;
-   |                                                   ^^^^^^^^^
-   |
-   = note: `ETAI1` must be used in combination with a concrete type within the same crate
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:183:51
-   |
-LL | type ETAI2<T: Iterator<Item: Copy, Item: Copy>> = impl Copy;
-   |                                                   ^^^^^^^^^
-   |
-   = note: `ETAI2` must be used in combination with a concrete type within the same crate
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:186:57
-   |
-LL | type ETAI3<T: Iterator<Item: 'static, Item: 'static>> = impl Copy;
-   |                                                         ^^^^^^^^^
-   |
-   = note: `ETAI3` must be used in combination with a concrete type within the same crate
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:189:14
-   |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `ETAI4` must be used in combination with a concrete type within the same crate
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:189:40
-   |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:189:40
-   |
-LL | type ETAI4 = impl Iterator<Item: Copy, Item: Send>;
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:193:14
-   |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `ETAI5` must be used in combination with a concrete type within the same crate
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:193:40
-   |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:193:40
-   |
-LL | type ETAI5 = impl Iterator<Item: Copy, Item: Copy>;
-   |                            ----------  ^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: unconstrained opaque type
-  --> $DIR/duplicate.rs:197:14
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `ETAI6` must be used in combination with a concrete type within the same crate
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:197:43
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |                            -------------  ^^^^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/duplicate.rs:197:43
-   |
-LL | type ETAI6 = impl Iterator<Item: 'static, Item: 'static>;
-   |                            -------------  ^^^^^^^^^^^^^ re-bound here
-   |                            |
-   |                            `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 87 previous errors
-
-Some errors have detailed explanations: E0282, E0719.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
index 71a4a2610aa..e96a2446b6c 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
+++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr
@@ -1,4 +1,4 @@
-error: conflicting associated type bounds for `Item` when expanding trait alias
+error: conflicting associated type bounds for `Item`
   --> $DIR/associated-types-overridden-binding-2.rs:6:13
    |
 LL | trait I32Iterator = Iterator<Item = i32>;
diff --git a/tests/ui/associated-types/associated-types-overridden-binding.stderr b/tests/ui/associated-types/associated-types-overridden-binding.stderr
index 3b20015dfca..08ab9b63ee9 100644
--- a/tests/ui/associated-types/associated-types-overridden-binding.stderr
+++ b/tests/ui/associated-types/associated-types-overridden-binding.stderr
@@ -22,7 +22,7 @@ note: required by a bound in `I32Iterator`
 LL | trait I32Iterator = Iterator<Item = i32>;
    |                              ^^^^^^^^^^ required by this bound in `I32Iterator`
 
-error: conflicting associated type bounds for `Item` when expanding trait alias
+error: conflicting associated type bounds for `Item`
   --> $DIR/associated-types-overridden-binding.rs:10:13
    |
 LL | trait I32Iterator = Iterator<Item = i32>;
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr
index 486e5f94165..f3938ff606f 100644
--- a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.stderr
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.current.stderr
@@ -1,5 +1,5 @@
-error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:43:45: 43:67}>`
-  --> $DIR/post-mono-higher-ranked-hang.rs:43:21
+error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:47:45: 47:67}>`
+  --> $DIR/post-mono-higher-ranked-hang.rs:47:21
    |
 LL | /                     self.perm_pairs(l, &mut async move |left_pair| {
 LL | |
@@ -8,7 +8,7 @@ LL | |                     })
    | |______________________^
    |
 note: `ToChain::<'env, 'db>::perm_pairs` defined here
-  --> $DIR/post-mono-higher-ranked-hang.rs:34:5
+  --> $DIR/post-mono-higher-ranked-hang.rs:38:5
    |
 LL | /     fn perm_pairs<'l>(
 LL | |         &'l self,
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr
new file mode 100644
index 00000000000..f3938ff606f
--- /dev/null
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.next.stderr
@@ -0,0 +1,21 @@
+error: reached the recursion limit while instantiating `ToChain::<'_, '_>::perm_pairs::<{async closure@$DIR/post-mono-higher-ranked-hang.rs:47:45: 47:67}>`
+  --> $DIR/post-mono-higher-ranked-hang.rs:47:21
+   |
+LL | /                     self.perm_pairs(l, &mut async move |left_pair| {
+LL | |
+LL | |                         self.perm_pairs(r, yield_chain).await
+LL | |                     })
+   | |______________________^
+   |
+note: `ToChain::<'env, 'db>::perm_pairs` defined here
+  --> $DIR/post-mono-higher-ranked-hang.rs:38:5
+   |
+LL | /     fn perm_pairs<'l>(
+LL | |         &'l self,
+LL | |         perm: &'l SymPerm<'db>,
+LL | |         yield_chain: &'l mut impl AsyncFnMut(&SymPerm<'db>),
+LL | |     ) -> Pin<Box<dyn std::future::Future<Output = ()> + 'l>> {
+   | |____________________________________________________________^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs
index f6ebf787f81..55d7cc30ec9 100644
--- a/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs
+++ b/tests/ui/async-await/async-closures/post-mono-higher-ranked-hang.rs
@@ -2,6 +2,10 @@
 //@ aux-build:block-on.rs
 //@ edition:2021
 
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 // Regression test for <https://github.com/rust-lang/rust/issues/135780>.
 
 extern crate block_on;
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
index 894d1327da7..c0181d96053 100644
--- a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs
@@ -1,7 +1,7 @@
 #[unsafe(unsafe(no_mangle))]
 //~^ ERROR expected identifier, found keyword `unsafe`
 //~| ERROR cannot find attribute `r#unsafe` in this scope
-//~| ERROR `r#unsafe` is not an unsafe attribute
+//~| ERROR unnecessary `unsafe`
 fn a() {}
 
 fn main() {}
diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
index 0825cf79408..846800daa54 100644
--- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr
@@ -9,13 +9,11 @@ help: escape `unsafe` to use it as an identifier
 LL | #[unsafe(r#unsafe(no_mangle))]
    |          ++
 
-error: `r#unsafe` is not an unsafe attribute
+error: unnecessary `unsafe` on safe attribute
   --> $DIR/double-unsafe-attributes.rs:1:3
    |
 LL | #[unsafe(unsafe(no_mangle))]
-   |   ^^^^^^ this is not an unsafe attribute
-   |
-   = note: extraneous unsafe is not allowed in attributes
+   |   ^^^^^^
 
 error: cannot find attribute `r#unsafe` in this scope
   --> $DIR/double-unsafe-attributes.rs:1:10
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
index 0f241cc439f..d9054248a29 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs
@@ -1,4 +1,4 @@
-#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute
+#[unsafe(diagnostic::on_unimplemented( //~ ERROR: unnecessary `unsafe`
     message = "testing",
 ))]
 trait Foo {}
diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
index 3bc291db5ac..a7662f5ee6c 100644
--- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
+++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr
@@ -1,10 +1,8 @@
-error: `diagnostic::on_unimplemented` is not an unsafe attribute
+error: unnecessary `unsafe` on safe attribute
   --> $DIR/unsafe-safe-attribute_diagnostic.rs:1:3
    |
 LL | #[unsafe(diagnostic::on_unimplemented(
-   |   ^^^^^^ this is not an unsafe attribute
-   |
-   = note: extraneous unsafe is not allowed in attributes
+   |   ^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/closures/impl-closure-147146.rs b/tests/ui/closures/impl-closure-147146.rs
new file mode 100644
index 00000000000..b709e577354
--- /dev/null
+++ b/tests/ui/closures/impl-closure-147146.rs
@@ -0,0 +1,7 @@
+impl typeof(|| {}) {}
+//~^ ERROR `typeof` is a reserved keyword but unimplemented
+
+unsafe impl Send for typeof(|| {}) {}
+//~^ ERROR `typeof` is a reserved keyword but unimplemented
+
+fn main() {}
diff --git a/tests/ui/closures/impl-closure-147146.stderr b/tests/ui/closures/impl-closure-147146.stderr
new file mode 100644
index 00000000000..6da16b5d450
--- /dev/null
+++ b/tests/ui/closures/impl-closure-147146.stderr
@@ -0,0 +1,15 @@
+error[E0516]: `typeof` is a reserved keyword but unimplemented
+  --> $DIR/impl-closure-147146.rs:1:6
+   |
+LL | impl typeof(|| {}) {}
+   |      ^^^^^^^^^^^^^ reserved keyword
+
+error[E0516]: `typeof` is a reserved keyword but unimplemented
+  --> $DIR/impl-closure-147146.rs:4:22
+   |
+LL | unsafe impl Send for typeof(|| {}) {}
+   |                      ^^^^^^^^^^^^^ reserved keyword
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0516`.
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs
index 5fa5b74c0c0..0a0dca804ef 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.rs
@@ -1,5 +1,6 @@
 //@ add-core-stubs
-//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Cincremental=true
+//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
+//@ incremental (required to trigger the bug)
 //@ needs-llvm-components: arm
 #![feature(abi_cmse_nonsecure_call, no_core)]
 #![no_core]
@@ -8,7 +9,7 @@ extern crate minicore;
 use minicore::*;
 
 // A regression test for https://github.com/rust-lang/rust/issues/131639.
-// NOTE: -Cincremental=true was required for triggering the bug.
+// NOTE: `-Cincremental` was required for triggering the bug.
 
 fn foo() {
     id::<extern "cmse-nonsecure-call" fn(&'a ())>(PhantomData);
diff --git a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr
index 4aca17e7354..7300bdb72cd 100644
--- a/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr
+++ b/tests/ui/cmse-nonsecure/cmse-nonsecure-call/undeclared-lifetime.stderr
@@ -1,5 +1,5 @@
 error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/undeclared-lifetime.rs:14:43
+  --> $DIR/undeclared-lifetime.rs:15:43
    |
 LL |     id::<extern "cmse-nonsecure-call" fn(&'a ())>(PhantomData);
    |                                           ^^ undeclared lifetime
diff --git a/tests/ui/compiletest-self-test/compile-flags-incremental.rs b/tests/ui/compiletest-self-test/compile-flags-incremental.rs
new file mode 100644
index 00000000000..62a1ad84d8f
--- /dev/null
+++ b/tests/ui/compiletest-self-test/compile-flags-incremental.rs
@@ -0,0 +1,17 @@
+//@ revisions: good bad bad-space
+//@ check-pass
+
+//@[bad] compile-flags: -Cincremental=true
+//@[bad] should-fail
+
+//@[bad-space] compile-flags:  -C  incremental=dir
+//@[bad-space] should-fail
+
+fn main() {}
+
+// Tests should not try to manually enable incremental compilation with
+// `-Cincremental`, because that typically results in stray directories being
+// created in the repository root.
+//
+// Instead, use the `//@ incremental` directive, which instructs compiletest
+// to handle the details of passing `-Cincremental` with a fresh directory.
diff --git a/tests/ui/coroutine/handle_opaques_before_coroutines.rs b/tests/ui/coroutine/handle_opaques_before_coroutines.rs
new file mode 100644
index 00000000000..2771c77429c
--- /dev/null
+++ b/tests/ui/coroutine/handle_opaques_before_coroutines.rs
@@ -0,0 +1,15 @@
+// test for https://github.com/rust-lang/trait-system-refactor-initiative/issues/239
+//@edition: 2024
+//@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+fn foo<'a>() -> impl Send {
+    if false {
+        foo();
+    }
+    async {}
+}
+
+fn main() {}
diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
index c74cb89f85c..286d6021396 100644
--- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
+++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
@@ -32,10 +32,10 @@ help: try adding parentheses to match on a tuple...
    |
 LL |         (Nucleotide::Adenine, Nucleotide::Cytosine, _) => true
    |         +                                            +
-help: ...or a vertical bar to match on multiple alternatives
+help: ...or a vertical bar to match on alternatives
    |
 LL -         Nucleotide::Adenine, Nucleotide::Cytosine, _ => true
-LL +         Nucleotide::Adenine | Nucleotide::Cytosine | _ => true
+LL +         Nucleotide::Adenine | Nucleotide::Cytosine, _ => true
    |
 
 error: unexpected `,` in pattern
diff --git a/tests/ui/error-codes/E0719.rs b/tests/ui/error-codes/E0719.rs
index 0ea6d19000b..d7b4b876d1b 100644
--- a/tests/ui/error-codes/E0719.rs
+++ b/tests/ui/error-codes/E0719.rs
@@ -1,8 +1,3 @@
-trait Foo: Iterator<Item = i32, Item = i32> {}
-//~^ ERROR is already specified
-//~| ERROR is already specified
-//~| ERROR is already specified
-
 type Unit = ();
 
 fn test() -> Box<dyn Iterator<Item = (), Item = Unit>> {
diff --git a/tests/ui/error-codes/E0719.stderr b/tests/ui/error-codes/E0719.stderr
index 7e8329db1f4..f4817568924 100644
--- a/tests/ui/error-codes/E0719.stderr
+++ b/tests/ui/error-codes/E0719.stderr
@@ -1,33 +1,5 @@
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/E0719.rs:1:33
-   |
-LL | trait Foo: Iterator<Item = i32, Item = i32> {}
-   |                     ----------  ^^^^^^^^^^ re-bound here
-   |                     |
-   |                     `Item` bound here first
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/E0719.rs:1:33
-   |
-LL | trait Foo: Iterator<Item = i32, Item = i32> {}
-   |                     ----------  ^^^^^^^^^^ re-bound here
-   |                     |
-   |                     `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/E0719.rs:1:33
-   |
-LL | trait Foo: Iterator<Item = i32, Item = i32> {}
-   |                     ----------  ^^^^^^^^^^ re-bound here
-   |                     |
-   |                     `Item` bound here first
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/E0719.rs:8:42
+  --> $DIR/E0719.rs:3:42
    |
 LL | fn test() -> Box<dyn Iterator<Item = (), Item = Unit>> {
    |                               ---------  ^^^^^^^^^^^ re-bound here
@@ -35,13 +7,13 @@ LL | fn test() -> Box<dyn Iterator<Item = (), Item = Unit>> {
    |                               `Item` bound here first
 
 error[E0719]: the value of the associated type `Item` in trait `Iterator` is already specified
-  --> $DIR/E0719.rs:14:38
+  --> $DIR/E0719.rs:9:38
    |
 LL |     let _: &dyn Iterator<Item = i32, Item = i32>;
    |                          ----------  ^^^^^^^^^^ re-bound here
    |                          |
    |                          `Item` bound here first
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0719`.
diff --git a/tests/ui/errors/auxiliary/remapped_dep.rs b/tests/ui/errors/auxiliary/remapped_dep.rs
index 36d4699a306..997118f822c 100644
--- a/tests/ui/errors/auxiliary/remapped_dep.rs
+++ b/tests/ui/errors/auxiliary/remapped_dep.rs
@@ -1,4 +1,4 @@
 //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
-// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
+// Manually remap, so the remapped path remains in .stderr file.
 
 pub struct SomeStruct {} // This line should be show as part of the error.
diff --git a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr
index b4f83f6bfc0..b2651f3e03a 100644
--- a/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr
+++ b/tests/ui/errors/remap-path-prefix-reverse.local-self.stderr
@@ -1,5 +1,5 @@
 error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
-  --> $DIR/remap-path-prefix-reverse.rs:16:13
+  --> $DIR/remap-path-prefix-reverse.rs:15:13
    |
 LL |     let _ = remapped_dep::SomeStruct;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
diff --git a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr
index b4f83f6bfc0..b2651f3e03a 100644
--- a/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr
+++ b/tests/ui/errors/remap-path-prefix-reverse.remapped-self.stderr
@@ -1,5 +1,5 @@
 error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
-  --> $DIR/remap-path-prefix-reverse.rs:16:13
+  --> $DIR/remap-path-prefix-reverse.rs:15:13
    |
 LL |     let _ = remapped_dep::SomeStruct;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
diff --git a/tests/ui/errors/remap-path-prefix-reverse.rs b/tests/ui/errors/remap-path-prefix-reverse.rs
index 28fdabb8f4d..562e44690f7 100644
--- a/tests/ui/errors/remap-path-prefix-reverse.rs
+++ b/tests/ui/errors/remap-path-prefix-reverse.rs
@@ -2,7 +2,6 @@
 //@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
 
 //@ revisions: local-self remapped-self
-// [local-self] no-remap-src-base: The hack should work regardless of remapping.
 //@ [remapped-self] remap-src-base
 
 // Verify that the expected source code is shown.
diff --git a/tests/ui/errors/remap-path-prefix.rs b/tests/ui/errors/remap-path-prefix.rs
index 7e38e16280f..de18aa8cc20 100644
--- a/tests/ui/errors/remap-path-prefix.rs
+++ b/tests/ui/errors/remap-path-prefix.rs
@@ -2,7 +2,7 @@
 //@ compile-flags: --remap-path-prefix={{src-base}}=remapped
 //@ [with-diagnostic-scope]compile-flags: -Zremap-path-scope=diagnostics
 //@ [without-diagnostic-scope]compile-flags: -Zremap-path-scope=object
-// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
+// Manually remap, so the remapped path remains in .stderr file.
 
 // The remapped paths are not normalized by compiletest.
 //@ normalize-stderr: "\\(errors)" -> "/$1"
diff --git a/tests/ui/extern/extern-types-field-offset.rs b/tests/ui/extern/extern-types-field-offset.rs
index 7a5f36da209..470ae07a0b5 100644
--- a/tests/ui/extern/extern-types-field-offset.rs
+++ b/tests/ui/extern/extern-types-field-offset.rs
@@ -23,12 +23,17 @@ fn main() {
     let x: &Newtype = unsafe { &*(&buf as *const _ as *const Newtype) };
     // Projecting to the newtype works, because it is always at offset 0.
     let field = &x.0;
+    // Avoid being eliminated by DSE.
+    std::hint::black_box(field);
 
     let x: &S = unsafe { &*(&buf as *const _ as *const S) };
     // Accessing sized fields is perfectly fine, even at non-zero offsets.
     let field = &x.i;
+    std::hint::black_box(field);
     let field = &x.j;
+    std::hint::black_box(field);
     // This needs to compute the field offset, but we don't know the type's alignment,
     // so this panics.
     let field = &x.a;
+    std::hint::black_box(field);
 }
diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.stderr b/tests/ui/feature-gates/feature-gate-never_patterns.stderr
index 473e263c796..e655209924a 100644
--- a/tests/ui/feature-gates/feature-gate-never_patterns.stderr
+++ b/tests/ui/feature-gates/feature-gate-never_patterns.stderr
@@ -8,7 +8,7 @@ help: try adding parentheses to match on a tuple...
    |
 LL |         (Some(_),)
    |         +        +
-help: ...or a vertical bar to match on multiple alternatives
+help: ...or a vertical bar to match on alternatives
    |
 LL -         Some(_),
 LL +         Some(_) |
diff --git a/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs
new file mode 100644
index 00000000000..29d4facffce
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-static_align-thread_local.rs
@@ -0,0 +1,11 @@
+// The feature gate error may be emitted twice, but only on certain targets
+//@ dont-require-annotations: ERROR
+//@ dont-check-compiler-stderr
+
+#![crate_type = "lib"]
+
+thread_local! {
+    //~^ ERROR the `#[rustc_align_static]` attribute is an experimental feature
+    #[rustc_align_static(16)]
+    static THREAD_LOCAL: u16 = 0;
+}
diff --git a/tests/ui/force-inlining/inherent.rs b/tests/ui/force-inlining/inherent.rs
new file mode 100644
index 00000000000..25c76eaf37a
--- /dev/null
+++ b/tests/ui/force-inlining/inherent.rs
@@ -0,0 +1,21 @@
+//@ check-fail
+#![feature(rustc_attrs)]
+
+struct Foo;
+
+impl Foo {
+    #[rustc_force_inline]
+    //~^ ERROR: `Foo::bar` is incompatible with `#[rustc_force_inline]`
+    #[rustc_no_mir_inline]
+    fn bar() {}
+}
+
+fn bar_caller() {
+    unsafe {
+        Foo::bar();
+    }
+}
+
+fn main() {
+    bar_caller();
+}
diff --git a/tests/ui/force-inlining/inherent.stderr b/tests/ui/force-inlining/inherent.stderr
new file mode 100644
index 00000000000..1ffc78848fe
--- /dev/null
+++ b/tests/ui/force-inlining/inherent.stderr
@@ -0,0 +1,13 @@
+error: `Foo::bar` is incompatible with `#[rustc_force_inline]`
+  --> $DIR/inherent.rs:7:5
+   |
+LL |     #[rustc_force_inline]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     fn bar() {}
+   |     -------- `Foo::bar` defined here
+   |
+   = note: incompatible due to: #[rustc_no_mir_inline]
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs
index 6047739992f..eaacbb50209 100644
--- a/tests/ui/force-inlining/invalid.rs
+++ b/tests/ui/force-inlining/invalid.rs
@@ -114,7 +114,6 @@ trait FooQux = FooBaz;
 //~^ ERROR attribute cannot be used on
 impl<T> Bar<T> {
     #[rustc_force_inline]
-//~^ ERROR attribute cannot be used on
     fn foo() {}
 }
 
diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr
index 299a3ed4a46..df3b646b6ce 100644
--- a/tests/ui/force-inlining/invalid.stderr
+++ b/tests/ui/force-inlining/invalid.stderr
@@ -1,5 +1,5 @@
 error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/invalid.rs:132:11
+  --> $DIR/invalid.rs:131:11
    |
 LL | fn barqux(#[rustc_force_inline] _x: u32) {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ error: `#[rustc_force_inline]` attribute cannot be used on foreign functions
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_force_inline]` can only be applied to functions
+   = help: `#[rustc_force_inline]` can be applied to functions and inherent methods
 
 error: `#[rustc_force_inline]` attribute cannot be used on type aliases
   --> $DIR/invalid.rs:66:1
@@ -222,7 +222,7 @@ error: `#[rustc_force_inline]` attribute cannot be used on provided trait method
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_force_inline]` can only be applied to functions
+   = help: `#[rustc_force_inline]` can be applied to functions and inherent methods
 
 error: `#[rustc_force_inline]` attribute cannot be used on trait aliases
   --> $DIR/invalid.rs:109:1
@@ -240,16 +240,8 @@ LL | #[rustc_force_inline]
    |
    = help: `#[rustc_force_inline]` can only be applied to functions
 
-error: `#[rustc_force_inline]` attribute cannot be used on inherent methods
-  --> $DIR/invalid.rs:116:5
-   |
-LL |     #[rustc_force_inline]
-   |     ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: `#[rustc_force_inline]` can only be applied to functions
-
 error: `#[rustc_force_inline]` attribute cannot be used on trait impl blocks
-  --> $DIR/invalid.rs:121:1
+  --> $DIR/invalid.rs:120:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -257,7 +249,7 @@ LL | #[rustc_force_inline]
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: `#[rustc_force_inline]` attribute cannot be used on macro defs
-  --> $DIR/invalid.rs:128:1
+  --> $DIR/invalid.rs:127:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -265,7 +257,7 @@ LL | #[rustc_force_inline]
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: `#[rustc_force_inline]` attribute cannot be used on function params
-  --> $DIR/invalid.rs:132:11
+  --> $DIR/invalid.rs:131:11
    |
 LL | fn barqux(#[rustc_force_inline] _x: u32) {}
    |           ^^^^^^^^^^^^^^^^^^^^^
@@ -273,15 +265,15 @@ LL | fn barqux(#[rustc_force_inline] _x: u32) {}
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: `#[rustc_force_inline]` attribute cannot be used on closures
-  --> $DIR/invalid.rs:149:14
+  --> $DIR/invalid.rs:148:14
    |
 LL |     let _x = #[rustc_force_inline] || { };
    |              ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: `#[rustc_force_inline]` can only be applied to functions
+   = help: `#[rustc_force_inline]` can be applied to functions and inherent methods
 
 error: `#[rustc_force_inline]` attribute cannot be used on expressions
-  --> $DIR/invalid.rs:151:14
+  --> $DIR/invalid.rs:150:14
    |
 LL |     let _y = #[rustc_force_inline] 3 + 4;
    |              ^^^^^^^^^^^^^^^^^^^^^
@@ -289,7 +281,7 @@ LL |     let _y = #[rustc_force_inline] 3 + 4;
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: `#[rustc_force_inline]` attribute cannot be used on statements
-  --> $DIR/invalid.rs:153:5
+  --> $DIR/invalid.rs:152:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -297,7 +289,7 @@ LL |     #[rustc_force_inline]
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: `#[rustc_force_inline]` attribute cannot be used on match arms
-  --> $DIR/invalid.rs:158:9
+  --> $DIR/invalid.rs:157:9
    |
 LL |         #[rustc_force_inline]
    |         ^^^^^^^^^^^^^^^^^^^^^
@@ -305,7 +297,7 @@ LL |         #[rustc_force_inline]
    = help: `#[rustc_force_inline]` can only be applied to functions
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:136:1
+  --> $DIR/invalid.rs:135:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -314,7 +306,7 @@ LL | async fn async_foo() {}
    | -------------------- `async`, `gen` or `async gen` function
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:140:1
+  --> $DIR/invalid.rs:139:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -323,7 +315,7 @@ LL | gen fn gen_foo() {}
    | ---------------- `async`, `gen` or `async gen` function
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:144:1
+  --> $DIR/invalid.rs:143:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -331,7 +323,7 @@ LL |
 LL | async gen fn async_gen_foo() {}
    | ---------------------------- `async`, `gen` or `async gen` function
 
-error: aborting due to 37 previous errors
+error: aborting due to 36 previous errors
 
 Some errors have detailed explanations: E0539, E0805.
 For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
index a26c617dc93..f8f64dcc545 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
@@ -37,7 +37,7 @@ error: higher-ranked lifetime error
 LL |     v.t(|| {});
    |         ^^^^^
    |
-   = note: could not prove `for<'a> &'a V: 'b`
+   = note: could not prove `for<'a> &'a V: '_`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr
index 9e0d7e4b7be..a04c6d770d7 100644
--- a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     || {};
    |     ^^^^^
    |
-   = note: could not prove `for<'a> &'a (): 'b`
+   = note: could not prove `for<'a> &'a (): '_`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs
new file mode 100644
index 00000000000..61a8d8f0054
--- /dev/null
+++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-fail.rs
@@ -0,0 +1,16 @@
+//@ edition:2018
+//@ proc-macro: same-res-ambigious-extern-macro.rs
+
+macro_rules! globbing{
+    () => {
+        pub use same_res_ambigious_extern_macro::*;
+    }
+}
+
+#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility
+extern crate same_res_ambigious_extern_macro;
+globbing! {} // this imports the same `RustEmbed` macro with `pub` visibility
+
+pub trait RustEmbed {}
+
+pub use RustEmbed as Embed;
diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs
new file mode 100644
index 00000000000..4e9b8427092
--- /dev/null
+++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern-macro.rs
@@ -0,0 +1,8 @@
+//@ edition: 2018
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(RustEmbed)]
+pub fn rust_embed_derive(_input: TokenStream) -> TokenStream {
+    TokenStream::new()
+}
diff --git a/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs
new file mode 100644
index 00000000000..5269dcd0b17
--- /dev/null
+++ b/tests/ui/imports/auxiliary/same-res-ambigious-extern.rs
@@ -0,0 +1,11 @@
+//@ edition:2018
+//@ proc-macro: same-res-ambigious-extern-macro.rs
+
+#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility
+extern crate same_res_ambigious_extern_macro;
+// this imports the same `RustEmbed` macro with `pub` visibility
+pub use same_res_ambigious_extern_macro::*;
+
+pub trait RustEmbed {}
+
+pub use RustEmbed as Embed;
diff --git a/tests/ui/imports/same-res-ambigious.fail.stderr b/tests/ui/imports/same-res-ambigious.fail.stderr
new file mode 100644
index 00000000000..dfd7c5a5f94
--- /dev/null
+++ b/tests/ui/imports/same-res-ambigious.fail.stderr
@@ -0,0 +1,20 @@
+error[E0603]: derive macro `Embed` is private
+  --> $DIR/same-res-ambigious.rs:8:28
+   |
+LL | #[derive(ambigious_extern::Embed)]
+   |                            ^^^^^ private derive macro
+   |
+note: the derive macro `Embed` is defined here
+  --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9
+   |
+LL | pub use RustEmbed as Embed;
+   |         ^^^^^^^^^
+help: import `Embed` directly
+   |
+LL - #[derive(ambigious_extern::Embed)]
+LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)]
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/tests/ui/imports/same-res-ambigious.nightly-fail.stderr b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr
new file mode 100644
index 00000000000..dfd7c5a5f94
--- /dev/null
+++ b/tests/ui/imports/same-res-ambigious.nightly-fail.stderr
@@ -0,0 +1,20 @@
+error[E0603]: derive macro `Embed` is private
+  --> $DIR/same-res-ambigious.rs:8:28
+   |
+LL | #[derive(ambigious_extern::Embed)]
+   |                            ^^^^^ private derive macro
+   |
+note: the derive macro `Embed` is defined here
+  --> $DIR/auxiliary/same-res-ambigious-extern-fail.rs:16:9
+   |
+LL | pub use RustEmbed as Embed;
+   |         ^^^^^^^^^
+help: import `Embed` directly
+   |
+LL - #[derive(ambigious_extern::Embed)]
+LL + #[derive(same_res_ambigious_extern_macro::RustEmbed)]
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/tests/ui/imports/same-res-ambigious.rs b/tests/ui/imports/same-res-ambigious.rs
new file mode 100644
index 00000000000..b5c13a15b7c
--- /dev/null
+++ b/tests/ui/imports/same-res-ambigious.rs
@@ -0,0 +1,11 @@
+//@ edition: 2018
+//@ revisions: fail pass
+//@[pass] check-pass
+//@[pass] aux-crate: ambigious_extern=same-res-ambigious-extern.rs
+//@[fail] aux-crate: ambigious_extern=same-res-ambigious-extern-fail.rs
+// see https://github.com/rust-lang/rust/pull/147196
+
+#[derive(ambigious_extern::Embed)] //[fail]~ ERROR: derive macro `Embed` is private
+struct Foo{}
+
+fn main(){}
diff --git a/tests/ui/indexing/ambiguity-after-deref-step.rs b/tests/ui/indexing/ambiguity-after-deref-step.rs
new file mode 100644
index 00000000000..2dd95eed097
--- /dev/null
+++ b/tests/ui/indexing/ambiguity-after-deref-step.rs
@@ -0,0 +1,9 @@
+// Regression test making sure that indexing fails with an ambiguity
+// error if one of the deref-steps encounters an inference variable.
+
+fn main() {
+    let x = &Default::default();
+    //~^ ERROR type annotations needed for `&_`
+    x[1];
+    let _: &Vec<()> = x;
+}
diff --git a/tests/ui/indexing/ambiguity-after-deref-step.stderr b/tests/ui/indexing/ambiguity-after-deref-step.stderr
new file mode 100644
index 00000000000..c7ddd4731c7
--- /dev/null
+++ b/tests/ui/indexing/ambiguity-after-deref-step.stderr
@@ -0,0 +1,17 @@
+error[E0282]: type annotations needed for `&_`
+  --> $DIR/ambiguity-after-deref-step.rs:5:9
+   |
+LL |     let x = &Default::default();
+   |         ^
+LL |
+LL |     x[1];
+   |     - type must be known at this point
+   |
+help: consider giving `x` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let x: &_ = &Default::default();
+   |          ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/indexing/index_message.stderr b/tests/ui/indexing/index_message.stderr
index 6affb1ed962..b6f61379f2a 100644
--- a/tests/ui/indexing/index_message.stderr
+++ b/tests/ui/indexing/index_message.stderr
@@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)`
   --> $DIR/index_message.rs:3:14
    |
 LL |     let _ = z[0];
-   |              ^^^ help: to access tuple elements, use: `.0`
+   |              ^^^ help: to access tuple element `0`, use: `.0`
+   |
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-27842.stderr b/tests/ui/issues/issue-27842.stderr
index b18fe1512b5..f388fdf85cd 100644
--- a/tests/ui/issues/issue-27842.stderr
+++ b/tests/ui/issues/issue-27842.stderr
@@ -2,17 +2,17 @@ error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer
   --> $DIR/issue-27842.rs:4:16
    |
 LL |     let _ = tup[0];
-   |                ^^^ help: to access tuple elements, use: `.0`
+   |                ^^^ help: to access tuple element `0`, use: `.0`
+   |
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error[E0608]: cannot index into a value of type `({integer}, {integer}, {integer})`
   --> $DIR/issue-27842.rs:9:16
    |
 LL |     let _ = tup[i];
-   |                ^-^
-   |                 |
-   |                 cannot access tuple elements at a variable index
+   |                ^^^
    |
-   = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error[E0608]: cannot index into a value of type `({integer},)`
   --> $DIR/issue-27842.rs:14:16
@@ -20,7 +20,7 @@ error[E0608]: cannot index into a value of type `({integer},)`
 LL |     let _ = tup[3];
    |                ^^^
    |
-   = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/lifetimes/re-empty-in-error.stderr b/tests/ui/lifetimes/re-empty-in-error.stderr
index 554bcb5451f..b3b6d3d269c 100644
--- a/tests/ui/lifetimes/re-empty-in-error.stderr
+++ b/tests/ui/lifetimes/re-empty-in-error.stderr
@@ -4,7 +4,7 @@ error: higher-ranked lifetime error
 LL |     foo(&10);
    |     ^^^^^^^^
    |
-   = note: could not prove `for<'b> &'b (): 'a`
+   = note: could not prove `for<'b> &'b (): '_`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/macro-local-data-key-priv.stderr b/tests/ui/macros/macro-local-data-key-priv.stderr
index e93bd11046d..8df1aec140d 100644
--- a/tests/ui/macros/macro-local-data-key-priv.stderr
+++ b/tests/ui/macros/macro-local-data-key-priv.stderr
@@ -9,7 +9,7 @@ note: the constant `baz` is defined here
    |
 LL |     thread_local!(static baz: f64 = 0.0);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_inner` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs
index 81eadb6692f..60290b883cb 100644
--- a/tests/ui/macros/macro-rules-attr-error.rs
+++ b/tests/ui/macros/macro-rules-attr-error.rs
@@ -50,3 +50,22 @@ macro_rules! forward_referenced_attr {
 macro_rules! cyclic_attr {
     attr() {} => {}
 }
+
+macro_rules! attr_with_safety {
+    unsafe attr() { struct RequiresUnsafe; } => {};
+    attr() { struct SafeInvocation; } => {};
+}
+
+#[attr_with_safety]
+struct SafeInvocation;
+
+//~v ERROR: unnecessary `unsafe` on safe attribute invocation
+#[unsafe(attr_with_safety)]
+struct SafeInvocation;
+
+//~v ERROR: unsafe attribute invocation requires `unsafe`
+#[attr_with_safety]
+struct RequiresUnsafe;
+
+#[unsafe(attr_with_safety)]
+struct RequiresUnsafe;
diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr
index 674d35091b6..27527a2da7e 100644
--- a/tests/ui/macros/macro-rules-attr-error.stderr
+++ b/tests/ui/macros/macro-rules-attr-error.stderr
@@ -9,6 +9,18 @@ LL |     #[local_attr]
    |
    = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error: unnecessary `unsafe` on safe attribute invocation
+  --> $DIR/macro-rules-attr-error.rs:63:3
+   |
+LL | #[unsafe(attr_with_safety)]
+   |   ^^^^^^
+
+error: unsafe attribute invocation requires `unsafe`
+  --> $DIR/macro-rules-attr-error.rs:67:1
+   |
+LL | #[attr_with_safety]
+   | ^^^^^^^^^^^^^^^^^^^
+
 error: cannot find macro `local_attr` in this scope
   --> $DIR/macro-rules-attr-error.rs:27:5
    |
@@ -59,5 +71,5 @@ note: a macro with the same name exists, but it appears later
 LL | macro_rules! cyclic_attr {
    |              ^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/methods/overflow-if-subtyping.rs b/tests/ui/methods/overflow-if-subtyping.rs
new file mode 100644
index 00000000000..a97f29f1f6d
--- /dev/null
+++ b/tests/ui/methods/overflow-if-subtyping.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+
+// Regression test for #128887.
+#![allow(unconditional_recursion)]
+trait Mappable<T> {
+    type Output;
+}
+
+trait Bound<T> {}
+// Deleting this impl made it compile on beta
+impl<T> Bound<T> for T {}
+
+trait Generic<M> {}
+
+// Deleting the `: Mappable<T>` already made it error on stable.
+struct IndexWithIter<I, M: Mappable<T>, T>(I, M, T);
+
+impl<I, M, T> IndexWithIter<I, M, T>
+where
+    <M as Mappable<T>>::Output: Bound<T>,
+    // Flipping these where bounds causes this to succeed, even when removing
+    // the where-clause on the struct definition.
+    M: Mappable<T>,
+    I: Generic<M>,
+{
+    fn new(x: I) {
+        IndexWithIter::<_, _, _>::new(x);
+    }
+}
+fn main() {}
diff --git a/tests/ui/nll/user-annotations/dump-fn-method.rs b/tests/ui/nll/user-annotations/dump-fn-method.rs
index 26714b6ffe3..ec349e36839 100644
--- a/tests/ui/nll/user-annotations/dump-fn-method.rs
+++ b/tests/ui/nll/user-annotations/dump-fn-method.rs
@@ -31,7 +31,7 @@ fn main() {
     // Here: we only want the `T` to be given, the rest should be variables.
     //
     // (`T` refers to the declaration of `Bazoom`)
-    let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^0, u32, ^1]
+    let x = <_ as Bazoom<u32>>::method::<_>; //~ ERROR [^c_0, u32, ^c_1]
     x(&22, 44, 66);
 
     // Here: all are given and definitely contain no lifetimes, so we
@@ -48,7 +48,7 @@ fn main() {
     //
     // (`U` refers to the declaration of `Bazoom`)
     let y = 22_u32;
-    y.method::<u32>(44, 66); //~ ERROR [^0, ^1, u32]
+    y.method::<u32>(44, 66); //~ ERROR [^c_0, ^c_1, u32]
 
     // Here: nothing is given, so we don't have any annotation.
     let y = 22_u32;
diff --git a/tests/ui/nll/user-annotations/dump-fn-method.stderr b/tests/ui/nll/user-annotations/dump-fn-method.stderr
index 8e847b464e1..f00fb0013df 100644
--- a/tests/ui/nll/user-annotations/dump-fn-method.stderr
+++ b/tests/ui/nll/user-annotations/dump-fn-method.stderr
@@ -4,7 +4,7 @@ error: user args: UserArgs { args: [&'static u32], user_self_ty: None }
 LL |     let x = foo::<&'static u32>;
    |             ^^^^^^^^^^^^^^^^^^^
 
-error: user args: UserArgs { args: [^0, u32, ^1], user_self_ty: None }
+error: user args: UserArgs { args: [^c_0, u32, ^c_1], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:34:13
    |
 LL |     let x = <_ as Bazoom<u32>>::method::<_>;
@@ -16,7 +16,7 @@ error: user args: UserArgs { args: [u8, &'static u16, u32], user_self_ty: None }
 LL |     let x = <u8 as Bazoom<&'static u16>>::method::<u32>;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: user args: UserArgs { args: [^0, ^1, u32], user_self_ty: None }
+error: user args: UserArgs { args: [^c_0, ^c_1, u32], user_self_ty: None }
   --> $DIR/dump-fn-method.rs:51:5
    |
 LL |     y.method::<u32>(44, 66);
diff --git a/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs b/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs
new file mode 100644
index 00000000000..a29afd68523
--- /dev/null
+++ b/tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs
@@ -0,0 +1,57 @@
+//! Test that with `-C panic=abort` the backtrace is not cut off by default
+//! (i.e. without using `-C force-unwind-tables=yes`) by ensuring that our own
+//! functions are in the backtrace. If we just check one function it might be
+//! the last function, so make sure the backtrace can continue by checking for
+//! two functions. Regression test for
+//! <https://github.com/rust-lang/rust/issues/81902>.
+
+//@ run-pass
+//@ needs-subprocess
+// We want to test if unwind tables are emitted by default. We must make sure
+// to disable debuginfo to test that, because enabling debuginfo also means that
+// unwind tables are emitted, which prevents us from testing what we want.
+// We also need to set opt-level=0 to avoid optimizing away our functions.
+//@ compile-flags: -C panic=abort -C opt-level=0 -C debuginfo=0
+//@ no-prefer-dynamic
+//@ ignore-apple
+//@ ignore-arm-unknown-linux-gnueabihf FIXME(#146996) Try removing this once #146996 has been fixed.
+//@ ignore-msvc Backtraces on Windows requires debuginfo which we can't use here
+
+static FN_1: &str = "this_function_must_be_in_the_backtrace";
+fn this_function_must_be_in_the_backtrace() {
+    and_this_function_too();
+}
+
+static FN_2: &str = "and_this_function_too";
+fn and_this_function_too() {
+    panic!("generate panic backtrace");
+}
+
+fn run_test() {
+    let output = std::process::Command::new(std::env::current_exe().unwrap())
+        .arg("whatever")
+        .env("RUST_BACKTRACE", "full")
+        .output()
+        .unwrap();
+    let backtrace = std::str::from_utf8(&output.stderr).unwrap();
+
+    fn assert(function_name: &str, backtrace: &str) {
+        assert!(
+            backtrace.contains(function_name),
+            "ERROR: no `{}` in stderr! actual stderr: {}",
+            function_name,
+            backtrace
+        );
+    }
+    assert(FN_1, backtrace);
+    assert(FN_2, backtrace);
+}
+
+fn main() {
+    let args: Vec<String> = std::env::args().collect();
+    if args.len() == 1 {
+        run_test();
+    } else {
+        this_function_must_be_in_the_backtrace();
+    }
+}
diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs
index d081c06044f..e1ea38f2795 100644
--- a/tests/ui/parser/issues/issue-87086-colon-path-sep.rs
+++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.rs
@@ -37,10 +37,9 @@ fn g1() {
         //~| HELP: maybe write a path separator here
         _ => {}
     }
-    if let Foo:Bar = f() { //~ WARN: irrefutable `if let` pattern
+    if let Foo:Bar = f() {
     //~^ ERROR: expected one of
     //~| HELP: maybe write a path separator here
-    //~| HELP: consider replacing the `if let` with a `let`
     }
 }
 
diff --git a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
index a9bad96f9af..061586882e0 100644
--- a/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
+++ b/tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
@@ -64,7 +64,7 @@ LL |     if let Foo::Bar = f() {
    |                +
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:49:16
+  --> $DIR/issue-87086-colon-path-sep.rs:48:16
    |
 LL |         ref qux: Foo::Baz => {}
    |                ^ -------- specifying the type of a pattern isn't supported
@@ -77,7 +77,7 @@ LL |         ref qux::Foo::Baz => {}
    |                ~~
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:58:16
+  --> $DIR/issue-87086-colon-path-sep.rs:57:16
    |
 LL |         mut qux: Foo::Baz => {}
    |                ^ -------- specifying the type of a pattern isn't supported
@@ -90,7 +90,7 @@ LL |         mut qux::Foo::Baz => {}
    |                ~~
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:69:12
+  --> $DIR/issue-87086-colon-path-sep.rs:68:12
    |
 LL |         Foo:Bar::Baz => {}
    |            ^-------- specifying the type of a pattern isn't supported
@@ -103,7 +103,7 @@ LL |         Foo::Bar::Baz => {}
    |             +
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:75:12
+  --> $DIR/issue-87086-colon-path-sep.rs:74:12
    |
 LL |         Foo:Bar => {}
    |            ^--- specifying the type of a pattern isn't supported
@@ -115,15 +115,5 @@ help: maybe write a path separator here
 LL |         Foo::Bar => {}
    |             +
 
-warning: irrefutable `if let` pattern
-  --> $DIR/issue-87086-colon-path-sep.rs:40:8
-   |
-LL |     if let Foo:Bar = f() {
-   |        ^^^^^^^^^^^^^^^^^
-   |
-   = note: this pattern will always match, so the `if let` is useless
-   = help: consider replacing the `if let` with a `let`
-   = note: `#[warn(irrefutable_let_patterns)]` on by default
-
-error: aborting due to 9 previous errors; 1 warning emitted
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/parser/macro/bad-macro-definition.rs b/tests/ui/parser/macro/bad-macro-definition.rs
index 3c5c93ea3b3..12df6e64bd2 100644
--- a/tests/ui/parser/macro/bad-macro-definition.rs
+++ b/tests/ui/parser/macro/bad-macro-definition.rs
@@ -20,3 +20,6 @@ macro_rules! e { {} }
 
 macro_rules! f {}
 //~^ ERROR: macros must contain at least one rule
+
+macro_rules! g { unsafe {} => {} }
+//~^ ERROR: `unsafe` is only supported on `attr` rules
diff --git a/tests/ui/parser/macro/bad-macro-definition.stderr b/tests/ui/parser/macro/bad-macro-definition.stderr
index de6d9d6a38b..d15f33f708d 100644
--- a/tests/ui/parser/macro/bad-macro-definition.stderr
+++ b/tests/ui/parser/macro/bad-macro-definition.stderr
@@ -52,5 +52,11 @@ error: macros must contain at least one rule
 LL | macro_rules! f {}
    | ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 9 previous errors
+error: `unsafe` is only supported on `attr` rules
+  --> $DIR/bad-macro-definition.rs:24:18
+   |
+LL | macro_rules! g { unsafe {} => {} }
+   |                  ^^^^^^
+
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/parser/macro/macro-attr-bad.rs b/tests/ui/parser/macro/macro-attr-bad.rs
index 9f50b057a7a..0ac46c8b768 100644
--- a/tests/ui/parser/macro/macro-attr-bad.rs
+++ b/tests/ui/parser/macro/macro-attr-bad.rs
@@ -13,6 +13,12 @@ macro_rules! attr_incomplete_3 { attr() {} }
 macro_rules! attr_incomplete_4 { attr() {} => }
 //~^ ERROR macro definition ended unexpectedly
 
+macro_rules! attr_incomplete_5 { unsafe }
+//~^ ERROR macro definition ended unexpectedly
+
+macro_rules! attr_incomplete_6 { unsafe attr }
+//~^ ERROR macro definition ended unexpectedly
+
 macro_rules! attr_noparens_1 { attr{} {} => {} }
 //~^ ERROR `attr` rule argument matchers require parentheses
 
diff --git a/tests/ui/parser/macro/macro-attr-bad.stderr b/tests/ui/parser/macro/macro-attr-bad.stderr
index bf0ed13cd55..481ef8118ae 100644
--- a/tests/ui/parser/macro/macro-attr-bad.stderr
+++ b/tests/ui/parser/macro/macro-attr-bad.stderr
@@ -22,8 +22,20 @@ error: macro definition ended unexpectedly
 LL | macro_rules! attr_incomplete_4 { attr() {} => }
    |                                              ^ expected right-hand side of macro rule
 
+error: macro definition ended unexpectedly
+  --> $DIR/macro-attr-bad.rs:16:40
+   |
+LL | macro_rules! attr_incomplete_5 { unsafe }
+   |                                        ^ expected `attr`
+
+error: macro definition ended unexpectedly
+  --> $DIR/macro-attr-bad.rs:19:45
+   |
+LL | macro_rules! attr_incomplete_6 { unsafe attr }
+   |                                             ^ expected macro attr args
+
 error: `attr` rule argument matchers require parentheses
-  --> $DIR/macro-attr-bad.rs:16:36
+  --> $DIR/macro-attr-bad.rs:22:36
    |
 LL | macro_rules! attr_noparens_1 { attr{} {} => {} }
    |                                    ^^
@@ -35,7 +47,7 @@ LL + macro_rules! attr_noparens_1 { attr() {} => {} }
    |
 
 error: `attr` rule argument matchers require parentheses
-  --> $DIR/macro-attr-bad.rs:19:36
+  --> $DIR/macro-attr-bad.rs:25:36
    |
 LL | macro_rules! attr_noparens_2 { attr[] {} => {} }
    |                                    ^^
@@ -47,13 +59,13 @@ LL + macro_rules! attr_noparens_2 { attr() {} => {} }
    |
 
 error: invalid macro matcher; matchers must be contained in balanced delimiters
-  --> $DIR/macro-attr-bad.rs:22:37
+  --> $DIR/macro-attr-bad.rs:28:37
    |
 LL | macro_rules! attr_noparens_3 { attr _ {} => {} }
    |                                     ^
 
 error: duplicate matcher binding
-  --> $DIR/macro-attr-bad.rs:25:52
+  --> $DIR/macro-attr-bad.rs:31:52
    |
 LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} }
    |                                           -------- ^^^^^^^^ duplicate binding
@@ -61,7 +73,7 @@ LL | macro_rules! attr_dup_matcher_1 { attr() {$x:ident $x:ident} => {} }
    |                                           previous binding
 
 error: duplicate matcher binding
-  --> $DIR/macro-attr-bad.rs:28:49
+  --> $DIR/macro-attr-bad.rs:34:49
    |
 LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} }
    |                                        -------- ^^^^^^^^ duplicate binding
@@ -69,12 +81,12 @@ LL | macro_rules! attr_dup_matcher_2 { attr($x:ident $x:ident) {} => {} }
    |                                        previous binding
 
 error: duplicate matcher binding
-  --> $DIR/macro-attr-bad.rs:31:51
+  --> $DIR/macro-attr-bad.rs:37:51
    |
 LL | macro_rules! attr_dup_matcher_3 { attr($x:ident) {$x:ident} => {} }
    |                                        --------   ^^^^^^^^ duplicate binding
    |                                        |
    |                                        previous binding
 
-error: aborting due to 10 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/parser/macro/macro-derive-bad.rs b/tests/ui/parser/macro/macro-derive-bad.rs
index 79b9eb8c113..74e7d9acdaf 100644
--- a/tests/ui/parser/macro/macro-derive-bad.rs
+++ b/tests/ui/parser/macro/macro-derive-bad.rs
@@ -41,3 +41,6 @@ macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} }
 //~^ ERROR duplicate matcher binding
 //~| NOTE duplicate binding
 //~| NOTE previous binding
+
+macro_rules! derive_unsafe { unsafe derive() {} => {} }
+//~^ ERROR `unsafe` is only supported on `attr` rules
diff --git a/tests/ui/parser/macro/macro-derive-bad.stderr b/tests/ui/parser/macro/macro-derive-bad.stderr
index ec750c9ac82..c98535f4031 100644
--- a/tests/ui/parser/macro/macro-derive-bad.stderr
+++ b/tests/ui/parser/macro/macro-derive-bad.stderr
@@ -86,5 +86,11 @@ LL | macro_rules! derive_dup_matcher { derive() {$x:ident $x:ident} => {} }
    |                                             |
    |                                             previous binding
 
-error: aborting due to 12 previous errors
+error: `unsafe` is only supported on `attr` rules
+  --> $DIR/macro-derive-bad.rs:45:30
+   |
+LL | macro_rules! derive_unsafe { unsafe derive() {} => {} }
+   |                              ^^^^^^
+
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/parser/match-arm-without-body.rs b/tests/ui/parser/match-arm-without-body.rs
index 4723abff8b6..7fe5b6d2539 100644
--- a/tests/ui/parser/match-arm-without-body.rs
+++ b/tests/ui/parser/match-arm-without-body.rs
@@ -17,13 +17,13 @@ fn main() {
         Some(_),
         //~^ ERROR unexpected `,` in pattern
         //~| HELP try adding parentheses to match on a tuple
-        //~| HELP or a vertical bar to match on multiple alternatives
+        //~| HELP or a vertical bar to match on alternative
     }
     match Some(false) {
         Some(_),
         //~^ ERROR unexpected `,` in pattern
         //~| HELP try adding parentheses to match on a tuple
-        //~| HELP or a vertical bar to match on multiple alternatives
+        //~| HELP or a vertical bar to match on alternative
         _ => {}
     }
     match Some(false) {
diff --git a/tests/ui/parser/match-arm-without-body.stderr b/tests/ui/parser/match-arm-without-body.stderr
index a65875b787a..59a323f2cc1 100644
--- a/tests/ui/parser/match-arm-without-body.stderr
+++ b/tests/ui/parser/match-arm-without-body.stderr
@@ -16,7 +16,7 @@ help: try adding parentheses to match on a tuple...
    |
 LL |         (Some(_),)
    |         +        +
-help: ...or a vertical bar to match on multiple alternatives
+help: ...or a vertical bar to match on alternatives
    |
 LL -         Some(_),
 LL +         Some(_) |
@@ -36,13 +36,10 @@ LL |
 LL |
 LL ~         _) => {}
    |
-help: ...or a vertical bar to match on multiple alternatives
+help: ...or a vertical bar to match on alternatives
    |
-LL ~         Some(_) |
-LL +
-LL +
-LL +
-LL ~         _ => {}
+LL -         Some(_),
+LL +         Some(_) |
    |
 
 error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_`
diff --git a/tests/ui/parser/type-ascription-in-pattern.rs b/tests/ui/parser/type-ascription-in-pattern.rs
index 18d7061d69c..75059d33db6 100644
--- a/tests/ui/parser/type-ascription-in-pattern.rs
+++ b/tests/ui/parser/type-ascription-in-pattern.rs
@@ -1,15 +1,16 @@
 fn foo(x: bool) -> i32 {
-    match x { //~ ERROR struct literals are not allowed here
-        x: i32 => x, //~ ERROR expected
-        true => 42., //~ ERROR expected identifier
-        false => 0.333, //~ ERROR expected identifier
+    match x {
+        x: i32 => x, //~ ERROR: expected
+        //~^ ERROR: mismatched types
+        true => 42.,
+        false => 0.333,
     }
-} //~ ERROR expected one of
+}
 
 fn main() {
     match foo(true) {
-        42: i32 => (), //~ ERROR expected
-        _: f64 => (), //~ ERROR expected
-        x: i32 => (), //~ ERROR expected
+        42: i32 => (), //~ ERROR: expected
+        _: f64 => (), //~ ERROR: expected
+        x: i32 => (), //~ ERROR: expected
     }
 }
diff --git a/tests/ui/parser/type-ascription-in-pattern.stderr b/tests/ui/parser/type-ascription-in-pattern.stderr
index 135879f208b..09190754993 100644
--- a/tests/ui/parser/type-ascription-in-pattern.stderr
+++ b/tests/ui/parser/type-ascription-in-pattern.stderr
@@ -1,64 +1,18 @@
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, `}`, or an operator, found `=>`
-  --> $DIR/type-ascription-in-pattern.rs:3:16
-   |
-LL |     match x {
-   |           - while parsing this struct
-LL |         x: i32 => x,
-   |               -^^ expected one of 8 possible tokens
-   |               |
-   |               help: try adding a comma: `,`
-
-error: expected identifier, found keyword `true`
-  --> $DIR/type-ascription-in-pattern.rs:4:9
-   |
-LL |     match x {
-   |           - while parsing this struct
-LL |         x: i32 => x,
-LL |         true => 42.,
-   |         ^^^^ expected identifier, found keyword
-
-error: expected identifier, found keyword `false`
-  --> $DIR/type-ascription-in-pattern.rs:5:9
-   |
-LL |     match x {
-   |           - while parsing this struct
-...
-LL |         false => 0.333,
-   |         ^^^^^ expected identifier, found keyword
-
-error: struct literals are not allowed here
-  --> $DIR/type-ascription-in-pattern.rs:2:11
-   |
-LL |       match x {
-   |  ___________^
-LL | |         x: i32 => x,
-LL | |         true => 42.,
-LL | |         false => 0.333,
-LL | |     }
-   | |_____^
-   |
-help: surround the struct literal with parentheses
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/type-ascription-in-pattern.rs:3:10
    |
-LL ~     match (x {
 LL |         x: i32 => x,
-LL |         true => 42.,
-LL |         false => 0.333,
-LL ~     })
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
    |
-
-error: expected one of `.`, `?`, `{`, or an operator, found `}`
-  --> $DIR/type-ascription-in-pattern.rs:7:1
+help: maybe write a path separator here
    |
-LL |     match x {
-   |     ----- while parsing this `match` expression
-...
-LL |     }
-   |      - expected one of `.`, `?`, `{`, or an operator
-LL | }
-   | ^ unexpected token
+LL |         x::i32 => x,
+   |          ~~
 
 error: expected one of `...`, `..=`, `..`, or `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:11:11
+  --> $DIR/type-ascription-in-pattern.rs:12:11
    |
 LL |         42: i32 => (),
    |           ^ --- specifying the type of a pattern isn't supported
@@ -66,7 +20,7 @@ LL |         42: i32 => (),
    |           expected one of `...`, `..=`, `..`, or `|`
 
 error: expected `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:12:10
+  --> $DIR/type-ascription-in-pattern.rs:13:10
    |
 LL |         _: f64 => (),
    |          ^ --- specifying the type of a pattern isn't supported
@@ -74,7 +28,7 @@ LL |         _: f64 => (),
    |          expected `|`
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/type-ascription-in-pattern.rs:13:10
+  --> $DIR/type-ascription-in-pattern.rs:14:10
    |
 LL |         x: i32 => (),
    |          ^ --- specifying the type of a pattern isn't supported
@@ -86,5 +40,15 @@ help: maybe write a path separator here
 LL |         x::i32 => (),
    |          ~~
 
-error: aborting due to 8 previous errors
+error[E0308]: mismatched types
+  --> $DIR/type-ascription-in-pattern.rs:3:19
+   |
+LL | fn foo(x: bool) -> i32 {
+   |                    --- expected `i32` because of return type
+LL |     match x {
+LL |         x: i32 => x,
+   |                   ^ expected `i32`, found `bool`
+
+error: aborting due to 5 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs
index 1e058abe3bc..c3dddd8e459 100644
--- a/tests/ui/proc-macro/expand-expr.rs
+++ b/tests/ui/proc-macro/expand-expr.rs
@@ -1,6 +1,6 @@
 //@ proc-macro: expand-expr.rs
 //@ ignore-backends: gcc
-// no-remap-src-base: check_expand_expr_file!() fails when enabled.
+// No `remap-src-base`, since `check_expand_expr_file!()` fails when enabled.
 
 #![feature(concat_bytes)]
 extern crate expand_expr;
diff --git a/tests/ui/proc-macro/pretty-print-hack-show.rs b/tests/ui/proc-macro/pretty-print-hack-show.rs
index 70f0d5f6ea9..08e26c81142 100644
--- a/tests/ui/proc-macro/pretty-print-hack-show.rs
+++ b/tests/ui/proc-macro/pretty-print-hack-show.rs
@@ -1,7 +1,6 @@
 //@ proc-macro: test-macros.rs
 //@ compile-flags: -Z span-debug
 //@ revisions: local remapped
-// [local] no-remap-src-base: The hack should work regardless of remapping.
 //@ [remapped] remap-src-base
 
 #![no_std] // Don't load unnecessary hygiene information from std
diff --git a/tests/ui/span/suggestion-non-ascii.stderr b/tests/ui/span/suggestion-non-ascii.stderr
index 6e6e31a5698..361f744ee8e 100644
--- a/tests/ui/span/suggestion-non-ascii.stderr
+++ b/tests/ui/span/suggestion-non-ascii.stderr
@@ -2,7 +2,9 @@ error[E0608]: cannot index into a value of type `({integer},)`
   --> $DIR/suggestion-non-ascii.rs:3:24
    |
 LL |     println!("☃{}", tup[0]);
-   |                        ^^^ help: to access tuple elements, use: `.0`
+   |                        ^^^ help: to access tuple element `0`, use: `.0`
+   |
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/static/static-align.rs b/tests/ui/static/static-align.rs
index 93241db09f9..e2db7c01adf 100644
--- a/tests/ui/static/static-align.rs
+++ b/tests/ui/static/static-align.rs
@@ -1,10 +1,14 @@
 //@ run-pass
+//@ compile-flags: --cfg FOURTY_TWO="42" --cfg TRUE --check-cfg=cfg(FOURTY_TWO,values("42")) --check-cfg=cfg(TRUE)
 #![feature(static_align)]
+#![deny(non_upper_case_globals)]
+
+use std::cell::Cell;
 
 #[rustc_align_static(64)]
 static A: u8 = 0;
 
-#[rustc_align_static(64)]
+#[rustc_align_static(4096)]
 static B: u8 = 0;
 
 #[rustc_align_static(128)]
@@ -17,10 +21,86 @@ unsafe extern "C" {
     static C: u64;
 }
 
+struct HasDrop(*const HasDrop);
+
+impl Drop for HasDrop {
+    fn drop(&mut self) {
+        assert_eq!(core::ptr::from_mut(self).cast_const(), self.0);
+    }
+}
+
+thread_local! {
+    #[rustc_align_static(4096)]
+    static LOCAL: u64 = 0;
+
+    #[allow(unused_mut, reason = "test attribute handling")]
+    #[cfg_attr(true, rustc_align_static(4096))]
+    static CONST_LOCAL: u64 = const { 0 };
+
+    #[cfg_attr(any(true), cfg_attr(true, rustc_align_static(4096)))]
+    #[allow(unused_mut, reason = "test attribute handling")]
+    static HASDROP_LOCAL: Cell<HasDrop> = Cell::new(HasDrop(core::ptr::null()));
+
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    #[allow(unused_mut, reason = "test attribute handling")]
+    #[cfg_attr(TRUE,
+      cfg_attr(FOURTY_TWO = "42",
+      cfg_attr(all(),
+      cfg_attr(any(true),
+      cfg_attr(true, rustc_align_static(4096))))))]
+    #[allow(unused_mut, reason = "test attribute handling")]
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    static HASDROP_CONST_LOCAL: Cell<HasDrop> = const { Cell::new(HasDrop(core::ptr::null())) };
+
+    #[cfg_attr(TRUE,)]
+    #[cfg_attr(true,)]
+    #[cfg_attr(false,)]
+    #[cfg_attr(
+        TRUE,
+        rustc_align_static(32),
+        cfg_attr(true, allow(non_upper_case_globals, reason = "test attribute handling")),
+        cfg_attr(false,)
+    )]
+    #[cfg_attr(false, rustc_align_static(0))]
+    static more_attr_testing: u64 = 0;
+}
+
+fn thread_local_ptr<T>(key: &'static std::thread::LocalKey<T>) -> *const T {
+    key.with(|local| core::ptr::from_ref::<T>(local))
+}
+
 fn main() {
     assert!(core::ptr::from_ref(&A).addr().is_multiple_of(64));
-    assert!(core::ptr::from_ref(&B).addr().is_multiple_of(64));
+    assert!(core::ptr::from_ref(&B).addr().is_multiple_of(4096));
 
     assert!(core::ptr::from_ref(&EXPORTED).addr().is_multiple_of(128));
     unsafe { assert!(core::ptr::from_ref(&C).addr().is_multiple_of(128)) };
+
+    assert!(thread_local_ptr(&LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&CONST_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&HASDROP_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&HASDROP_CONST_LOCAL).addr().is_multiple_of(4096));
+    assert!(thread_local_ptr(&more_attr_testing).addr().is_multiple_of(32));
+
+    // Test that address (and therefore alignment) is maintained during drop
+    let hasdrop_ptr = thread_local_ptr(&HASDROP_LOCAL);
+    core::mem::forget(HASDROP_LOCAL.replace(HasDrop(hasdrop_ptr.cast())));
+    let hasdrop_const_ptr = thread_local_ptr(&HASDROP_CONST_LOCAL);
+    core::mem::forget(HASDROP_CONST_LOCAL.replace(HasDrop(hasdrop_const_ptr.cast())));
 }
diff --git a/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed
new file mode 100644
index 00000000000..0258f868f00
--- /dev/null
+++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.fixed
@@ -0,0 +1,18 @@
+//@ run-rustfix
+
+// Regression test for issue #143330.
+// Ensure we suggest to replace only the intended coma with a bar, not all commas in the pattern.
+
+fn main() {
+    struct Foo { x: i32, ch: char }
+    let pos = Foo { x: 2, ch: 'x' };
+    match pos {
+        // All commas here were replaced with bars.
+        // Foo { x: 2 | ch: ' |' } | Foo { x: 3 | ch: '@' } => (),
+        (Foo { x: 2, ch: ',' } | Foo { x: 3, ch: '@' }) => (),
+        //~^ ERROR unexpected `,` in pattern
+        //~| HELP try adding parentheses to match on a tuple...
+        //~| HELP ...or a vertical bar to match on alternative
+        _ => todo!(),
+    }
+}
diff --git a/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs
new file mode 100644
index 00000000000..7d5087fa0ff
--- /dev/null
+++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.rs
@@ -0,0 +1,18 @@
+//@ run-rustfix
+
+// Regression test for issue #143330.
+// Ensure we suggest to replace only the intended coma with a bar, not all commas in the pattern.
+
+fn main() {
+    struct Foo { x: i32, ch: char }
+    let pos = Foo { x: 2, ch: 'x' };
+    match pos {
+        // All commas here were replaced with bars.
+        // Foo { x: 2 | ch: ' |' } | Foo { x: 3 | ch: '@' } => (),
+        Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (),
+        //~^ ERROR unexpected `,` in pattern
+        //~| HELP try adding parentheses to match on a tuple...
+        //~| HELP ...or a vertical bar to match on alternative
+        _ => todo!(),
+    }
+}
diff --git a/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr
new file mode 100644
index 00000000000..ee75e2db133
--- /dev/null
+++ b/tests/ui/suggestions/only-replace-intended-coma-not-all-in-pattern.stderr
@@ -0,0 +1,18 @@
+error: unexpected `,` in pattern
+  --> $DIR/only-replace-intended-coma-not-all-in-pattern.rs:12:30
+   |
+LL |         Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (),
+   |                              ^
+   |
+help: try adding parentheses to match on a tuple...
+   |
+LL |         (Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' }) => (),
+   |         +                                            +
+help: ...or a vertical bar to match on alternatives
+   |
+LL -         Foo { x: 2, ch: ',' }, Foo { x: 3, ch: '@' } => (),
+LL +         Foo { x: 2, ch: ',' } | Foo { x: 3, ch: '@' } => (),
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/thread-local/long-docs.rs b/tests/ui/thread-local/long-docs.rs
new file mode 100644
index 00000000000..0577d0b27c2
--- /dev/null
+++ b/tests/ui/thread-local/long-docs.rs
@@ -0,0 +1,266 @@
+//@ check-pass
+
+thread_local! {
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    pub static LONG_DOCS: () = ();
+
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    /// I love doc comments.
+    #[allow(unused_mut, reason = "testing")]
+    pub static LONG_DOCS_2: () = ();
+}
+
+fn main() {}
diff --git a/tests/ui/thread-local/no-unstable.rs b/tests/ui/thread-local/no-unstable.rs
new file mode 100644
index 00000000000..3de7985e62d
--- /dev/null
+++ b/tests/ui/thread-local/no-unstable.rs
@@ -0,0 +1,17 @@
+thread_local! {
+    //~^ ERROR: use of an internal attribute [E0658]
+    //~| ERROR: use of an internal attribute [E0658]
+    //~| ERROR: `#[used(linker)]` is currently unstable [E0658]
+    //~| ERROR: `#[used]` attribute cannot be used on constants
+
+    #[rustc_dummy = 17]
+    pub static FOO: () = ();
+
+    #[cfg_attr(true, rustc_dummy = 17)]
+    pub static BAR: () = ();
+
+    #[used(linker)]
+    pub static BAZ: () = ();
+}
+
+fn main() {}
diff --git a/tests/ui/thread-local/no-unstable.stderr b/tests/ui/thread-local/no-unstable.stderr
new file mode 100644
index 00000000000..fbcd804d917
--- /dev/null
+++ b/tests/ui/thread-local/no-unstable.stderr
@@ -0,0 +1,57 @@
+error[E0658]: use of an internal attribute
+  --> $DIR/no-unstable.rs:1:1
+   |
+LL | / thread_local! {
+...  |
+LL | |     pub static BAZ: () = ();
+LL | | }
+   | |_^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+   = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_dummy]` attribute is used for rustc unit tests
+   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: use of an internal attribute
+  --> $DIR/no-unstable.rs:1:1
+   |
+LL | / thread_local! {
+...  |
+LL | |     pub static BAZ: () = ();
+LL | | }
+   | |_^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+   = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_dummy]` attribute is used for rustc unit tests
+   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `#[used(linker)]` is currently unstable
+  --> $DIR/no-unstable.rs:1:1
+   |
+LL | / thread_local! {
+...  |
+LL | |     pub static BAZ: () = ();
+LL | | }
+   | |_^
+   |
+   = note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information
+   = help: add `#![feature(used_with_arg)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `#[used]` attribute cannot be used on constants
+  --> $DIR/no-unstable.rs:1:1
+   |
+LL | / thread_local! {
+...  |
+LL | |     pub static BAZ: () = ();
+LL | | }
+   | |_^
+   |
+   = help: `#[used]` can only be applied to statics
+   = note: this error originates in the macro `$crate::thread::local_impl::thread_local_process_attrs` which comes from the expansion of the macro `thread_local` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs
new file mode 100644
index 00000000000..679d6b1fb16
--- /dev/null
+++ b/tests/ui/traits/next-solver/forced-ambiguity-typenum-ice.rs
@@ -0,0 +1,60 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#105. We previously encountered
+// an ICE in typenum as `forced_ambiguity` failed. While this test no longer causes
+// `forced_ambiguity` to error, we still want to use it as a regression test.
+
+pub struct UInt<U, B> {
+    _msb: U,
+    _lsb: B,
+}
+pub struct B1;
+pub trait Sub<Rhs> {
+    type Output;
+}
+impl<U, B> Sub<B1> for UInt<UInt<U, B>, B1> {
+    type Output = ();
+}
+impl<U> Sub<B1> for UInt<U, ()>
+where
+    U: Sub<B1>,
+    U::Output: Send,
+{
+    type Output = ();
+}
+
+pub trait Op<N, R, I> {
+    fn op(&self) {
+        unimplemented!()
+    }
+}
+trait OpIf<N, R, I> {}
+
+impl<N, Ur, Br, I> Op<N, UInt<Ur, Br>, I> for ()
+where
+    N: Sub<I>,
+    (): OpIf<N, UInt<UInt<Ur, Br>, N::Output>, I>,
+{
+}
+impl<N, R, Ui, Bi> OpIf<N, R, UInt<Ui, Bi>> for ()
+where
+    UInt<Ui, Bi>: Sub<B1>,
+    (): Op<N, R, <UInt<Ui, Bi> as Sub<B1>>::Output>,
+{
+}
+impl<N, R> OpIf<N, R, ()> for () where R: Sub<N> {}
+
+pub trait Compute {
+    type Output;
+}
+
+pub fn repro<Ul, Bl>()
+where
+    UInt<Ul, Bl>: Compute,
+    <UInt<Ul, Bl> as Compute>::Output: Sub<B1>,
+    (): Op<UInt<(), Bl>, (), ()>,
+{
+    ().op();
+}
+fn main() {}
diff --git a/tests/ui/type/pattern_types/const_generics.rs b/tests/ui/type/pattern_types/const_generics.rs
index 79d46c010d7..f5eb90e94d4 100644
--- a/tests/ui/type/pattern_types/const_generics.rs
+++ b/tests/ui/type/pattern_types/const_generics.rs
@@ -1,4 +1,7 @@
 //@ check-pass
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 
 #![feature(pattern_types, generic_pattern_types, pattern_type_macro)]
 #![expect(incomplete_features)]
diff --git a/tests/ui/type/pattern_types/transmute.stderr b/tests/ui/type/pattern_types/transmute.current.stderr
index 578549b515c..edec542e5e1 100644
--- a/tests/ui/type/pattern_types/transmute.stderr
+++ b/tests/ui/type/pattern_types/transmute.current.stderr
@@ -1,5 +1,5 @@
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/transmute.rs:20:14
+  --> $DIR/transmute.rs:23:14
    |
 LL |     unsafe { std::mem::transmute(x) }
    |              ^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     unsafe { std::mem::transmute(x) }
    = note: target type: `u32` (32 bits)
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
-  --> $DIR/transmute.rs:28:14
+  --> $DIR/transmute.rs:31:14
    |
 LL |     unsafe { std::mem::transmute(x) }
    |              ^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/type/pattern_types/transmute.next.stderr b/tests/ui/type/pattern_types/transmute.next.stderr
new file mode 100644
index 00000000000..edec542e5e1
--- /dev/null
+++ b/tests/ui/type/pattern_types/transmute.next.stderr
@@ -0,0 +1,21 @@
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute.rs:23:14
+   |
+LL |     unsafe { std::mem::transmute(x) }
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32)
+   = note: target type: `u32` (32 bits)
+
+error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
+  --> $DIR/transmute.rs:31:14
+   |
+LL |     unsafe { std::mem::transmute(x) }
+   |              ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: source type: `Option<(u32) is S..=E>` (size can vary because of u32)
+   = note: target type: `Option<u32>` (64 bits)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0512`.
diff --git a/tests/ui/type/pattern_types/transmute.rs b/tests/ui/type/pattern_types/transmute.rs
index 43dd62a19e7..4e686245f93 100644
--- a/tests/ui/type/pattern_types/transmute.rs
+++ b/tests/ui/type/pattern_types/transmute.rs
@@ -1,3 +1,6 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
 #![feature(pattern_types, pattern_type_macro, generic_pattern_types)]
 #![expect(incomplete_features)]
 
diff --git a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr
index 13bc0cd94f3..ef5f1786801 100644
--- a/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr
+++ b/tests/ui/typeck/coercion-check-for-indexing-expression-issue-40861.stderr
@@ -4,7 +4,7 @@ error[E0608]: cannot index into a value of type `()`
 LL |     ()[f(&[1.0])];
    |       ^^^^^^^^^^^
    |
-   = help: to access tuple elements, use tuple indexing syntax (e.g., `tuple.0`)
+   = help: tuples are indexed with a dot and a literal index: `tuple.0`, `tuple.1`, etc.
 
 error: aborting due to 1 previous error
 
diff --git a/triagebot.toml b/triagebot.toml
index a04f8d28072..79b5c2d1b72 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -61,10 +61,6 @@ required-issue-label = "regression-from-stable-to-beta"
 # if the above conditions matches, the PR will receive these labels
 add-labels = ["beta-nominated"]
 
-[backport.t-compiler-stable-backport]
-required-pr-labels = ["T-compiler"]
-required-issue-label = "regression-from-stable-to-stable"
-add-labels = ["stable-nominated"]
 
 # ------------------------------------------------------------------------------
 # Ping groups