about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock14
-rw-r--r--compiler/rustc_abi/src/layout.rs46
-rw-r--r--compiler/rustc_abi/src/layout/ty.rs10
-rw-r--r--compiler/rustc_abi/src/lib.rs19
-rw-r--r--compiler/rustc_ast/src/token.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/delegation.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs136
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs334
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs151
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs70
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs21
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs46
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_ast_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs3
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/lib.rs35
-rw-r--r--compiler/rustc_borrowck/src/nll.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs14
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs (renamed from compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs)20
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs33
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs23
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs28
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs98
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs285
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs48
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs82
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs13
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs188
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs91
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs26
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs8
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs16
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs6
-rw-r--r--compiler/rustc_const_eval/src/util/check_validity_requirement.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0539.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0542.md1
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0667.md6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0801.md51
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs2
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs2
-rw-r--r--compiler/rustc_errors/src/emitter.rs15
-rw-r--r--compiler/rustc_errors/src/json.rs4
-rw-r--r--compiler/rustc_expand/messages.ftl2
-rw-r--r--compiler/rustc_expand/src/errors.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs5
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs13
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs7
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs98
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs3
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs20
-rw-r--r--compiler/rustc_hir/src/intravisit.rs7
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl10
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs67
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs517
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs125
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs6
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs91
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs5
-rw-r--r--compiler/rustc_infer/src/infer/at.rs36
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs6
-rw-r--r--compiler/rustc_infer/src/infer/context.rs17
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs99
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs51
-rw-r--r--compiler/rustc_infer/src/infer/relate/generalize.rs11
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/messages.ftl12
-rw-r--r--compiler/rustc_lint/src/builtin.rs25
-rw-r--r--compiler/rustc_lint/src/context.rs35
-rw-r--r--compiler/rustc_lint/src/dangling.rs223
-rw-r--r--compiler/rustc_lint/src/early.rs18
-rw-r--r--compiler/rustc_lint/src/for_loops_over_fallibles.rs2
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs2
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs3
-rw-r--r--compiler/rustc_lint/src/impl_trait_overcaptures.rs4
-rw-r--r--compiler/rustc_lint/src/late.rs17
-rw-r--r--compiler/rustc_lint/src/lib.rs19
-rw-r--r--compiler/rustc_lint/src/lints.rs17
-rw-r--r--compiler/rustc_lint/src/methods.rs69
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/types/literal.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp14
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp261
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs5
-rw-r--r--compiler/rustc_macros/src/diagnostics/error.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs2
-rw-r--r--compiler/rustc_macros/src/lib.rs10
-rw-r--r--compiler/rustc_macros/src/try_from.rs55
-rw-r--r--compiler/rustc_metadata/Cargo.toml1
-rw-r--r--compiler/rustc_metadata/src/creader.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs2
-rw-r--r--compiler/rustc_middle/src/middle/debugger_visualizer.rs2
-rw-r--r--compiler/rustc_middle/src/middle/resolve_bound_vars.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs17
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs45
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs19
-rw-r--r--compiler/rustc_middle/src/ty/context.rs36
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs6
-rw-r--r--compiler/rustc_mir_dataflow/Cargo.toml1
-rw-r--r--compiler/rustc_mir_dataflow/src/drop_flag_effects.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/graphviz.rs111
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs109
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/results.rs (renamed from compiler/rustc_mir_dataflow/src/framework/engine.rs)121
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs6
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs15
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs2
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml1
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs23
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs31
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs117
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs3
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs5
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs8
-rw-r--r--compiler/rustc_mir_transform/src/lint.rs6
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/delegate.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs14
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs23
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs17
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs50
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs46
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs3
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_passes/Cargo.toml1
-rw-r--r--compiler/rustc_passes/messages.ftl4
-rw-r--r--compiler/rustc_passes/src/check_attr.rs50
-rw-r--r--compiler/rustc_passes/src/dead.rs2
-rw-r--r--compiler/rustc_passes/src/errors.rs9
-rw-r--r--compiler/rustc_passes/src/layout_test.rs5
-rw-r--r--compiler/rustc_passes/src/stability.rs3
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml3
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs2
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc/print.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs4
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs6
-rw-r--r--compiler/rustc_resolve/src/late.rs40
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_resolve/src/macros.rs42
-rw-r--r--compiler/rustc_session/Cargo.toml1
-rw-r--r--compiler/rustc_session/src/code_stats.rs2
-rw-r--r--compiler/rustc_session/src/config/cfg.rs2
-rw-r--r--compiler/rustc_session/src/filesearch.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs6
-rw-r--r--compiler/rustc_session/src/session.rs5
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs14
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs50
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/mir.rs6
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs2
-rw-r--r--compiler/rustc_span/src/caching_source_map_view.rs14
-rw-r--r--compiler/rustc_span/src/source_map.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs5
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml2
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs17
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs28
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs59
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/effects.rs153
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs48
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs40
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs113
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs5
-rw-r--r--compiler/rustc_traits/src/codegen.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_transmute/Cargo.toml6
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs2
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs14
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs2
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs4
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs32
-rw-r--r--compiler/rustc_ty_utils/src/layout/invariant.rs6
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs4
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs4
-rw-r--r--compiler/rustc_type_ir/src/infer_ctxt.rs68
-rw-r--r--compiler/rustc_type_ir/src/interner.rs23
-rw-r--r--compiler/rustc_type_ir/src/outlives.rs12
-rw-r--r--compiler/rustc_type_ir/src/relate/combine.rs18
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs21
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs13
-rw-r--r--library/alloc/src/boxed.rs1032
-rw-r--r--library/alloc/src/boxed/convert.rs747
-rw-r--r--library/alloc/src/boxed/iter.rs194
-rw-r--r--library/alloc/src/rc.rs28
-rw-r--r--library/alloc/src/sync.rs16
-rw-r--r--library/alloc/tests/arc.rs40
-rw-r--r--library/alloc/tests/boxed.rs39
-rw-r--r--library/alloc/tests/rc.rs38
-rw-r--r--library/core/benches/lib.rs1
-rw-r--r--library/core/src/cell.rs1
-rw-r--r--library/core/src/char/methods.rs3
-rw-r--r--library/core/src/ffi/c_str.rs4
-rw-r--r--library/core/src/lib.rs4
-rw-r--r--library/core/src/marker.rs7
-rw-r--r--library/core/src/net/socket_addr.rs40
-rw-r--r--library/core/src/num/int_macros.rs48
-rw-r--r--library/core/src/num/mod.rs65
-rw-r--r--library/core/src/num/nonzero.rs5
-rw-r--r--library/core/src/num/uint_macros.rs5
-rw-r--r--library/core/src/primitive_docs.rs12
-rw-r--r--library/core/src/str/mod.rs48
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/num/int_macros.rs4
-rw-r--r--library/core/tests/num/midpoint.rs54
-rw-r--r--library/core/tests/num/mod.rs1
-rw-r--r--library/proc_macro/src/lib.rs4
-rw-r--r--library/proc_macro/src/to_tokens.rs310
-rw-r--r--library/std/src/fs.rs2
-rw-r--r--library/std/src/sys/sync/condvar/no_threads.rs2
-rw-r--r--library/std/src/sys/sync/condvar/xous.rs1
-rw-r--r--library/std/src/sys/sync/mutex/no_threads.rs2
-rw-r--r--library/std/src/sys/sync/mutex/xous.rs1
-rw-r--r--library/std/src/sys/sync/once/no_threads.rs2
-rw-r--r--library/std/src/sys/sync/rwlock/no_threads.rs2
m---------library/stdarch0
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs23
-rw-r--r--src/bootstrap/src/core/config/config.rs9
-rw-r--r--src/bootstrap/src/lib.rs2
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile3
-rwxr-xr-xsrc/ci/docker/scripts/freebsd-toolchain.sh8
-rw-r--r--src/doc/rustc/src/SUMMARY.md3
-rw-r--r--src/doc/rustc/src/platform-support.md24
-rw-r--r--src/doc/rustc/src/platform-support/aix.md4
-rw-r--r--src/doc/rustc/src/platform-support/fuchsia.md23
-rwxr-xr-xsrc/etc/cat-and-grep.sh1
-rwxr-xr-xsrc/etc/htmldocck.py2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs4
-rw-r--r--src/librustdoc/clean/inline.rs26
-rw-r--r--src/librustdoc/clean/mod.rs8
-rw-r--r--src/librustdoc/doctest/runner.rs4
-rw-r--r--src/librustdoc/html/format.rs13
-rw-r--r--src/librustdoc/html/render/search_index.rs5
-rw-r--r--src/librustdoc/html/render/type_layout.rs8
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css4
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/mir/possible_borrower.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.rs10
-rw-r--r--src/tools/clippy/tests/ui/cast.rs1
-rw-r--r--src/tools/clippy/tests/ui/cast.stderr184
-rw-r--r--src/tools/clippy/tests/ui/issue_4266.stderr2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr18
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/directive-list.rs (renamed from src/tools/compiletest/src/command-list.rs)0
-rw-r--r--src/tools/compiletest/src/header.rs116
-rw-r--r--src/tools/compiletest/src/header/tests.rs78
-rw-r--r--src/tools/compiletest/src/lib.rs2
-rw-r--r--src/tools/compiletest/src/runtest.rs10
-rw-r--r--src/tools/compiletest/src/runtest/run_make.rs1
-rw-r--r--src/tools/compiletest/src/tests.rs13
-rw-r--r--src/tools/jsondocck/src/main.rs2
-rw-r--r--src/tools/miri/.github/workflows/ci.yml44
-rwxr-xr-xsrc/tools/miri/ci/ci.sh2
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs6
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs30
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs11
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs9
-rw-r--r--src/tools/miri/src/shims/io_error.rs10
-rw-r--r--src/tools/miri/src/shims/time.rs12
-rw-r--r--src/tools/miri/src/shims/unix/android/foreign_items.rs4
-rw-r--r--src/tools/miri/src/shims/unix/android/mod.rs1
-rw-r--r--src/tools/miri/src/shims/unix/android/thread.rs57
-rw-r--r--src/tools/miri/src/shims/unix/fd.rs37
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs25
-rw-r--r--src/tools/miri/src/shims/unix/freebsd/foreign_items.rs1
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs221
-rw-r--r--src/tools/miri/src/shims/unix/linux/epoll.rs42
-rw-r--r--src/tools/miri/src/shims/unix/linux/foreign_items.rs1
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs4
-rw-r--r--src/tools/miri/src/shims/unix/linux/sync.rs17
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs1
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs16
-rw-r--r--src/tools/miri/src/shims/unix/solarish/foreign_items.rs1
-rw-r--r--src/tools/miri/src/shims/unix/thread.rs12
-rw-r--r--src/tools/miri/src/shims/windows/sync.rs2
-rw-r--r--src/tools/miri/test_dependencies/Cargo.lock6
-rw-r--r--src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs10
-rw-r--r--src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr21
-rw-r--r--src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs2
-rw-r--r--src/tools/miri/tests/fail/coroutine-pinned-moved.stderr2
-rw-r--r--src/tools/miri/tests/fail/provenance/ptr_invalid.rs1
-rw-r--r--src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs16
-rw-r--r--src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr30
-rw-r--r--src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs74
-rw-r--r--src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs18
-rw-r--r--src/tools/miri/tests/pass/dyn-upcast.rs3
-rw-r--r--src/tools/miri/tests/pass/float.rs160
-rw-r--r--src/tools/run-make-support/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml37
-rw-r--r--src/tools/rust-analyzer/.gitignore3
-rw-r--r--src/tools/rust-analyzer/Cargo.lock45
-rw-r--r--src/tools/rust-analyzer/Cargo.toml15
-rw-r--r--src/tools/rust-analyzer/crates/cfg/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body.rs267
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs693
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs65
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs34
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs341
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir.rs228
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs228
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs279
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs388
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs100
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lower.rs63
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs207
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs46
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path.rs168
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs55
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/pretty.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs88
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/test_db.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs42
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs81
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs187
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs108
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs120
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs245
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs169
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs331
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs29
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs272
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs98
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs86
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/db.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs111
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs38
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs98
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs255
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs45
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/documentation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/source_change.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs559
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs (renamed from src/tools/rust-analyzer/crates/text-edit/src/lib.rs)2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs94
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs190
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs161
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs27
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs277
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs106
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs121
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/join_lines.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/move_item.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs25
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs18
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests.rs17
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast11
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast11
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs23
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt6
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt12
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt11
-rw-r--r--src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs35
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs22
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs38
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs69
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs83
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs23
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs31
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs131
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs42
-rw-r--r--src/tools/rust-analyzer/crates/span/src/ast_id.rs3
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs17
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs472
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram11
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/algo.rs561
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs81
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs16
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/fuzz.rs9
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs23
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs59
-rw-r--r--src/tools/rust-analyzer/crates/text-edit/Cargo.toml20
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/buffer.rs2
-rw-r--r--src/tools/rust-analyzer/editors/code/.vscodeignore1
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json7
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts2
-rw-r--r--src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md10
-rw-r--r--src/tools/rust-analyzer/rust-bors.toml1
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen.rs4
-rw-r--r--src/tools/rust-analyzer/xtask/src/dist.rs3
-rw-r--r--src/tools/rust-analyzer/xtask/src/release/changelog.rs5
-rw-r--r--src/tools/rust-analyzer/xtask/src/tidy.rs2
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/assembly/riscv-soft-abi-with-float-features.rs11
-rw-r--r--tests/crashes/125249.rs8
-rw-r--r--tests/crashes/126725.rs20
-rw-r--r--tests/crashes/23707.rs109
-rw-r--r--tests/run-make/linkage-attr-framework/main.rs17
-rw-r--r--tests/run-make/linkage-attr-framework/rmake.rs26
-rw-r--r--tests/rustdoc-gui/check-stab-in-docblock.goml14
-rw-r--r--tests/rustdoc-gui/docblock-big-code-mobile.goml10
-rw-r--r--tests/rustdoc-gui/fields.goml50
-rw-r--r--tests/rustdoc-gui/struct-fields.goml3
-rw-r--r--tests/rustdoc-js/extern-func.js8
-rw-r--r--tests/rustdoc-js/extern-func.rs5
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.rs15
-rw-r--r--tests/rustdoc-ui/doctest/dead-code-2024.stdout29
-rw-r--r--tests/rustdoc-ui/doctest/dead-code.rs15
-rw-r--r--tests/rustdoc-ui/doctest/dead-code.stdout29
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr136
-rw-r--r--tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr2
-rw-r--r--tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr134
-rw-r--r--tests/ui-fulldeps/try-from-u32/errors.rs24
-rw-r--r--tests/ui-fulldeps/try-from-u32/errors.stderr32
-rw-r--r--tests/ui-fulldeps/try-from-u32/hygiene.rs32
-rw-r--r--tests/ui-fulldeps/try-from-u32/values.rs36
-rw-r--r--tests/ui/array-slice-vec/vec-macro-with-comma-only.rs2
-rw-r--r--tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr2
-rw-r--r--tests/ui/associated-consts/issue-58022.stderr2
-rw-r--r--tests/ui/associated-type-bounds/implied-from-self-where-clause.rs21
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr2
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs (renamed from tests/crashes/131648.rs)3
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr27
-rw-r--r--tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr2
-rw-r--r--tests/ui/associated-types/defaults-suitability.current.stderr6
-rw-r--r--tests/ui/associated-types/defaults-suitability.next.stderr6
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-1.stderr2
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-1.stderr2
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-2.stderr2
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-3.stderr2
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-4.stderr2
-rw-r--r--tests/ui/associated-types/hr-associated-type-bound-param-5.stderr4
-rw-r--r--tests/ui/associated-types/issue-38821.stderr36
-rw-r--r--tests/ui/associated-types/issue-43784-associated-type.stderr2
-rw-r--r--tests/ui/associated-types/issue-65774-1.stderr2
-rw-r--r--tests/ui/associated-types/substs-ppaux.normal.stderr2
-rw-r--r--tests/ui/associated-types/substs-ppaux.verbose.stderr2
-rw-r--r--tests/ui/async-await/async-await-let-else.stderr8
-rw-r--r--tests/ui/async-await/async-closures/not-clone-closure.stderr2
-rw-r--r--tests/ui/async-await/async-fn-nonsend.stderr4
-rw-r--r--tests/ui/async-await/async-is-unwindsafe.stderr2
-rw-r--r--tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr2
-rw-r--r--tests/ui/async-await/drop-track-bad-field-in-fru.stderr2
-rw-r--r--tests/ui/async-await/drop-track-field-assign-nonsend.stderr2
-rw-r--r--tests/ui/async-await/field-assign-nonsend.stderr2
-rw-r--r--tests/ui/async-await/in-trait/missing-send-bound.stderr2
-rw-r--r--tests/ui/async-await/issue-101715.stderr2
-rw-r--r--tests/ui/async-await/issue-64130-1-sync.stderr2
-rw-r--r--tests/ui/async-await/issue-64130-2-send.stderr2
-rw-r--r--tests/ui/async-await/issue-64130-3-other.stderr2
-rw-r--r--tests/ui/async-await/issue-64130-non-send-future-diags.stderr2
-rw-r--r--tests/ui/async-await/issue-67252-unnamed-future.stderr2
-rw-r--r--tests/ui/async-await/issue-68112.stderr6
-rw-r--r--tests/ui/async-await/issue-70935-complex-spans.stderr4
-rw-r--r--tests/ui/async-await/issue-71137.stderr2
-rw-r--r--tests/ui/async-await/issue-72590-type-error-sized.stderr2
-rw-r--r--tests/ui/async-await/issues/issue-67893.stderr2
-rw-r--r--tests/ui/async-await/partial-drop-partial-reinit.stderr2
-rw-r--r--tests/ui/async-await/pin-needed-to-poll-2.stderr2
-rw-r--r--tests/ui/async-await/unnecessary-await.stderr8
-rw-r--r--tests/ui/auto-traits/issue-83857-ub.stderr4
-rw-r--r--tests/ui/auto-traits/str-contains-slice-conceptually.stderr2
-rw-r--r--tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr2
-rw-r--r--tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr2
-rw-r--r--tests/ui/binop/binary-op-suggest-deref.stderr16
-rw-r--r--tests/ui/block-result/issue-22645.stderr2
-rw-r--r--tests/ui/cast/unsized-union-ice.stderr2
-rw-r--r--tests/ui/check-cfg/mix.stderr2
-rw-r--r--tests/ui/check-cfg/well-known-values.stderr2
-rw-r--r--tests/ui/closures/closure-move-sync.stderr2
-rw-r--r--tests/ui/closures/closure-return-type-must-be-sized.stderr18
-rw-r--r--tests/ui/coherence/deep-bad-copy-reason.stderr2
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr2
-rw-r--r--tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr6
-rw-r--r--tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-85848.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-67185-2.stderr4
-rw-r--r--tests/ui/const-generics/kind_mismatch.stderr2
-rw-r--r--tests/ui/consts/const-block-const-bound.stderr8
-rw-r--r--tests/ui/consts/const-blocks/fn-call-in-non-const.stderr2
-rw-r--r--tests/ui/consts/const-blocks/migrate-fail.stderr4
-rw-r--r--tests/ui/consts/const-blocks/nll-fail.stderr4
-rw-r--r--tests/ui/consts/const-blocks/trait-error.stderr2
-rw-r--r--tests/ui/consts/const-fn-in-vec.stderr4
-rw-r--r--tests/ui/consts/constifconst-call-in-const-position.stderr17
-rw-r--r--tests/ui/consts/fn_trait_refs.stderr92
-rw-r--r--tests/ui/consts/rustc-const-stability-require-const.rs5
-rw-r--r--tests/ui/consts/rustc-const-stability-require-const.stderr22
-rw-r--r--tests/ui/consts/unstable-const-fn-in-libcore.stderr8
-rw-r--r--tests/ui/consts/zst_no_llvm_alloc.rs7
-rw-r--r--tests/ui/coroutine/clone-impl.stderr12
-rw-r--r--tests/ui/coroutine/drop-tracking-parent-expression.stderr6
-rw-r--r--tests/ui/coroutine/drop-yield-twice.stderr2
-rw-r--r--tests/ui/coroutine/issue-105084.stderr2
-rw-r--r--tests/ui/coroutine/issue-68112.stderr4
-rw-r--r--tests/ui/coroutine/not-send-sync.stderr4
-rw-r--r--tests/ui/coroutine/parent-expression.stderr6
-rw-r--r--tests/ui/coroutine/print/coroutine-print-verbose-1.stderr4
-rw-r--r--tests/ui/coroutine/print/coroutine-print-verbose-2.stderr4
-rw-r--r--tests/ui/coroutine/ref-upvar-not-send.stderr4
-rw-r--r--tests/ui/coroutine/resume-arg-outlives-2.rs34
-rw-r--r--tests/ui/coroutine/resume-arg-outlives-2.stderr17
-rw-r--r--tests/ui/coroutine/resume-arg-outlives.rs27
-rw-r--r--tests/ui/coroutine/resume-arg-outlives.stderr20
-rw-r--r--tests/ui/coroutine/unresolved-ct-var.stderr2
-rw-r--r--tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr2
-rw-r--r--tests/ui/delegation/unsupported.stderr7
-rw-r--r--tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr2
-rw-r--r--tests/ui/derives/derives-span-Debug-enum.stderr2
-rw-r--r--tests/ui/derives/derives-span-Debug-struct.stderr2
-rw-r--r--tests/ui/derives/derives-span-Debug-tuple-struct.stderr2
-rw-r--r--tests/ui/deriving/auxiliary/another-proc-macro.rs2
-rw-r--r--tests/ui/deriving/built-in-proc-macro-scope.rs6
-rw-r--r--tests/ui/deriving/built-in-proc-macro-scope.stdout4
-rw-r--r--tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs (renamed from tests/ui/deriving/smart-pointer-bounds-issue-127647.rs)16
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-expanded.rs (renamed from tests/ui/deriving/deriving-smart-pointer-expanded.rs)10
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-expanded.stdout (renamed from tests/ui/deriving/deriving-smart-pointer-expanded.stdout)4
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-neg.rs (renamed from tests/ui/deriving/deriving-smart-pointer-neg.rs)88
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-neg.stderr119
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee.rs (renamed from tests/ui/deriving/deriving-smart-pointer.rs)6
-rw-r--r--tests/ui/deriving/deriving-smart-pointer-neg.stderr119
-rw-r--r--tests/ui/deriving/issue-103157.stderr2
-rw-r--r--tests/ui/deriving/proc-macro-attribute-mixing.rs4
-rw-r--r--tests/ui/deriving/proc-macro-attribute-mixing.stdout4
-rw-r--r--tests/ui/drop/drop_order.rs2
-rw-r--r--tests/ui/drop/drop_order_if_let_rescope.rs1
-rw-r--r--tests/ui/drop/if-let-rescope-borrowck-suggestions.rs1
-rw-r--r--tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr12
-rw-r--r--tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr (renamed from tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr)0
-rw-r--r--tests/ui/drop/lint-if-let-rescope-gated.rs22
-rw-r--r--tests/ui/drop/lint-if-let-rescope-with-macro.rs1
-rw-r--r--tests/ui/drop/lint-if-let-rescope-with-macro.stderr6
-rw-r--r--tests/ui/drop/lint-if-let-rescope.fixed2
-rw-r--r--tests/ui/drop/lint-if-let-rescope.rs2
-rw-r--r--tests/ui/dropck/const_drop_is_valid.stderr7
-rw-r--r--tests/ui/dst/dst-bad-deep-2.stderr2
-rw-r--r--tests/ui/dst/dst-bad-deep.stderr2
-rw-r--r--tests/ui/editions/edition-keywords-2015-2015-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2015-parsing.stderr4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2018-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2015-2018-parsing.stderr4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.stderr6
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.rs4
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr6
-rw-r--r--tests/ui/error-codes/E0277-2.stderr2
-rw-r--r--tests/ui/error-codes/E0277.stderr2
-rw-r--r--tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr28
-rw-r--r--tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr28
-rw-r--r--tests/ui/extern/extern-types-unsized.stderr6
-rw-r--r--tests/ui/fail-simple.rs2
-rw-r--r--tests/ui/fail-simple.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-if-let-rescope.rs27
-rw-r--r--tests/ui/feature-gates/feature-gate-if-let-rescope.stderr18
-rw-r--r--tests/ui/feature-gates/feature-gate-offset-of-slice.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-trivial_bounds.stderr2
-rw-r--r--tests/ui/fmt/ifmt-unimpl.stderr2
-rw-r--r--tests/ui/for/for-c-in-str.stderr2
-rw-r--r--tests/ui/for/for-loop-bogosity.stderr2
-rw-r--r--tests/ui/function-pointer/unsized-ret.stderr4
-rw-r--r--tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr2
-rw-r--r--tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr2
-rw-r--r--tests/ui/generic-associated-types/impl_bounds.stderr4
-rw-r--r--tests/ui/generic-associated-types/issue-101020.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-74824.current.stderr2
-rw-r--r--tests/ui/generic-associated-types/issue-74824.next.stderr2
-rw-r--r--tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr6
-rw-r--r--tests/ui/impl-trait/auto-trait-leak2.stderr4
-rw-r--r--tests/ui/impl-trait/closure-in-type.rs (renamed from tests/crashes/126850.rs)3
-rw-r--r--tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs20
-rw-r--r--tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg62
-rw-r--r--tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr4
-rw-r--r--tests/ui/impl-trait/impl_trait_projections.rs11
-rw-r--r--tests/ui/impl-trait/impl_trait_projections.stderr70
-rw-r--r--tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs22
-rw-r--r--tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr11
-rw-r--r--tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr12
-rw-r--r--tests/ui/impl-trait/in-trait/return-type-notation.rs9
-rw-r--r--tests/ui/impl-trait/in-trait/return-type-notation.stderr27
-rw-r--r--tests/ui/impl-trait/in-trait/variance.rs6
-rw-r--r--tests/ui/impl-trait/in-trait/variance.stderr6
-rw-r--r--tests/ui/impl-trait/issue-55872-1.stderr4
-rw-r--r--tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs2
-rw-r--r--tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr6
-rw-r--r--tests/ui/impl-trait/nested_impl_trait.stderr4
-rw-r--r--tests/ui/impl-trait/normalize-tait-in-const.stderr16
-rw-r--r--tests/ui/indexing/index-help.stderr2
-rw-r--r--tests/ui/indexing/indexing-requires-a-uint.stderr2
-rw-r--r--tests/ui/indexing/point-at-index-for-obligation-failure.stderr2
-rw-r--r--tests/ui/integral-indexing.stderr16
-rw-r--r--tests/ui/interior-mutability/interior-mutability.stderr2
-rw-r--r--tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr7
-rw-r--r--tests/ui/issues/issue-21763.stderr2
-rw-r--r--tests/ui/issues/issue-22872.stderr2
-rw-r--r--tests/ui/issues/issue-22874.stderr2
-rw-r--r--tests/ui/issues/issue-40827.stderr4
-rw-r--r--tests/ui/issues/issue-7364.stderr2
-rw-r--r--tests/ui/iterators/float_iterator_hint.stderr2
-rw-r--r--tests/ui/iterators/integral.stderr24
-rw-r--r--tests/ui/iterators/issue-28098.stderr4
-rw-r--r--tests/ui/iterators/ranges.stderr4
-rw-r--r--tests/ui/iterators/string.stderr4
-rw-r--r--tests/ui/kindck/kindck-impl-type-params-2.stderr2
-rw-r--r--tests/ui/kindck/kindck-impl-type-params.stderr8
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr2
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr2
-rw-r--r--tests/ui/kindck/kindck-nonsendable-1.stderr2
-rw-r--r--tests/ui/kindck/kindck-send-object.stderr4
-rw-r--r--tests/ui/kindck/kindck-send-object1.stderr4
-rw-r--r--tests/ui/kindck/kindck-send-object2.stderr4
-rw-r--r--tests/ui/kindck/kindck-send-owned.stderr2
-rw-r--r--tests/ui/linkage-attr/framework.omit.stderr8
-rw-r--r--tests/ui/linkage-attr/framework.rs32
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/allow.rs23
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr34
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/calls.rs52
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr62
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs (renamed from tests/ui/lint/lint-temporary-cstring-as-param.rs)4
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr10
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs (renamed from tests/ui/lint/lint-temporary-cstring-as-ptr.rs)5
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr (renamed from tests/ui/lint/lint-temporary-cstring-as-ptr.stderr)28
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs19
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs13
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr29
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/ext.rs32
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr29
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/methods.rs8
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr29
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs136
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr99
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.rs52
-rw-r--r--tests/ui/lint/dangling-pointers-from-temporaries/types.stderr172
-rw-r--r--tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs10
-rw-r--r--tests/ui/lint/keyword-idents/multi-file.rs14
-rw-r--r--tests/ui/lint/lint-temporary-cstring-as-param.stderr18
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr4
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr4
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr4
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr4
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr4
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs15
-rw-r--r--tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr4
-rw-r--r--tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr4
-rw-r--r--tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr4
-rw-r--r--tests/ui/macros/best-failure.rs2
-rw-r--r--tests/ui/macros/best-failure.stderr2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2021.stderr4
-rw-r--r--tests/ui/macros/expr_2021_inline_const.edi2024.stderr2
-rw-r--r--tests/ui/macros/expr_2021_inline_const.rs4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr4
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr2
-rw-r--r--tests/ui/macros/expr_2024_underscore_expr.rs4
-rw-r--r--tests/ui/macros/issue-118786.rs2
-rw-r--r--tests/ui/macros/issue-118786.stderr2
-rw-r--r--tests/ui/macros/issue-30007.rs2
-rw-r--r--tests/ui/macros/issue-30007.stderr2
-rw-r--r--tests/ui/macros/issue-54441.rs2
-rw-r--r--tests/ui/macros/issue-54441.stderr2
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.rs14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2015.stderr14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.rs14
-rw-r--r--tests/ui/macros/macro-at-most-once-rep-2018.stderr14
-rw-r--r--tests/ui/macros/macro-context.rs6
-rw-r--r--tests/ui/macros/macro-context.stderr6
-rw-r--r--tests/ui/macros/macro-in-expression-context.fixed2
-rw-r--r--tests/ui/macros/macro-in-expression-context.rs2
-rw-r--r--tests/ui/macros/macro-in-expression-context.stderr2
-rw-r--r--tests/ui/macros/macro-non-lifetime.rs2
-rw-r--r--tests/ui/macros/macro-non-lifetime.stderr2
-rw-r--r--tests/ui/macros/missing-comma.rs10
-rw-r--r--tests/ui/macros/missing-comma.stderr10
-rw-r--r--tests/ui/macros/nonterminal-matching.rs10
-rw-r--r--tests/ui/macros/nonterminal-matching.stderr14
-rw-r--r--tests/ui/macros/syntax-error-recovery.rs2
-rw-r--r--tests/ui/macros/syntax-error-recovery.stderr2
-rw-r--r--tests/ui/macros/trace_faulty_macros.stderr2
-rw-r--r--tests/ui/mir/mir_let_chains_drop_order.rs1
-rw-r--r--tests/ui/modules/issue-107649.stderr2
-rw-r--r--tests/ui/mut/mutable-enum-indirect.stderr2
-rw-r--r--tests/ui/nll/issue-54556-niconii.edition2021.stderr2
-rw-r--r--tests/ui/nll/issue-54556-niconii.rs2
-rw-r--r--tests/ui/no-send-res-ports.stderr2
-rw-r--r--tests/ui/no_send-enum.stderr2
-rw-r--r--tests/ui/no_share-enum.stderr2
-rw-r--r--tests/ui/not-clone-closure.stderr2
-rw-r--r--tests/ui/not-panic/not-panic-safe-2.stderr4
-rw-r--r--tests/ui/not-panic/not-panic-safe-3.stderr4
-rw-r--r--tests/ui/not-panic/not-panic-safe-4.stderr4
-rw-r--r--tests/ui/not-panic/not-panic-safe-5.stderr2
-rw-r--r--tests/ui/not-panic/not-panic-safe-6.stderr4
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.rs2
-rw-r--r--tests/ui/offset-of/offset-of-arg-count.stderr2
-rw-r--r--tests/ui/offset-of/offset-of-dst-field.stderr2
-rw-r--r--tests/ui/offset-of/offset-of-tuple.stderr2
-rw-r--r--tests/ui/on-unimplemented/slice-index.stderr4
-rw-r--r--tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs4
-rw-r--r--tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr4
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-1.rs2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-1.stderr2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-2.rs2
-rw-r--r--tests/ui/parser/macro/macro-doc-comments-2.stderr2
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.rs2
-rw-r--r--tests/ui/parser/macro/macro-expand-to-match-arm.stderr2
-rw-r--r--tests/ui/parser/macro/macro-incomplete-parse.rs4
-rw-r--r--tests/ui/parser/macro/macro-incomplete-parse.stderr4
-rw-r--r--tests/ui/parser/macro/trait-non-item-macros.rs2
-rw-r--r--tests/ui/parser/macro/trait-non-item-macros.stderr2
-rw-r--r--tests/ui/parser/struct-literal-in-for.stderr2
-rw-r--r--tests/ui/proc-macro/attr-invalid-exprs.rs4
-rw-r--r--tests/ui/proc-macro/attr-invalid-exprs.stderr4
-rw-r--r--tests/ui/proc-macro/expand-expr.rs4
-rw-r--r--tests/ui/proc-macro/expand-expr.stderr4
-rw-r--r--tests/ui/range/range-1.stderr2
-rw-r--r--tests/ui/recursion/recursive-requirements.stderr4
-rw-r--r--tests/ui/repr/repr_align_greater_usize.msp430.stderr19
-rw-r--r--tests/ui/repr/repr_align_greater_usize.rs25
-rw-r--r--tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs2
-rw-r--r--tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr20
-rw-r--r--tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs20
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-ice.rs2
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs-ice.stderr10
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.default.stderr162
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.feature.stderr176
-rw-r--r--tests/ui/self/arbitrary-self-from-method-substs.rs94
-rw-r--r--tests/ui/specialization/const_trait_impl.stderr24
-rw-r--r--tests/ui/specialization/min_specialization/issue-79224.stderr8
-rw-r--r--tests/ui/statics/unsized_type2.stderr4
-rw-r--r--tests/ui/statics/unsizing-wfcheck-issue-127299.stderr2
-rw-r--r--tests/ui/str/str-idx.stderr4
-rw-r--r--tests/ui/str/str-mut-idx.stderr4
-rw-r--r--tests/ui/suggestions/derive-clone-for-eq.stderr2
-rw-r--r--tests/ui/suggestions/derive-macro-missing-bounds.stderr10
-rw-r--r--tests/ui/suggestions/into-str.stderr2
-rw-r--r--tests/ui/suggestions/issue-71394-no-from-impl.stderr2
-rw-r--r--tests/ui/suggestions/issue-88696.stderr2
-rw-r--r--tests/ui/suggestions/issue-96223.stderr2
-rw-r--r--tests/ui/suggestions/issue-96555.stderr6
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr4
-rw-r--r--tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr4
-rw-r--r--tests/ui/suggestions/path-by-value.stderr2
-rw-r--r--tests/ui/suggestions/path-display.stderr2
-rw-r--r--tests/ui/suggestions/suggest-dereferencing-index.stderr2
-rw-r--r--tests/ui/suggestions/suggest-pin-macro.stderr2
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-1.stderr2
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-2.stderr2
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-3.stderr2
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-4.stderr2
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-5.stderr4
-rw-r--r--tests/ui/sync/mutexguard-sync.stderr2
-rw-r--r--tests/ui/sync/reentrantlockguard-sync.stderr2
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout46
-rw-r--r--tests/ui/trait-bounds/super-assoc-mismatch.stderr4
-rw-r--r--tests/ui/traits/alias/cross-crate.stderr4
-rw-r--r--tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr2
-rw-r--r--tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs2
-rw-r--r--tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr2
-rw-r--r--tests/ui/traits/const-traits/assoc-type.stderr2
-rw-r--r--tests/ui/traits/const-traits/call-generic-in-impl.stderr8
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-chain.stderr16
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr16
-rw-r--r--tests/ui/traits/const-traits/call-generic-method-pass.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr19
-rw-r--r--tests/ui/traits/const-traits/const-closure-parse-not-item.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-closure-trait-method.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-closures.stderr32
-rw-r--r--tests/ui/traits/const-traits/const-drop-bound.stderr24
-rw-r--r--tests/ui/traits/const-traits/const-drop-fail-2.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-drop-fail.precise.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-drop-fail.stock.stderr8
-rw-r--r--tests/ui/traits/const-traits/const-drop.precise.stderr36
-rw-r--r--tests/ui/traits/const-traits/const-drop.stock.stderr36
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr7
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-use.stderr7
-rw-r--r--tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr13
-rw-r--r--tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr15
-rw-r--r--tests/ui/traits/const-traits/effects/no-explicit-const-params.rs1
-rw-r--r--tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr14
-rw-r--r--tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr9
-rw-r--r--tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr11
-rw-r--r--tests/ui/traits/const-traits/effects/trait-fn-const.stderr7
-rw-r--r--tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr7
-rw-r--r--tests/ui/traits/const-traits/effects/with-without-next-solver.rs10
-rw-r--r--tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr7
-rw-r--r--tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr7
-rw-r--r--tests/ui/traits/const-traits/ice-120503-async-const-method.stderr7
-rw-r--r--tests/ui/traits/const-traits/ice-121536-const-method.stderr7
-rw-r--r--tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr15
-rw-r--r--tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr7
-rw-r--r--tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr7
-rw-r--r--tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr7
-rw-r--r--tests/ui/traits/const-traits/issue-92111.stderr8
-rw-r--r--tests/ui/traits/const-traits/item-bound-entailment-fails.stderr4
-rw-r--r--tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr8
-rw-r--r--tests/ui/traits/const-traits/predicate-entailment-fails.stderr12
-rw-r--r--tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr7
-rw-r--r--tests/ui/traits/const-traits/specializing-constness.stderr7
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr12
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr20
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr20
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr20
-rw-r--r--tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr8
-rw-r--r--tests/ui/traits/const-traits/tilde-const-and-const-params.rs2
-rw-r--r--tests/ui/traits/const-traits/tilde-const-and-const-params.stderr20
-rw-r--r--tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr2
-rw-r--r--tests/ui/traits/copy-impl-cannot-normalize.stderr2
-rw-r--r--tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr2
-rw-r--r--tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr2
-rw-r--r--tests/ui/traits/issue-43784-supertrait.stderr2
-rw-r--r--tests/ui/traits/issue-7013.stderr2
-rw-r--r--tests/ui/traits/issue-71036.stderr2
-rw-r--r--tests/ui/traits/issue-71136.stderr2
-rw-r--r--tests/ui/traits/issue-91594.stderr2
-rw-r--r--tests/ui/traits/issue-97576.stderr2
-rw-r--r--tests/ui/traits/negative-impls/negated-auto-traits-error.stderr6
-rw-r--r--tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr2
-rw-r--r--tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr2
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr2
-rw-r--r--tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr2
-rw-r--r--tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr2
-rw-r--r--tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr2
-rw-r--r--tests/ui/traits/next-solver/dyn-incompatibility.stderr4
-rw-r--r--tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr4
-rw-r--r--tests/ui/traits/question-mark-result-err-mismatch.stderr6
-rw-r--r--tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr2
-rw-r--r--tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr8
-rw-r--r--tests/ui/traits/suggest-dereferences/issue-39029.stderr2
-rw-r--r--tests/ui/traits/suggest-dereferences/root-obligation.stderr2
-rw-r--r--tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr2
-rw-r--r--tests/ui/traits/unsend-future.stderr2
-rw-r--r--tests/ui/try-block/try-block-bad-type.stderr2
-rw-r--r--tests/ui/try-trait/bad-interconversion.stderr2
-rw-r--r--tests/ui/try-trait/issue-32709.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/escaping-bound-var.rs1
-rw-r--r--tests/ui/type-alias-impl-trait/escaping-bound-var.stderr14
-rw-r--r--tests/ui/type-alias-impl-trait/issue-57700.rs21
-rw-r--r--tests/ui/type-alias-impl-trait/issue-57700.stderr8
-rw-r--r--tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/underconstrained_generic.stderr2
-rw-r--r--tests/ui/type-alias-impl-trait/variance.rs16
-rw-r--r--tests/ui/type-alias-impl-trait/variance.stderr16
-rw-r--r--tests/ui/type/issue-58355.stderr2
-rw-r--r--tests/ui/typeck/bad-index-due-to-nested.stderr4
-rw-r--r--tests/ui/typeck/issue-90101.stderr2
-rw-r--r--tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr2
-rw-r--r--tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr4
-rw-r--r--tests/ui/typeck/typeck-unsafe-always-share.stderr2
-rw-r--r--tests/ui/underscore-ident-matcher.rs2
-rw-r--r--tests/ui/underscore-ident-matcher.stderr2
-rw-r--r--tests/ui/union/projection-as-union-type-error-2.stderr2
-rw-r--r--tests/ui/unsized-locals/issue-50940-with-feature.stderr2
-rw-r--r--tests/ui/unsized-locals/rust-call.stderr2
-rw-r--r--tests/ui/unsized-locals/unsized-exprs.stderr6
-rw-r--r--tests/ui/unsized/unsized-enum2.stderr8
-rw-r--r--tests/ui/wf/hir-wf-check-erase-regions.stderr6
-rw-r--r--tests/ui/wf/wf-const-type.stderr6
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs4
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr10
-rw-r--r--tests/ui/wf/wf-static-type.stderr6
-rw-r--r--triagebot.toml7
1107 files changed, 16680 insertions, 10160 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 01e814e7d7f..fc16ccf0a67 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -720,6 +720,7 @@ dependencies = [
  "miropt-test-tools",
  "regex",
  "rustfix",
+ "semver",
  "serde",
  "serde_json",
  "tracing",
@@ -3301,6 +3302,7 @@ version = "0.0.0"
 dependencies = [
  "itertools",
  "rustc_ast",
+ "rustc_data_structures",
  "rustc_lexer",
  "rustc_span",
  "thin-vec",
@@ -3621,6 +3623,7 @@ version = "0.0.0"
 dependencies = [
  "annotate-snippets 0.11.4",
  "derive_setters",
+ "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
@@ -3718,6 +3721,7 @@ name = "rustc_hir_analysis"
 version = "0.0.0"
 dependencies = [
  "itertools",
+ "rustc_abi",
  "rustc_arena",
  "rustc_ast",
  "rustc_attr",
@@ -3906,6 +3910,7 @@ dependencies = [
 name = "rustc_lint"
 version = "0.0.0"
 dependencies = [
+ "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_attr",
@@ -3980,6 +3985,7 @@ dependencies = [
  "bitflags 2.6.0",
  "libloading",
  "odht",
+ "rustc_abi",
  "rustc_ast",
  "rustc_attr",
  "rustc_data_structures",
@@ -4074,6 +4080,7 @@ version = "0.0.0"
 dependencies = [
  "polonius-engine",
  "regex",
+ "rustc_abi",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4095,6 +4102,7 @@ version = "0.0.0"
 dependencies = [
  "either",
  "itertools",
+ "rustc_abi",
  "rustc_arena",
  "rustc_ast",
  "rustc_attr",
@@ -4187,6 +4195,7 @@ dependencies = [
 name = "rustc_passes"
 version = "0.0.0"
 dependencies = [
+ "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_attr",
@@ -4213,6 +4222,7 @@ name = "rustc_pattern_analysis"
 version = "0.0.0"
 dependencies = [
  "rustc-hash 2.0.0",
+ "rustc_abi",
  "rustc_apfloat",
  "rustc_arena",
  "rustc_data_structures",
@@ -4352,6 +4362,7 @@ dependencies = [
  "bitflags 2.6.0",
  "getopts",
  "libc",
+ "rustc_abi",
  "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
@@ -4415,6 +4426,7 @@ version = "0.0.0"
 dependencies = [
  "punycode",
  "rustc-demangle",
+ "rustc_abi",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hir",
@@ -4496,6 +4508,7 @@ name = "rustc_transmute"
 version = "0.0.0"
 dependencies = [
  "itertools",
+ "rustc_abi",
  "rustc_ast_ir",
  "rustc_data_structures",
  "rustc_hir",
@@ -4503,7 +4516,6 @@ dependencies = [
  "rustc_macros",
  "rustc_middle",
  "rustc_span",
- "rustc_target",
  "tracing",
 ]
 
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 0340d1bd6bc..86de39b8f97 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -7,7 +7,7 @@ use tracing::debug;
 
 use crate::{
     Abi, AbiAndPrefAlign, Align, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
-    LayoutS, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
+    LayoutData, Niche, NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding,
     Variants, WrappingRange,
 };
 
@@ -26,9 +26,9 @@ fn absent<'a, FieldIdx, VariantIdx, F>(fields: &IndexSlice<FieldIdx, F>) -> bool
 where
     FieldIdx: Idx,
     VariantIdx: Idx,
-    F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+    F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
 {
-    let uninhabited = fields.iter().any(|f| f.abi.is_uninhabited());
+    let uninhabited = fields.iter().any(|f| f.is_uninhabited());
     // We cannot ignore alignment; that might lead us to entirely discard a variant and
     // produce an enum that is less aligned than it should be!
     let is_1zst = fields.iter().all(|f| f.is_1zst());
@@ -89,7 +89,7 @@ impl<F> LayoutCalculatorError<F> {
 }
 
 type LayoutCalculatorResult<FieldIdx, VariantIdx, F> =
-    Result<LayoutS<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
+    Result<LayoutData<FieldIdx, VariantIdx>, LayoutCalculatorError<F>>;
 
 #[derive(Clone, Copy, Debug)]
 pub struct LayoutCalculator<Cx> {
@@ -105,7 +105,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         &self,
         a: Scalar,
         b: Scalar,
-    ) -> LayoutS<FieldIdx, VariantIdx> {
+    ) -> LayoutData<FieldIdx, VariantIdx> {
         let dl = self.cx.data_layout();
         let b_align = b.align(dl);
         let align = a.align(dl).max(b_align).max(dl.aggregate_align);
@@ -119,7 +119,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             .chain(Niche::from_scalar(dl, Size::ZERO, a))
             .max_by_key(|niche| niche.available(dl));
 
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary {
                 offsets: [Size::ZERO, b_offset].into(),
@@ -138,7 +138,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
@@ -211,9 +211,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
 
     pub fn layout_of_never_type<FieldIdx: Idx, VariantIdx: Idx>(
         &self,
-    ) -> LayoutS<FieldIdx, VariantIdx> {
+    ) -> LayoutData<FieldIdx, VariantIdx> {
         let dl = self.cx.data_layout();
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Uninhabited,
@@ -229,7 +229,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -292,7 +292,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -384,7 +384,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             return Err(LayoutCalculatorError::EmptyUnion);
         };
 
-        Ok(LayoutS {
+        Ok(LayoutData {
             variants: Variants::Single { index: only_variant_idx },
             fields: FieldsShape::Union(union_field_count),
             abi,
@@ -401,7 +401,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -501,7 +501,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         repr: &ReprOptions,
@@ -516,8 +516,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         // overall LayoutS. Store the overall LayoutS
         // and the variant LayoutSs here until then.
         struct TmpLayout<FieldIdx: Idx, VariantIdx: Idx> {
-            layout: LayoutS<FieldIdx, VariantIdx>,
-            variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
+            layout: LayoutData<FieldIdx, VariantIdx>,
+            variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
         }
 
         let dl = self.cx.data_layout();
@@ -649,7 +649,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
                 Abi::Aggregate { sized: true }
             };
 
-            let layout = LayoutS {
+            let layout = LayoutData {
                 variants: Variants::Multiple {
                     tag: niche_scalar,
                     tag_encoding: TagEncoding::Niche {
@@ -681,7 +681,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         let discr_type = repr.discr_type();
         let bits = Integer::from_attr(dl, discr_type).size().bits();
         for (i, mut val) in discriminants {
-            if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) {
+            if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
                 continue;
             }
             if discr_type.is_signed() {
@@ -958,7 +958,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
 
         let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
 
-        let tagged_layout = LayoutS {
+        let tagged_layout = LayoutData {
             variants: Variants::Multiple {
                 tag,
                 tag_encoding: TagEncoding::Direct,
@@ -1013,7 +1013,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug + Copy,
     >(
         &self,
         fields: &IndexSlice<FieldIdx, F>,
@@ -1341,7 +1341,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
             unadjusted_abi_align
         };
 
-        Ok(LayoutS {
+        Ok(LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Arbitrary { offsets, memory_index },
             abi,
@@ -1357,10 +1357,10 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
         'a,
         FieldIdx: Idx,
         VariantIdx: Idx,
-        F: Deref<Target = &'a LayoutS<FieldIdx, VariantIdx>> + fmt::Debug,
+        F: Deref<Target = &'a LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
     >(
         &self,
-        layout: &LayoutS<FieldIdx, VariantIdx>,
+        layout: &LayoutData<FieldIdx, VariantIdx>,
         fields: &IndexSlice<FieldIdx, F>,
     ) -> String {
         let dl = self.cx.data_layout();
diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs
index c6812c4d4c0..e029e1426b2 100644
--- a/compiler/rustc_abi/src/layout/ty.rs
+++ b/compiler/rustc_abi/src/layout/ty.rs
@@ -58,7 +58,7 @@ rustc_index::newtype_index! {
 }
 #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 #[rustc_pass_by_value]
-pub struct Layout<'a>(pub Interned<'a, LayoutS<FieldIdx, VariantIdx>>);
+pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
 
 impl<'a> fmt::Debug for Layout<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -68,8 +68,8 @@ impl<'a> fmt::Debug for Layout<'a> {
 }
 
 impl<'a> Deref for Layout<'a> {
-    type Target = &'a LayoutS<FieldIdx, VariantIdx>;
-    fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
+    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
+    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
         &self.0.0
     }
 }
@@ -142,8 +142,8 @@ impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
 }
 
 impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
-    type Target = &'a LayoutS<FieldIdx, VariantIdx>;
-    fn deref(&self) -> &&'a LayoutS<FieldIdx, VariantIdx> {
+    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
+    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
         &self.layout.0.0
     }
 }
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 8e90130da4c..41922aee648 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -1485,7 +1485,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
         tag: Scalar,
         tag_encoding: TagEncoding<VariantIdx>,
         tag_field: usize,
-        variants: IndexVec<VariantIdx, LayoutS<FieldIdx, VariantIdx>>,
+        variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
     },
 }
 
@@ -1603,7 +1603,7 @@ impl Niche {
 // NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
 #[derive(PartialEq, Eq, Hash, Clone)]
 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
-pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
+pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
     /// Says where the fields are located within the layout.
     pub fields: FieldsShape<FieldIdx>,
 
@@ -1643,7 +1643,7 @@ pub struct LayoutS<FieldIdx: Idx, VariantIdx: Idx> {
     pub unadjusted_abi_align: Align,
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
+impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     /// Returns `true` if this is an aggregate type (including a ScalarPair!)
     pub fn is_aggregate(&self) -> bool {
         match self.abi {
@@ -1652,11 +1652,16 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
         }
     }
 
+    /// Returns `true` if this is an uninhabited type
+    pub fn is_uninhabited(&self) -> bool {
+        self.abi.is_uninhabited()
+    }
+
     pub fn scalar<C: HasDataLayout>(cx: &C, scalar: Scalar) -> Self {
         let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
         let size = scalar.size(cx);
         let align = scalar.align(cx);
-        LayoutS {
+        LayoutData {
             variants: Variants::Single { index: VariantIdx::new(0) },
             fields: FieldsShape::Primitive,
             abi: Abi::Scalar(scalar),
@@ -1669,7 +1674,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
     }
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutS<FieldIdx, VariantIdx>
+impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
 where
     FieldsShape<FieldIdx>: fmt::Debug,
     Variants<FieldIdx, VariantIdx>: fmt::Debug,
@@ -1678,7 +1683,7 @@ where
         // This is how `Layout` used to print before it become
         // `Interned<LayoutS>`. We print it like this to avoid having to update
         // expected output in a lot of tests.
-        let LayoutS {
+        let LayoutData {
             size,
             align,
             abi,
@@ -1723,7 +1728,7 @@ pub struct PointeeInfo {
     pub safe: Option<PointerKind>,
 }
 
-impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
+impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
     /// Returns `true` if the layout corresponds to an unsized type.
     #[inline]
     pub fn is_unsized(&self) -> bool {
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 1d6abbef06c..3b9edef0615 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -368,7 +368,7 @@ impl Clone for TokenKind {
         // a copy. This is faster than the `derive(Clone)` version which has a
         // separate path for every variant.
         match self {
-            Interpolated(nt) => Interpolated(nt.clone()),
+            Interpolated(nt) => Interpolated(Lrc::clone(nt)),
             _ => unsafe { std::ptr::read(self) },
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 9d2b5690c23..20d3ce65fac 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -10,17 +10,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         b: &Block,
         targeted_by_break: bool,
     ) -> &'hir hir::Block<'hir> {
-        self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
+        let hir_id = self.lower_node_id(b.id);
+        self.arena.alloc(self.lower_block_noalloc(hir_id, b, targeted_by_break))
     }
 
     pub(super) fn lower_block_noalloc(
         &mut self,
+        hir_id: hir::HirId,
         b: &Block,
         targeted_by_break: bool,
     ) -> hir::Block<'hir> {
         let (stmts, expr) = self.lower_stmts(&b.stmts);
         let rules = self.lower_block_check_mode(&b.rules);
-        let hir_id = self.lower_node_id(b.id);
         hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 3b85f1737bd..70c94f4019a 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -259,10 +259,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         self_param_id: pat_node_id,
                     };
                     self_resolver.visit_block(block);
+                    // Target expr needs to lower `self` path.
+                    this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
                     this.lower_target_expr(&block)
                 } else {
-                    let pat_hir_id = this.lower_node_id(pat_node_id);
-                    this.generate_arg(pat_hir_id, span)
+                    this.generate_arg(param.pat.hir_id, span)
                 };
                 args.push(arg);
             }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a1a16d0ca26..b7cf2d252dc 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -3,6 +3,7 @@ use std::assert_matches::assert_matches;
 use rustc_ast::ptr::P as AstP;
 use rustc_ast::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::HirId;
 use rustc_hir::def::{DefKind, Res};
@@ -70,8 +71,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 _ => (),
             }
 
-            let hir_id = self.lower_node_id(e.id);
-            self.lower_attrs(hir_id, &e.attrs);
+            let expr_hir_id = self.lower_node_id(e.id);
+            self.lower_attrs(expr_hir_id, &e.attrs);
 
             let kind = match &e.kind {
                 ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
@@ -143,7 +144,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::IncludedBytes(bytes) => {
                     let lit = self.arena.alloc(respan(
                         self.lower_span(e.span),
-                        LitKind::ByteStr(bytes.clone(), StrStyle::Cooked),
+                        LitKind::ByteStr(Lrc::clone(bytes), StrStyle::Cooked),
                     ));
                     hir::ExprKind::Lit(lit)
                 }
@@ -175,18 +176,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::If(cond, then, else_opt) => {
                     self.lower_expr_if(cond, then, else_opt.as_deref())
                 }
-                ExprKind::While(cond, body, opt_label) => self.with_loop_scope(e.id, |this| {
-                    let span = this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
-                    this.lower_expr_while_in_loop_scope(span, cond, body, *opt_label)
-                }),
-                ExprKind::Loop(body, opt_label, span) => self.with_loop_scope(e.id, |this| {
-                    hir::ExprKind::Loop(
-                        this.lower_block(body, false),
-                        this.lower_label(*opt_label),
-                        hir::LoopSource::Loop,
-                        this.lower_span(*span),
-                    )
-                }),
+                ExprKind::While(cond, body, opt_label) => {
+                    self.with_loop_scope(expr_hir_id, |this| {
+                        let span =
+                            this.mark_span_with_reason(DesugaringKind::WhileLoop, e.span, None);
+                        let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
+                        this.lower_expr_while_in_loop_scope(span, cond, body, opt_label)
+                    })
+                }
+                ExprKind::Loop(body, opt_label, span) => {
+                    self.with_loop_scope(expr_hir_id, |this| {
+                        let opt_label = this.lower_label(*opt_label, e.id, expr_hir_id);
+                        hir::ExprKind::Loop(
+                            this.lower_block(body, false),
+                            opt_label,
+                            hir::LoopSource::Loop,
+                            this.lower_span(*span),
+                        )
+                    })
+                }
                 ExprKind::TryBlock(body) => self.lower_expr_try_block(body),
                 ExprKind::Match(expr, arms, kind) => hir::ExprKind::Match(
                     self.lower_expr(expr),
@@ -212,7 +220,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         binder,
                         *capture_clause,
                         e.id,
-                        hir_id,
+                        expr_hir_id,
                         *coroutine_kind,
                         fn_decl,
                         body,
@@ -223,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         binder,
                         *capture_clause,
                         e.id,
-                        hir_id,
+                        expr_hir_id,
                         *constness,
                         *movability,
                         fn_decl,
@@ -250,8 +258,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     )
                 }
                 ExprKind::Block(blk, opt_label) => {
-                    let opt_label = self.lower_label(*opt_label);
-                    hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
+                    // Different from loops, label of block resolves to block id rather than
+                    // expr node id.
+                    let block_hir_id = self.lower_node_id(blk.id);
+                    let opt_label = self.lower_label(*opt_label, blk.id, block_hir_id);
+                    let hir_block = self.arena.alloc(self.lower_block_noalloc(
+                        block_hir_id,
+                        blk,
+                        opt_label.is_some(),
+                    ));
+                    hir::ExprKind::Block(hir_block, opt_label)
                 }
                 ExprKind::Assign(el, er, span) => self.lower_expr_assign(el, er, *span, e.span),
                 ExprKind::AssignOp(op, el, er) => hir::ExprKind::AssignOp(
@@ -354,7 +370,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span),
             };
 
-            hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
+            hir::Expr { hir_id: expr_hir_id, kind, span: self.lower_span(e.span) }
         })
     }
 
@@ -504,7 +520,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let if_expr = self.expr(span, if_kind);
         let block = self.block_expr(self.arena.alloc(if_expr));
         let span = self.lower_span(span.with_hi(cond.span.hi()));
-        let opt_label = self.lower_label(opt_label);
         hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span)
     }
 
@@ -512,8 +527,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
     /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
     /// and save the block id to use it as a break target for desugaring of the `?` operator.
     fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
-        self.with_catch_scope(body.id, |this| {
-            let mut block = this.lower_block_noalloc(body, true);
+        let body_hir_id = self.lower_node_id(body.id);
+        self.with_catch_scope(body_hir_id, |this| {
+            let mut block = this.lower_block_noalloc(body_hir_id, body, true);
 
             // Final expression of the block (if present) or `()` with span at the end of block
             let (try_span, tail_expr) = if let Some(expr) = block.expr.take() {
@@ -521,7 +537,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     this.mark_span_with_reason(
                         DesugaringKind::TryBlock,
                         expr.span,
-                        Some(this.allow_try_trait.clone()),
+                        Some(Lrc::clone(&this.allow_try_trait)),
                     ),
                     expr,
                 )
@@ -529,7 +545,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let try_span = this.mark_span_with_reason(
                     DesugaringKind::TryBlock,
                     this.tcx.sess.source_map().end_point(body.span),
-                    Some(this.allow_try_trait.clone()),
+                    Some(Lrc::clone(&this.allow_try_trait)),
                 );
 
                 (try_span, this.expr_unit(try_span))
@@ -638,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let unstable_span = self.mark_span_with_reason(
                     DesugaringKind::Async,
                     self.lower_span(span),
-                    Some(self.allow_gen_future.clone()),
+                    Some(Lrc::clone(&self.allow_gen_future)),
                 );
                 let resume_ty =
                     self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
@@ -724,7 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let unstable_span = self.mark_span_with_reason(
                 DesugaringKind::Async,
                 span,
-                Some(self.allow_gen_future.clone()),
+                Some(Lrc::clone(&self.allow_gen_future)),
             );
             self.lower_attrs(inner_hir_id, &[Attribute {
                 kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
@@ -800,13 +816,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let features = match await_kind {
             FutureKind::Future => None,
-            FutureKind::AsyncIterator => Some(self.allow_for_await.clone()),
+            FutureKind::AsyncIterator => Some(Lrc::clone(&self.allow_for_await)),
         };
         let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, features);
         let gen_future_span = self.mark_span_with_reason(
             DesugaringKind::Await,
             full_span,
-            Some(self.allow_gen_future.clone()),
+            Some(Lrc::clone(&self.allow_gen_future)),
         );
         let expr_hir_id = expr.hir_id;
 
@@ -869,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
             let ready_field = self.single_pat_field(gen_future_span, x_pat);
             let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field);
-            let break_x = self.with_loop_scope(loop_node_id, move |this| {
+            let break_x = self.with_loop_scope(loop_hir_id, move |this| {
                 let expr_break =
                     hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
                 this.arena.alloc(this.expr(gen_future_span, expr_break))
@@ -1101,8 +1117,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::CoroutineSource::Closure,
                     );
 
-                    let hir_id = this.lower_node_id(coroutine_kind.closure_id());
-                    this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
+                    this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id);
 
                     (parameters, expr)
                 });
@@ -1465,8 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
         )
     }
 
-    fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> {
+    // Record labelled expr's HirId so that we can retrieve it in `lower_jump_destination` without
+    // lowering node id again.
+    fn lower_label(
+        &mut self,
+        opt_label: Option<Label>,
+        dest_id: NodeId,
+        dest_hir_id: hir::HirId,
+    ) -> Option<Label> {
         let label = opt_label?;
+        self.ident_and_label_to_local_id.insert(dest_id, dest_hir_id.local_id);
         Some(Label { ident: self.lower_ident(label.ident) })
     }
 
@@ -1474,17 +1497,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let target_id = match destination {
             Some((id, _)) => {
                 if let Some(loop_id) = self.resolver.get_label_res(id) {
-                    Ok(self.lower_node_id(loop_id))
+                    let local_id = self.ident_and_label_to_local_id[&loop_id];
+                    let loop_hir_id = HirId { owner: self.current_hir_id_owner, local_id };
+                    Ok(loop_hir_id)
                 } else {
                     Err(hir::LoopIdError::UnresolvedLabel)
                 }
             }
-            None => self
-                .loop_scope
-                .map(|id| Ok(self.lower_node_id(id)))
-                .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)),
+            None => {
+                self.loop_scope.map(|id| Ok(id)).unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
+            }
         };
-        let label = self.lower_label(destination.map(|(_, label)| label));
+        let label = destination
+            .map(|(_, label)| label)
+            .map(|label| Label { ident: self.lower_ident(label.ident) });
         hir::Destination { label, target_id }
     }
 
@@ -1499,14 +1525,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    fn with_catch_scope<T>(&mut self, catch_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+    fn with_catch_scope<T>(&mut self, catch_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
         let old_scope = self.catch_scope.replace(catch_id);
         let result = f(self);
         self.catch_scope = old_scope;
         result
     }
 
-    fn with_loop_scope<T>(&mut self, loop_id: NodeId, f: impl FnOnce(&mut Self) -> T) -> T {
+    fn with_loop_scope<T>(&mut self, loop_id: hir::HirId, f: impl FnOnce(&mut Self) -> T) -> T {
         // We're no longer in the base loop's condition; we're in another loop.
         let was_in_loop_condition = self.is_in_loop_condition;
         self.is_in_loop_condition = false;
@@ -1658,9 +1684,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let head_span = self.mark_span_with_reason(DesugaringKind::ForLoop, head.span, None);
         let pat_span = self.mark_span_with_reason(DesugaringKind::ForLoop, pat.span, None);
 
+        let loop_hir_id = self.lower_node_id(e.id);
+        let label = self.lower_label(opt_label, e.id, loop_hir_id);
+
         // `None => break`
         let none_arm = {
-            let break_expr = self.with_loop_scope(e.id, |this| this.expr_break_alloc(for_span));
+            let break_expr =
+                self.with_loop_scope(loop_hir_id, |this| this.expr_break_alloc(for_span));
             let pat = self.pat_none(for_span);
             self.arm(pat, break_expr)
         };
@@ -1668,7 +1698,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // Some(<pat>) => <body>,
         let some_arm = {
             let some_pat = self.pat_some(pat_span, pat);
-            let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
+            let body_block =
+                self.with_loop_scope(loop_hir_id, |this| this.lower_block(body, false));
             let body_expr = self.arena.alloc(self.expr_block(body_block));
             self.arm(some_pat, body_expr)
         };
@@ -1722,12 +1753,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `[opt_ident]: loop { ... }`
         let kind = hir::ExprKind::Loop(
             loop_block,
-            self.lower_label(opt_label),
+            label,
             hir::LoopSource::ForLoop,
             self.lower_span(for_span.with_hi(head.span.hi())),
         );
-        let loop_expr =
-            self.arena.alloc(hir::Expr { hir_id: self.lower_node_id(e.id), kind, span: for_span });
+        let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind, span: for_span });
 
         // `mut iter => { ... }`
         let iter_arm = self.arm(iter_pat, loop_expr);
@@ -1812,13 +1842,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let unstable_span = self.mark_span_with_reason(
             DesugaringKind::QuestionMark,
             span,
-            Some(self.allow_try_trait.clone()),
+            Some(Lrc::clone(&self.allow_try_trait)),
         );
         let try_span = self.tcx.sess.source_map().end_point(span);
         let try_span = self.mark_span_with_reason(
             DesugaringKind::QuestionMark,
             try_span,
-            Some(self.allow_try_trait.clone()),
+            Some(Lrc::clone(&self.allow_try_trait)),
         );
 
         // `Try::branch(<expr>)`
@@ -1867,8 +1897,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self.arena.alloc(residual_expr),
                 unstable_span,
             );
-            let ret_expr = if let Some(catch_node) = self.catch_scope {
-                let target_id = Ok(self.lower_node_id(catch_node));
+            let ret_expr = if let Some(catch_id) = self.catch_scope {
+                let target_id = Ok(catch_id);
                 self.arena.alloc(self.expr(
                     try_span,
                     hir::ExprKind::Break(
@@ -1912,7 +1942,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let unstable_span = self.mark_span_with_reason(
             DesugaringKind::YeetExpr,
             span,
-            Some(self.allow_try_trait.clone()),
+            Some(Lrc::clone(&self.allow_try_trait)),
         );
 
         let from_yeet_expr = self.wrap_in_try_constructor(
@@ -1922,8 +1952,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             yeeted_span,
         );
 
-        if let Some(catch_node) = self.catch_scope {
-            let target_id = Ok(self.lower_node_id(catch_node));
+        if let Some(catch_id) = self.catch_scope {
+            let target_id = Ok(catch_id);
             hir::ExprKind::Break(hir::Destination { label: None, target_id }, Some(from_yeet_expr))
         } else {
             hir::ExprKind::Ret(Some(from_yeet_expr))
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 97fa90d340e..d7245607501 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -154,7 +154,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
         let mut ident = i.ident;
         let vis_span = self.lower_span(i.vis.span);
-        let hir_id = self.lower_node_id(i.id);
+        let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
         let attrs = self.lower_attrs(hir_id, &i.attrs);
         let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
         let item = hir::Item {
@@ -604,7 +604,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
-        let hir_id = self.lower_node_id(i.id);
+        let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
         let owner_id = hir_id.expect_owner();
         self.lower_attrs(hir_id, &i.attrs);
         let item = hir::ForeignItem {
@@ -728,7 +728,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
-        let hir_id = self.lower_node_id(i.id);
+        let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
         self.lower_attrs(hir_id, &i.attrs);
         let trait_item_def_id = hir_id.expect_owner();
 
@@ -858,7 +858,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // Since `default impl` is not yet implemented, this is always true in impls.
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
-        let hir_id = self.lower_node_id(i.id);
+        let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
         self.lower_attrs(hir_id, &i.attrs);
 
         let (generics, kind) = match &i.kind {
@@ -1086,7 +1086,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             );
 
             // FIXME(async_fn_track_caller): Can this be moved above?
-            let hir_id = this.lower_node_id(coroutine_kind.closure_id());
+            let hir_id = expr.hir_id;
             this.maybe_forward_track_caller(body.span, fn_id, hir_id);
 
             (parameters, expr)
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 34b8137aea8..e1ee3d0af49 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -40,23 +40,19 @@
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
-use std::collections::hash_map::Entry;
-
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, *};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
+use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
 use rustc_hir::{
-    self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind,
-    ParamName, TraitCandidate,
+    self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate,
 };
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::extension;
@@ -85,7 +81,6 @@ mod expr;
 mod format;
 mod index;
 mod item;
-mod lifetime_collector;
 mod pat;
 mod path;
 
@@ -115,8 +110,8 @@ struct LoweringContext<'a, 'hir> {
     /// outside of an `async fn`.
     current_item: Option<Span>,
 
-    catch_scope: Option<NodeId>,
-    loop_scope: Option<NodeId>,
+    catch_scope: Option<HirId>,
+    loop_scope: Option<HirId>,
     is_in_loop_condition: bool,
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
@@ -140,7 +135,10 @@ struct LoweringContext<'a, 'hir> {
     impl_trait_defs: Vec<hir::GenericParam<'hir>>,
     impl_trait_bounds: Vec<hir::WherePredicate<'hir>>,
 
-    /// NodeIds that are lowered inside the current HIR owner.
+    /// NodeIds of pattern identifiers and labelled nodes that are lowered inside the current HIR owner.
+    ident_and_label_to_local_id: NodeMap<hir::ItemLocalId>,
+    /// NodeIds that are lowered inside the current HIR owner. Only used for duplicate lowering check.
+    #[cfg(debug_assertions)]
     node_id_to_local_id: NodeMap<hir::ItemLocalId>,
 
     allow_try_trait: Lrc<[Symbol]>,
@@ -148,12 +146,6 @@ struct LoweringContext<'a, 'hir> {
     allow_async_iterator: Lrc<[Symbol]>,
     allow_for_await: Lrc<[Symbol]>,
     allow_async_fn_traits: Lrc<[Symbol]>,
-
-    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
-    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
-    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
-    /// field from the original parameter 'a to the new parameter 'a1.
-    generics_def_id_map: Vec<LocalDefIdMap<LocalDefId>>,
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
@@ -171,6 +163,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             current_hir_id_owner: hir::CRATE_OWNER_ID,
             current_def_id_parent: CRATE_DEF_ID,
             item_local_id_counter: hir::ItemLocalId::ZERO,
+            ident_and_label_to_local_id: Default::default(),
+            #[cfg(debug_assertions)]
             node_id_to_local_id: Default::default(),
             trait_map: Default::default(),
 
@@ -196,7 +190,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
             // interact with `gen`/`async gen` blocks
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
-            generics_def_id_map: Default::default(),
         }
     }
 
@@ -525,54 +518,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
     /// resolver (if any).
-    fn orig_opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver.node_id_to_def_id.get(&node).copied()
-    }
-
-    /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
-    /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
-    ///
-    /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
-    /// invoking with the id from the `ast::Lifetime` node found inside
-    /// the `&'a u32` type would return the `LocalDefId` of the
-    /// `'a` parameter declared on `foo`.
-    ///
-    /// This function also applies remapping from `get_remapped_def_id`.
-    /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth.
-    /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`,
-    /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
-    /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.orig_opt_local_def_id(node).map(|local_def_id| self.get_remapped_def_id(local_def_id))
+        self.resolver.node_id_to_def_id.get(&node).copied()
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
         self.opt_local_def_id(node).unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
     }
 
-    /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
-    /// `generics_def_id_map` field.
-    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId {
-        // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
-        // push new mappings, so we first need to get the latest (innermost) mappings, hence `iter().rev()`.
-        //
-        // Consider:
-        //
-        // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
-        //
-        // We would end with a generics_def_id_map like:
-        //
-        // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
-        //
-        // for the opaque type generated on `impl Sized + 'b`, we want the result to be: impl_sized#'b.
-        // So, if we were trying to find first from the start (outermost) would give the wrong result, impl_trait#'b.
-        self.generics_def_id_map
-            .iter()
-            .rev()
-            .find_map(|map| map.get(&local_def_id).copied())
-            .unwrap_or(local_def_id)
-    }
-
     /// Freshen the `LoweringContext` and ready it to lower a nested item.
     /// The lowered item is registered into `self.children`.
     ///
@@ -588,7 +541,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         let current_attrs = std::mem::take(&mut self.attrs);
         let current_bodies = std::mem::take(&mut self.bodies);
-        let current_node_ids = std::mem::take(&mut self.node_id_to_local_id);
+        let current_ident_and_label_to_local_id =
+            std::mem::take(&mut self.ident_and_label_to_local_id);
+
+        #[cfg(debug_assertions)]
+        let current_node_id_to_local_id = std::mem::take(&mut self.node_id_to_local_id);
         let current_trait_map = std::mem::take(&mut self.trait_map);
         let current_owner =
             std::mem::replace(&mut self.current_hir_id_owner, hir::OwnerId { def_id });
@@ -602,8 +559,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // and the caller to refer to some of the subdefinitions' nodes' `LocalDefId`s.
 
         // Always allocate the first `HirId` for the owner itself.
-        let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
-        debug_assert_eq!(_old, None);
+        #[cfg(debug_assertions)]
+        {
+            let _old = self.node_id_to_local_id.insert(owner, hir::ItemLocalId::ZERO);
+            debug_assert_eq!(_old, None);
+        }
 
         let item = self.with_def_id_parent(def_id, f);
         debug_assert_eq!(def_id, item.def_id().def_id);
@@ -614,7 +574,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         self.attrs = current_attrs;
         self.bodies = current_bodies;
-        self.node_id_to_local_id = current_node_ids;
+        self.ident_and_label_to_local_id = current_ident_and_label_to_local_id;
+
+        #[cfg(debug_assertions)]
+        {
+            self.node_id_to_local_id = current_node_id_to_local_id;
+        }
         self.trait_map = current_trait_map;
         self.current_hir_id_owner = current_owner;
         self.item_local_id_counter = current_local_counter;
@@ -632,27 +597,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         result
     }
 
-    /// Installs the remapping `remap` in scope while `f` is being executed.
-    /// This causes references to the `LocalDefId` keys to be changed to
-    /// refer to the values instead.
-    ///
-    /// The remapping is used when one piece of AST expands to multiple
-    /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`,
-    /// expands to both a function definition (`foo`) and a TAIT for the return value,
-    /// both of which have a lifetime parameter `'a`. The remapping allows us to
-    /// rewrite the `'a` in the return value to refer to the
-    /// `'a` declared on the TAIT, instead of the function.
-    fn with_remapping<R>(
-        &mut self,
-        remap: LocalDefIdMap<LocalDefId>,
-        f: impl FnOnce(&mut Self) -> R,
-    ) -> R {
-        self.generics_def_id_map.push(remap);
-        let res = f(self);
-        self.generics_def_id_map.pop();
-        res
-    }
-
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
@@ -680,39 +624,37 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
     }
 
-    /// This method allocates a new `HirId` for the given `NodeId` and stores it in
-    /// the `LoweringContext`'s `NodeId => HirId` map.
+    /// This method allocates a new `HirId` for the given `NodeId`.
     /// Take care not to call this method if the resulting `HirId` is then not
     /// actually used in the HIR, as that would trigger an assertion in the
     /// `HirIdValidator` later on, which makes sure that all `NodeId`s got mapped
-    /// properly. Calling the method twice with the same `NodeId` is fine though.
+    /// properly. Calling the method twice with the same `NodeId` is also forbidden.
     #[instrument(level = "debug", skip(self), ret)]
     fn lower_node_id(&mut self, ast_node_id: NodeId) -> HirId {
         assert_ne!(ast_node_id, DUMMY_NODE_ID);
 
-        match self.node_id_to_local_id.entry(ast_node_id) {
-            Entry::Occupied(o) => HirId { owner: self.current_hir_id_owner, local_id: *o.get() },
-            Entry::Vacant(v) => {
-                // Generate a new `HirId`.
-                let owner = self.current_hir_id_owner;
-                let local_id = self.item_local_id_counter;
-                let hir_id = HirId { owner, local_id };
-
-                v.insert(local_id);
-                self.item_local_id_counter.increment_by(1);
+        let owner = self.current_hir_id_owner;
+        let local_id = self.item_local_id_counter;
+        assert_ne!(local_id, hir::ItemLocalId::ZERO);
+        self.item_local_id_counter.increment_by(1);
+        let hir_id = HirId { owner, local_id };
 
-                assert_ne!(local_id, hir::ItemLocalId::ZERO);
-                if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
-                    self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
-                }
+        if let Some(def_id) = self.opt_local_def_id(ast_node_id) {
+            self.children.push((def_id, hir::MaybeOwner::NonOwner(hir_id)));
+        }
 
-                if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
-                    self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
-                }
+        if let Some(traits) = self.resolver.trait_map.remove(&ast_node_id) {
+            self.trait_map.insert(hir_id.local_id, traits.into_boxed_slice());
+        }
 
-                hir_id
-            }
+        // Check whether the same `NodeId` is lowered more than once.
+        #[cfg(debug_assertions)]
+        {
+            let old = self.node_id_to_local_id.insert(ast_node_id, local_id);
+            assert_eq!(old, None);
         }
+
+        hir_id
     }
 
     /// Generate a new `HirId` without a backing `NodeId`.
@@ -729,7 +671,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_res(&mut self, res: Res<NodeId>) -> Res {
         let res: Result<Res, ()> = res.apply_id(|id| {
             let owner = self.current_hir_id_owner;
-            let local_id = self.node_id_to_local_id.get(&id).copied().ok_or(())?;
+            let local_id = self.ident_and_label_to_local_id.get(&id).copied().ok_or(())?;
             Ok(HirId { owner, local_id })
         });
         trace!(?res);
@@ -1486,27 +1428,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // frequently opened issues show.
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
-        // Whether this opaque always captures lifetimes in scope.
-        // Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
-        // is enabled. We don't check the span of the edition, since this is done
-        // on a per-opaque basis to account for nested opaques.
-        let always_capture_in_scope = match origin {
-            _ if self.tcx.features().lifetime_capture_rules_2024() => true,
-            hir::OpaqueTyOrigin::TyAlias { .. } => true,
-            hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
-            hir::OpaqueTyOrigin::AsyncFn { .. } => {
-                unreachable!("should be using `lower_coroutine_fn_ret_ty`")
-            }
-        };
-        let captured_lifetimes_to_duplicate = lifetime_collector::lifetimes_for_opaque(
-            self.resolver,
-            always_capture_in_scope,
-            opaque_ty_node_id,
-            bounds,
-            span,
-        );
-        debug!(?captured_lifetimes_to_duplicate);
-
         // Feature gate for RPITIT + use<..>
         match origin {
             rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => {
@@ -1529,22 +1450,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             _ => {}
         }
 
-        self.lower_opaque_inner(
-            opaque_ty_node_id,
-            origin,
-            captured_lifetimes_to_duplicate,
-            span,
-            opaque_ty_span,
-            |this| this.lower_param_bounds(bounds, itctx),
-        )
+        self.lower_opaque_inner(opaque_ty_node_id, origin, opaque_ty_span, |this| {
+            this.lower_param_bounds(bounds, itctx)
+        })
     }
 
     fn lower_opaque_inner(
         &mut self,
         opaque_ty_node_id: NodeId,
         origin: hir::OpaqueTyOrigin,
-        captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
-        span: Span,
         opaque_ty_span: Span,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
@@ -1552,145 +1466,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_hir_id = self.lower_node_id(opaque_ty_node_id);
         debug!(?opaque_ty_def_id, ?opaque_ty_hir_id);
 
-        // Map from captured (old) lifetime to synthetic (new) lifetime.
-        // Used to resolve lifetimes in the bounds of the opaque.
-        let mut captured_to_synthesized_mapping = LocalDefIdMap::default();
-        // List of (early-bound) synthetic lifetimes that are owned by the opaque.
-        // This is used to create the `hir::Generics` owned by the opaque.
-        let mut synthesized_lifetime_definitions = vec![];
-        // Pairs of lifetime arg (that resolves to the captured lifetime)
-        // and the def-id of the (early-bound) synthetic lifetime definition.
-        // This is used both to create generics for the `TyKind::OpaqueDef` that
-        // we return, and also as a captured lifetime mapping for RPITITs.
-        let mut synthesized_lifetime_args = vec![];
-
-        for lifetime in captured_lifetimes_to_duplicate {
-            let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
-            let (old_def_id, missing_kind) = match res {
-                LifetimeRes::Param { param: old_def_id, binder: _ } => (old_def_id, None),
-
-                LifetimeRes::Fresh { param, kind, .. } => {
-                    debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
-                    if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
-                        (old_def_id, Some(kind))
-                    } else {
-                        self.dcx()
-                            .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
-                        continue;
-                    }
-                }
-
-                // Opaques do not capture `'static`
-                LifetimeRes::Static { .. } | LifetimeRes::Error => {
-                    continue;
-                }
-
-                res => {
-                    let bug_msg = format!(
-                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
-                        res, lifetime.ident, lifetime.ident.span
-                    );
-                    span_bug!(lifetime.ident.span, "{}", bug_msg);
-                }
-            };
-
-            if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
-                // Create a new lifetime parameter local to the opaque.
-                let duplicated_lifetime_node_id = self.next_node_id();
-                let duplicated_lifetime_def_id = self.create_def(
-                    opaque_ty_def_id,
-                    duplicated_lifetime_node_id,
-                    lifetime.ident.name,
-                    DefKind::LifetimeParam,
-                    self.lower_span(lifetime.ident.span),
-                );
-                captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
-                // FIXME: Instead of doing this, we could move this whole loop
-                // into the `with_hir_id_owner`, then just directly construct
-                // the `hir::GenericParam` here.
-                synthesized_lifetime_definitions.push((
-                    duplicated_lifetime_node_id,
-                    duplicated_lifetime_def_id,
-                    self.lower_ident(lifetime.ident),
-                    missing_kind,
-                ));
-
-                // Now make an arg that we can use for the generic params of the opaque tykind.
-                let id = self.next_node_id();
-                let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
-                let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
-                synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
-            }
-        }
-
         let opaque_ty_def = self.with_def_id_parent(opaque_ty_def_id, |this| {
-            // Install the remapping from old to new (if any). This makes sure that
-            // any lifetimes that would have resolved to the def-id of captured
-            // lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
-            let bounds = this
-                .with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
-
-            let generic_params =
-                this.arena.alloc_from_iter(synthesized_lifetime_definitions.iter().map(
-                    |&(new_node_id, new_def_id, ident, missing_kind)| {
-                        let hir_id = this.lower_node_id(new_node_id);
-                        let (name, kind) = if ident.name == kw::UnderscoreLifetime {
-                            (
-                                hir::ParamName::Fresh,
-                                hir::LifetimeParamKind::Elided(
-                                    missing_kind.unwrap_or(MissingLifetimeKind::Underscore),
-                                ),
-                            )
-                        } else {
-                            (hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
-                        };
-
-                        hir::GenericParam {
-                            hir_id,
-                            def_id: new_def_id,
-                            name,
-                            span: ident.span,
-                            pure_wrt_drop: false,
-                            kind: hir::GenericParamKind::Lifetime { kind },
-                            colon_span: None,
-                            source: hir::GenericParamSource::Generics,
-                        }
-                    },
-                ));
-            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-            let lifetime_mapping = self.arena.alloc_slice(&synthesized_lifetime_args);
-
-            trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
+            let bounds = lower_item_bounds(this);
             let opaque_ty_def = hir::OpaqueTy {
                 hir_id: opaque_ty_hir_id,
                 def_id: opaque_ty_def_id,
-                generics: this.arena.alloc(hir::Generics {
-                    params: generic_params,
-                    predicates: &[],
-                    has_where_clause_predicates: false,
-                    where_clause_span: this.lower_span(span),
-                    span: this.lower_span(span),
-                }),
                 bounds,
                 origin,
-                lifetime_mapping,
                 span: this.lower_span(opaque_ty_span),
             };
             this.arena.alloc(opaque_ty_def)
         });
 
-        let generic_args = self.arena.alloc_from_iter(
-            synthesized_lifetime_args
-                .iter()
-                .map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
-        );
-
-        // Create the `Foo<...>` reference itself. Note that the `type
-        // Foo = impl Trait` is, internally, created as a child of the
-        // async fn, so the *type parameters* are inherited. It's
-        // only the lifetime parameters that we must supply.
-        hir::TyKind::OpaqueDef(opaque_ty_def, generic_args)
+        hir::TyKind::OpaqueDef(opaque_ty_def)
     }
 
     fn lower_precise_capturing_args(
@@ -1865,20 +1653,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             CoroutineKind::Async { return_impl_trait_id, .. } => (return_impl_trait_id, None),
             CoroutineKind::Gen { return_impl_trait_id, .. } => (return_impl_trait_id, None),
             CoroutineKind::AsyncGen { return_impl_trait_id, .. } => {
-                (return_impl_trait_id, Some(self.allow_async_iterator.clone()))
+                (return_impl_trait_id, Some(Lrc::clone(&self.allow_async_iterator)))
             }
         };
 
         let opaque_ty_span =
             self.mark_span_with_reason(DesugaringKind::Async, span, allowed_features);
 
-        let captured_lifetimes = self
-            .resolver
-            .extra_lifetime_params(opaque_ty_node_id)
-            .into_iter()
-            .map(|(ident, id, _)| Lifetime { id, ident })
-            .collect();
-
         let in_trait_or_impl = match fn_kind {
             FnDeclKind::Trait => Some(hir::RpitContext::Trait),
             FnDeclKind::Impl => Some(hir::RpitContext::TraitImpl),
@@ -1889,8 +1670,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_ref = self.lower_opaque_inner(
             opaque_ty_node_id,
             hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, in_trait_or_impl },
-            captured_lifetimes,
-            span,
             opaque_ty_span,
             |this| {
                 let bound = this.lower_coroutine_fn_output_type_to_bound(
@@ -1987,10 +1766,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         res: LifetimeRes,
     ) -> &'hir hir::Lifetime {
         let res = match res {
-            LifetimeRes::Param { param, .. } => {
-                let param = self.get_remapped_def_id(param);
-                hir::LifetimeName::Param(param)
-            }
+            LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
             LifetimeRes::Fresh { param, .. } => {
                 let param = self.local_def_id(param);
                 hir::LifetimeName::Param(param)
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
deleted file mode 100644
index 8d47c856bdd..00000000000
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
-use rustc_ast::{
-    GenericBound, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind,
-};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_hir::def::{DefKind, LifetimeRes, Res};
-use rustc_middle::span_bug;
-use rustc_middle::ty::ResolverAstLowering;
-use rustc_span::Span;
-use rustc_span::symbol::{Ident, kw};
-
-use super::ResolverAstLoweringExt;
-
-struct LifetimeCollectVisitor<'ast> {
-    resolver: &'ast mut ResolverAstLowering,
-    always_capture_in_scope: bool,
-    current_binders: Vec<NodeId>,
-    collected_lifetimes: FxIndexSet<Lifetime>,
-}
-
-impl<'ast> LifetimeCollectVisitor<'ast> {
-    fn new(resolver: &'ast mut ResolverAstLowering, always_capture_in_scope: bool) -> Self {
-        Self {
-            resolver,
-            always_capture_in_scope,
-            current_binders: Vec::new(),
-            collected_lifetimes: FxIndexSet::default(),
-        }
-    }
-
-    fn visit_opaque(&mut self, opaque_ty_node_id: NodeId, bounds: &'ast GenericBounds, span: Span) {
-        // If we're edition 2024 or within a TAIT or RPITIT, *and* there is no
-        // `use<>` statement to override the default capture behavior, then
-        // capture all of the in-scope lifetimes.
-        if (self.always_capture_in_scope || span.at_least_rust_2024())
-            && bounds.iter().all(|bound| !matches!(bound, GenericBound::Use(..)))
-        {
-            for (ident, id, _) in self.resolver.extra_lifetime_params(opaque_ty_node_id) {
-                self.record_lifetime_use(Lifetime { id, ident });
-            }
-        }
-
-        // We also recurse on the bounds to make sure we capture all the lifetimes
-        // mentioned in the bounds. These may disagree with the `use<>` list, in which
-        // case we will error on these later. We will also recurse to visit any
-        // nested opaques, which may *implicitly* capture lifetimes.
-        for bound in bounds {
-            self.visit_param_bound(bound, BoundKind::Bound);
-        }
-    }
-
-    fn record_lifetime_use(&mut self, lifetime: Lifetime) {
-        match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
-            LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
-                if !self.current_binders.contains(&binder) {
-                    self.collected_lifetimes.insert(lifetime);
-                }
-            }
-            LifetimeRes::Static { .. } | LifetimeRes::Error => {
-                self.collected_lifetimes.insert(lifetime);
-            }
-            LifetimeRes::Infer => {}
-            res => {
-                let bug_msg = format!(
-                    "Unexpected lifetime resolution {:?} for {:?} at {:?}",
-                    res, lifetime.ident, lifetime.ident.span
-                );
-                span_bug!(lifetime.ident.span, "{}", bug_msg);
-            }
-        }
-    }
-
-    /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
-    /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
-    /// in the list start..end.
-    fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
-        if let Some(LifetimeRes::ElidedAnchor { start, end }) =
-            self.resolver.get_lifetime_res(node_id)
-        {
-            for i in start..end {
-                let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
-                self.record_lifetime_use(lifetime);
-            }
-        }
-    }
-}
-
-impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
-    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
-        self.record_lifetime_use(*lifetime);
-    }
-
-    fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) {
-        self.record_elided_anchor(path_segment.id, path_segment.ident.span);
-        visit::walk_path_segment(self, path_segment);
-    }
-
-    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
-        self.current_binders.push(t.trait_ref.ref_id);
-
-        visit::walk_poly_trait_ref(self, t);
-
-        self.current_binders.pop();
-    }
-
-    fn visit_ty(&mut self, t: &'ast Ty) {
-        match &t.kind {
-            TyKind::Path(None, _) => {
-                // We can sometimes encounter bare trait objects
-                // which are represented in AST as paths.
-                if let Some(partial_res) = self.resolver.get_partial_res(t.id)
-                    && let Some(Res::Def(DefKind::Trait | DefKind::TraitAlias, _)) =
-                        partial_res.full_res()
-                {
-                    self.current_binders.push(t.id);
-                    visit::walk_ty(self, t);
-                    self.current_binders.pop();
-                } else {
-                    visit::walk_ty(self, t);
-                }
-            }
-            TyKind::BareFn(_) => {
-                self.current_binders.push(t.id);
-                visit::walk_ty(self, t);
-                self.current_binders.pop();
-            }
-            TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => {
-                self.record_elided_anchor(t.id, t.span);
-                visit::walk_ty(self, t);
-            }
-            TyKind::ImplTrait(opaque_ty_node_id, bounds) => {
-                self.visit_opaque(*opaque_ty_node_id, bounds, t.span)
-            }
-            _ => {
-                visit::walk_ty(self, t);
-            }
-        }
-    }
-}
-
-pub(crate) fn lifetimes_for_opaque(
-    resolver: &mut ResolverAstLowering,
-    always_capture_in_scope: bool,
-    opaque_ty_node_id: NodeId,
-    bounds: &GenericBounds,
-    span: Span,
-) -> FxIndexSet<Lifetime> {
-    let mut visitor = LifetimeCollectVisitor::new(resolver, always_capture_in_scope);
-    visitor.visit_opaque(opaque_ty_node_id, bounds, span);
-    visitor.collected_lifetimes
-}
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 760f84564f1..ace7bfb5c73 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -21,13 +21,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
         ensure_sufficient_stack(|| {
             // loop here to avoid recursion
+            let pat_hir_id = self.lower_node_id(pattern.id);
             let node = loop {
                 match &pattern.kind {
                     PatKind::Wild => break hir::PatKind::Wild,
                     PatKind::Never => break hir::PatKind::Never,
                     PatKind::Ident(binding_mode, ident, sub) => {
                         let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
-                        break self.lower_pat_ident(pattern, *binding_mode, *ident, lower_sub);
+                        break self.lower_pat_ident(
+                            pattern,
+                            *binding_mode,
+                            *ident,
+                            pat_hir_id,
+                            lower_sub,
+                        );
                     }
                     PatKind::Lit(e) => {
                         break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
@@ -119,7 +126,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 }
             };
 
-            self.pat_with_node_id_of(pattern, node)
+            self.pat_with_node_id_of(pattern, node, pat_hir_id)
         })
     }
 
@@ -187,10 +194,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut prev_rest_span = None;
 
         // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
-        let lower_rest_sub = |this: &mut Self, pat, &ann, &ident, sub| {
-            let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
-            let node = this.lower_pat_ident(pat, ann, ident, lower_sub);
-            this.pat_with_node_id_of(pat, node)
+        let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| {
+            let sub_hir_id = this.lower_node_id(sub.id);
+            let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id));
+            let pat_hir_id = this.lower_node_id(pat.id);
+            let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub);
+            this.pat_with_node_id_of(pat, node, pat_hir_id)
         };
 
         let mut iter = pats.iter();
@@ -200,7 +209,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
                 PatKind::Rest => {
                     prev_rest_span = Some(pat.span);
-                    slice = Some(self.pat_wild_with_node_id_of(pat));
+                    let hir_id = self.lower_node_id(pat.id);
+                    slice = Some(self.pat_wild_with_node_id_of(pat, hir_id));
                     break;
                 }
                 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
@@ -248,19 +258,35 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &Pat,
         annotation: BindingMode,
         ident: Ident,
+        hir_id: hir::HirId,
         lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
     ) -> hir::PatKind<'hir> {
         match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
             // `None` can occur in body-less function signatures
             res @ (None | Some(Res::Local(_))) => {
-                let canonical_id = match res {
-                    Some(Res::Local(id)) => id,
-                    _ => p.id,
+                let binding_id = match res {
+                    Some(Res::Local(id)) => {
+                        // In `Or` patterns like `VariantA(s) | VariantB(s, _)`, multiple identifier patterns
+                        // will be resolved to the same `Res::Local`. Thus they just share a single
+                        // `HirId`.
+                        if id == p.id {
+                            self.ident_and_label_to_local_id.insert(id, hir_id.local_id);
+                            hir_id
+                        } else {
+                            hir::HirId {
+                                owner: self.current_hir_id_owner,
+                                local_id: self.ident_and_label_to_local_id[&id],
+                            }
+                        }
+                    }
+                    _ => {
+                        self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id);
+                        hir_id
+                    }
                 };
-
                 hir::PatKind::Binding(
                     annotation,
-                    self.lower_node_id(canonical_id),
+                    binding_id,
                     self.lower_ident(ident),
                     lower_sub(self),
                 )
@@ -280,18 +306,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
-        self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
+    fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> {
+        self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id))
     }
 
-    /// Construct a `Pat` with the `HirId` of `p.id` lowered.
-    fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
-        hir::Pat {
-            hir_id: self.lower_node_id(p.id),
-            kind,
-            span: self.lower_span(p.span),
-            default_binding_modes: true,
-        }
+    /// Construct a `Pat` with the `HirId` of `p.id` already lowered.
+    fn pat_with_node_id_of(
+        &mut self,
+        p: &Pat,
+        kind: hir::PatKind<'hir>,
+        hir_id: hir::HirId,
+    ) -> hir::Pat<'hir> {
+        hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true }
     }
 
     /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 258655de486..133793e26ea 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -34,7 +34,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         modifiers: Option<ast::TraitBoundModifiers>,
     ) -> hir::QPath<'hir> {
         let qself_position = qself.as_ref().map(|q| q.position);
-        let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx));
+        let qself = qself
+            .as_ref()
+            // Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
+            .map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
 
         let partial_res =
             self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@@ -70,11 +73,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let bound_modifier_allowed_features = if let Res::Def(DefKind::Trait, async_def_id) = res
             && self.tcx.async_fn_trait_kind_from_def_id(async_def_id).is_some()
         {
-            Some(self.allow_async_fn_traits.clone())
+            Some(Lrc::clone(&self.allow_async_fn_traits))
         } else {
             None
         };
 
+        // Only permit `impl Trait` in the final segment. E.g., we permit `Option<impl Trait>`,
+        // `option::Option<T>::Xyz<impl Trait>` and reject `option::Option<impl Trait>::Xyz`.
+        let itctx = |i| {
+            if i + 1 == p.segments.len() {
+                itctx
+            } else {
+                ImplTraitContext::Disallowed(ImplTraitPosition::Path)
+            }
+        };
+
         let path_span_lo = p.span.shrink_to_lo();
         let proj_start = p.segments.len() - unresolved_segments;
         let path = self.arena.alloc(hir::Path {
@@ -121,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         segment,
                         param_mode,
                         generic_args_mode,
-                        itctx,
+                        itctx(i),
                         bound_modifier_allowed_features.clone(),
                     )
                 },
@@ -185,7 +198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 segment,
                 param_mode,
                 generic_args_mode,
-                itctx,
+                itctx(i),
                 None,
             ));
             let qpath = hir::QPath::TypeRelative(ty, hir_segment);
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 92acaaa5f36..d81fd53938b 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -146,8 +146,6 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
 
 ast_passes_generic_default_trailing = generic parameters with a default must be trailing
 
-ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
-
 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
     .help = remove one of these features
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 1d149e91b85..0a4f86d4822 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -80,10 +80,6 @@ struct AstValidator<'a> {
 
     disallow_tilde_const: Option<TildeConstReason>,
 
-    /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
-    /// or `Foo::Bar<impl Trait>`
-    is_impl_trait_banned: bool,
-
     /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
     extern_mod_safety: Option<Safety>,
 
@@ -123,12 +119,6 @@ impl<'a> AstValidator<'a> {
         self.extern_mod_safety = old;
     }
 
-    fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.is_impl_trait_banned, true);
-        f(self);
-        self.is_impl_trait_banned = old;
-    }
-
     fn with_tilde_const(
         &mut self,
         disallowed: Option<TildeConstReason>,
@@ -213,37 +203,6 @@ impl<'a> AstValidator<'a> {
                 .with_tilde_const(Some(TildeConstReason::TraitObject), |this| {
                     visit::walk_ty(this, t)
                 }),
-            TyKind::Path(qself, path) => {
-                // We allow these:
-                //  - `Option<impl Trait>`
-                //  - `option::Option<impl Trait>`
-                //  - `option::Option<T>::Foo<impl Trait>`
-                //
-                // But not these:
-                //  - `<impl Trait>::Foo`
-                //  - `option::Option<impl Trait>::Foo`.
-                //
-                // To implement this, we disallow `impl Trait` from `qself`
-                // (for cases like `<impl Trait>::Foo>`)
-                // but we allow `impl Trait` in `GenericArgs`
-                // iff there are no more PathSegments.
-                if let Some(qself) = qself {
-                    // `impl Trait` in `qself` is always illegal
-                    self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
-                }
-
-                // Note that there should be a call to visit_path here,
-                // so if any logic is added to process `Path`s a call to it should be
-                // added both in visit_path and here. This code mirrors visit::walk_path.
-                for (i, segment) in path.segments.iter().enumerate() {
-                    // Allow `impl Trait` iff we're on the final path segment
-                    if i == path.segments.len() - 1 {
-                        self.visit_path_segment(segment);
-                    } else {
-                        self.with_banned_impl_trait(|this| this.visit_path_segment(segment));
-                    }
-                }
-            }
             _ => visit::walk_ty(self, t),
         }
     }
@@ -737,10 +696,6 @@ impl<'a> AstValidator<'a> {
                 }
             }
             TyKind::ImplTrait(_, bounds) => {
-                if self.is_impl_trait_banned {
-                    self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
-                }
-
                 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
                     self.dcx().emit_err(errors::NestedImplTrait {
                         span: ty.span,
@@ -1729,7 +1684,6 @@ pub fn check_crate(
         has_proc_macro_decls: false,
         outer_impl_trait: None,
         disallow_tilde_const: Some(TildeConstReason::Item),
-        is_impl_trait_banned: false,
         extern_mod_safety: None,
         lint_buffer: lints,
     };
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 4ca1acde1e2..8c3ac9864ed 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -419,13 +419,6 @@ pub(crate) struct TraitObjectBound {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_impl_trait_path, code = E0667)]
-pub(crate) struct ImplTraitPath {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_nested_impl_trait, code = E0666)]
 pub(crate) struct NestedImplTrait {
     #[primary_span]
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 9ae5c9b3cec..f290fedcd8b 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 # tidy-alphabetical-start
 itertools = "0.12"
 rustc_ast = { path = "../rustc_ast" }
+rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_span = { path = "../rustc_span" }
 thin-vec = "0.2.12"
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 1e18f0779f0..de9f5187be7 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -21,6 +21,7 @@ use rustc_ast::{
     GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass,
     InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
 };
+use rustc_data_structures::sync::Lrc;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{Ident, IdentPrinter, Symbol, kw, sym};
@@ -105,7 +106,7 @@ fn split_block_comment_into_lines(text: &str, col: CharPos) -> Vec<String> {
 fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comment> {
     let sm = SourceMap::new(sm.path_mapping().clone());
     let source_file = sm.new_source_file(path, src);
-    let text = (*source_file.src.as_ref().unwrap()).clone();
+    let text = Lrc::clone(&(*source_file.src.as_ref().unwrap()));
 
     let text: &str = text.as_str();
     let start_bpos = source_file.start_pos;
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index b4b8373ac97..6ca7251295d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -830,7 +830,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
     ///
     /// [`OpaqueDef`]: hir::TyKind::OpaqueDef
     fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
-        let hir::TyKind::OpaqueDef(opaque_ty, _) = hir_ty.kind else {
+        let hir::TyKind::OpaqueDef(opaque_ty) = hir_ty.kind else {
             span_bug!(
                 hir_ty.span,
                 "lowered return type of async fn is not OpaqueDef: {:?}",
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 698fdafc936..efcee2899c6 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -34,7 +34,7 @@ use rustc_infer::infer::{
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::*;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
@@ -193,9 +193,7 @@ fn do_mir_borrowck<'tcx>(
         .map(|(idx, body)| (idx, MoveData::gather_moves(body, tcx, |_| true)));
 
     let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, Some("borrowck"))
         .into_results_cursor(body);
 
     let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
@@ -243,18 +241,21 @@ fn do_mir_borrowck<'tcx>(
     // usage significantly on some benchmarks.
     drop(flow_inits);
 
-    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
-    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
-    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data)
-        .into_engine(tcx, body)
-        .pass_name("borrowck")
-        .iterate_to_fixpoint();
+    let flow_borrows = Borrows::new(tcx, body, &regioncx, &borrow_set).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
+    let flow_ever_inits = EverInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(
+        tcx,
+        body,
+        Some("borrowck"),
+    );
 
     let movable_coroutine =
         // The first argument is the coroutine type passed by value
@@ -440,7 +441,7 @@ pub struct BorrowckInferCtxt<'tcx> {
 
 impl<'tcx> BorrowckInferCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
-        let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, def_id));
         BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) }
     }
 
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 3674053409b..f76603d5679 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -107,13 +107,13 @@ pub(crate) fn compute_regions<'a, 'tcx>(
             param_env,
             body,
             promoted,
-            universal_regions.clone(),
+            Rc::clone(&universal_regions),
             location_table,
             borrow_set,
             &mut all_facts,
             flow_inits,
             move_data,
-            elements.clone(),
+            Rc::clone(&elements),
             upvars,
         );
 
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index e85f529bf0e..d5c2796932e 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -733,7 +733,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         // Now take member constraints into account.
-        let member_constraints = self.member_constraints.clone();
+        let member_constraints = Rc::clone(&self.member_constraints);
         for m_c_i in member_constraints.indices(scc_a) {
             self.apply_member_constraint(scc_a, m_c_i, member_constraints.choice_regions(m_c_i));
         }
@@ -1679,7 +1679,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         infcx: &InferCtxt<'tcx>,
         errors_buffer: &mut RegionErrors<'tcx>,
     ) {
-        let member_constraints = self.member_constraints.clone();
+        let member_constraints = Rc::clone(&self.member_constraints);
         for m_c_i in member_constraints.all_indices() {
             debug!(?m_c_i);
             let m_c = &member_constraints[m_c_i];
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index abce98265b3..741dac9e763 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -9,6 +9,7 @@ use rustc_macros::extension;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable,
+    TypingMode,
 };
 use rustc_span::Span;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
@@ -340,14 +341,13 @@ fn check_opaque_type_well_formed<'tcx>(
         parent_def_id = tcx.local_parent(parent_def_id);
     }
 
-    // FIXME(-Znext-solver): We probably should use `&[]` instead of
-    // and prepopulate this `InferCtxt` with known opaque values, rather than
-    // allowing opaque types to be defined and checking them after the fact.
+    // FIXME(#132279): This should eventually use the already defined hidden types
+    // instead. Alternatively we'll entirely remove this function given we also check
+    // the opaque in `check_opaque_meets_bounds` later.
     let infcx = tcx
         .infer_ctxt()
         .with_next_trait_solver(next_trait_solver)
-        .with_opaque_type_inference(parent_def_id)
-        .build();
+        .build(TypingMode::analysis_in_body(tcx, parent_def_id));
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     let identity_args = GenericArgs::identity_for_item(tcx, def_id);
 
@@ -517,7 +517,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
             },
         );
 
-        let infcx = tcx.infer_ctxt().build();
+        // FIXME(#132279): It feels wrong to use `non_body_analysis` here given that we're
+        // in a body here.
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = ObligationCtxt::new(&infcx);
 
         let wf_tys = ocx.assumed_wf_types(param_env, parent).unwrap_or_else(|_| {
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a544d88e832..26919bfd488 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -134,7 +134,7 @@ pub(crate) fn type_check<'a, 'tcx>(
     let mut constraints = MirTypeckRegionConstraints {
         placeholder_indices: PlaceholderIndices::default(),
         placeholder_index_to_region: IndexVec::default(),
-        liveness_constraints: LivenessValues::with_specific_points(elements.clone()),
+        liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)),
         outlives_constraints: OutlivesConstraintSet::default(),
         member_constraints: MemberConstraintSet::default(),
         type_tests: Vec::default(),
@@ -150,7 +150,7 @@ pub(crate) fn type_check<'a, 'tcx>(
         infcx,
         param_env,
         implicit_region_bound,
-        universal_regions.clone(),
+        Rc::clone(&universal_regions),
         &mut constraints,
     );
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 731945f5cbf..53e938ee216 100644
--- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -19,7 +19,7 @@ macro_rules! path {
     ($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
 }
 
-pub(crate) fn expand_deriving_smart_ptr(
+pub(crate) fn expand_deriving_coerce_pointee(
     cx: &ExtCtxt<'_>,
     span: Span,
     _mitem: &MetaItem,
@@ -41,7 +41,7 @@ pub(crate) fn expand_deriving_smart_ptr(
             cx.dcx()
                 .struct_span_err(
                     span,
-                    "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                    "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
                 )
                 .emit();
             return;
@@ -54,7 +54,7 @@ pub(crate) fn expand_deriving_smart_ptr(
             cx.dcx()
                 .struct_span_err(
                     span,
-                    "`SmartPointer` can only be derived on `struct`s with at least one field",
+                    "`CoercePointee` can only be derived on `struct`s with at least one field",
                 )
                 .emit();
             return;
@@ -64,7 +64,7 @@ pub(crate) fn expand_deriving_smart_ptr(
         cx.dcx()
             .struct_span_err(
                 span,
-                "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
+                "`CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`",
             )
             .emit();
         return;
@@ -94,10 +94,10 @@ pub(crate) fn expand_deriving_smart_ptr(
         .collect();
 
     let pointee_param_idx = if type_params.is_empty() {
-        // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
+        // `#[derive(CoercePointee)]` requires at least one generic type on the target `struct`
         cx.dcx().struct_span_err(
             span,
-            "`SmartPointer` can only be derived on `struct`s that are generic over at least one type",
+            "`CoercePointee` can only be derived on `struct`s that are generic over at least one type",
         ).emit();
         return;
     } else if type_params.len() == 1 {
@@ -113,7 +113,7 @@ pub(crate) fn expand_deriving_smart_ptr(
             (None, _) => {
                 cx.dcx().struct_span_err(
                     span,
-                    "exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits",
+                    "exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits",
                 ).emit();
                 return;
             }
@@ -121,7 +121,7 @@ pub(crate) fn expand_deriving_smart_ptr(
                 cx.dcx()
                     .struct_span_err(
                         vec![one, another],
-                        "only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits",
+                        "only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits",
                     )
                     .emit();
                 return;
@@ -185,7 +185,7 @@ pub(crate) fn expand_deriving_smart_ptr(
                 .struct_span_err(
                     pointee_ty_ident.span,
                     format!(
-                        "`derive(SmartPointer)` requires {} to be marked `?Sized`",
+                        "`derive(CoercePointee)` requires {} to be marked `?Sized`",
                         pointee_ty_ident.name
                     ),
                 )
@@ -195,7 +195,7 @@ pub(crate) fn expand_deriving_smart_ptr(
         let arg = GenericArg::Type(s_ty.clone());
         let unsize = cx.path_all(span, true, path!(span, core::marker::Unsize), vec![arg]);
         pointee.bounds.push(cx.trait_bound(unsize, false));
-        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(SmartPointer)`
+        // Drop `#[pointee]` attribute since it should not be recognized outside `derive(CoercePointee)`
         pointee.attrs.retain(|attr| !attr.has_name(sym::pointee));
     }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index e884c0ec718..681fbd1651d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -22,12 +22,12 @@ macro path_std($($x:tt)*) {
 
 pub(crate) mod bounds;
 pub(crate) mod clone;
+pub(crate) mod coerce_pointee;
 pub(crate) mod debug;
 pub(crate) mod decodable;
 pub(crate) mod default;
 pub(crate) mod encodable;
 pub(crate) mod hash;
-pub(crate) mod smart_ptr;
 
 #[path = "cmp/eq.rs"]
 pub(crate) mod eq;
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 377d7f542cf..9eee92164cf 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -133,7 +133,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         PartialOrd: partial_ord::expand_deriving_partial_ord,
         RustcDecodable: decodable::expand_deriving_rustc_decodable,
         RustcEncodable: encodable::expand_deriving_rustc_encodable,
-        SmartPointer: smart_ptr::expand_deriving_smart_ptr,
+        CoercePointee: coerce_pointee::expand_deriving_coerce_pointee,
     }
 
     let client = proc_macro::bridge::client::Client::expand1(proc_macro::quote);
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index a318cae1722..daea789ee3e 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -79,7 +79,7 @@ pub(super) fn add_local_place_comments<'tcx>(
         return;
     }
     let TyAndLayout { ty, layout } = place.layout();
-    let rustc_target::abi::LayoutS { size, align, .. } = layout.0.0;
+    let rustc_abi::LayoutData { size, align, .. } = layout.0.0;
 
     let (kind, extra) = place.debug_comment();
 
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 2fe5ed32daa..8a1ee48c43c 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -415,7 +415,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
         instance: Option<ty::Instance<'tcx>>,
     ) {
         let mut func_attrs = SmallVec::<[_; 3]>::new();
-        if self.ret.layout.abi.is_uninhabited() {
+        if self.ret.layout.is_uninhabited() {
             func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(cx.llcx));
         }
         if !self.can_unwind {
@@ -532,7 +532,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 
     fn apply_attrs_callsite(&self, bx: &mut Builder<'_, 'll, 'tcx>, callsite: &'ll Value) {
         let mut func_attrs = SmallVec::<[_; 2]>::new();
-        if self.ret.layout.abi.is_uninhabited() {
+        if self.ret.layout.is_uninhabited() {
             func_attrs.push(llvm::AttributeKind::NoReturn.create_attr(bx.cx.llcx));
         }
         if !self.can_unwind {
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 89f5305840b..149ded28356 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -7,6 +7,7 @@ use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{DebugInfo, OomStrategy};
 
+use crate::common::AsCCharPtr;
 use crate::llvm::{self, Context, False, Module, True, Type};
 use crate::{ModuleLlvm, attributes, debuginfo};
 
@@ -76,21 +77,15 @@ pub(crate) unsafe fn codegen(
     unsafe {
         // __rust_alloc_error_handler_should_panic
         let name = OomStrategy::SYMBOL;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let val = tcx.sess.opts.unstable_opts.oom.should_panic();
         let llval = llvm::LLVMConstInt(i8, val as u64, False);
         llvm::LLVMSetInitializer(ll_g, llval);
 
         let name = NO_ALLOC_SHIM_IS_UNSTABLE;
-        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
-        llvm::LLVMRustSetVisibility(
-            ll_g,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8);
+        llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
         let llval = llvm::LLVMConstInt(i8, 0, False);
         llvm::LLVMSetInitializer(ll_g, llval);
     }
@@ -121,7 +116,7 @@ fn create_wrapper_function(
         );
         let llfn = llvm::LLVMRustGetOrInsertFunction(
             llmod,
-            from_name.as_ptr().cast(),
+            from_name.as_c_char_ptr(),
             from_name.len(),
             ty,
         );
@@ -134,10 +129,7 @@ fn create_wrapper_function(
             None
         };
 
-        llvm::LLVMRustSetVisibility(
-            llfn,
-            llvm::Visibility::from_generic(tcx.sess.default_visibility()),
-        );
+        llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility()));
 
         if tcx.sess.must_emit_unwind_tables() {
             let uwtable =
@@ -146,12 +138,12 @@ fn create_wrapper_function(
         }
 
         let callee =
-            llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_ptr().cast(), to_name.len(), ty);
+            llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty);
         if let Some(no_return) = no_return {
             // -> ! DIFlagNoReturn
             attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
         }
-        llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+        llvm::set_visibility(callee, llvm::Visibility::Hidden);
 
         let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr());
 
@@ -162,7 +154,7 @@ fn create_wrapper_function(
             .enumerate()
             .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
             .collect::<Vec<_>>();
-        let ret = llvm::LLVMRustBuildCall(
+        let ret = llvm::LLVMBuildCallWithOperandBundles(
             llbuilder,
             ty,
             callee,
@@ -170,6 +162,7 @@ fn create_wrapper_function(
             args.len() as c_uint,
             [].as_ptr(),
             0 as c_uint,
+            c"".as_ptr(),
         );
         llvm::LLVMSetTailCall(ret, True);
         if output.is_some() {
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index d1d7d0cf4ce..3c30822a2e2 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -15,7 +15,7 @@ use smallvec::SmallVec;
 use tracing::debug;
 
 use crate::builder::Builder;
-use crate::common::Funclet;
+use crate::common::{AsCCharPtr, Funclet};
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
@@ -420,7 +420,7 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
         unsafe {
             llvm::LLVMAppendModuleInlineAsm(
                 self.llmod,
-                template_str.as_ptr().cast(),
+                template_str.as_c_char_ptr(),
                 template_str.len(),
             );
         }
@@ -458,14 +458,14 @@ pub(crate) fn inline_asm_call<'ll>(
     let fty = bx.cx.type_func(&argtys, output);
     unsafe {
         // Ask LLVM to verify that the constraints are well-formed.
-        let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
+        let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len());
         debug!("constraint verification result: {:?}", constraints_ok);
         if constraints_ok {
             let v = llvm::LLVMRustInlineAsm(
                 fty,
-                asm.as_ptr().cast(),
+                asm.as_c_char_ptr(),
                 asm.len(),
-                cons.as_ptr().cast(),
+                cons.as_c_char_ptr(),
                 cons.len(),
                 volatile,
                 alignstack,
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 1f7a923dd2c..48beb9be2b2 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -165,13 +165,14 @@ fn get_bitcode_slice_from_object_data<'a>(
     // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment
     // name" which in the public API for sections gets treated as part of the section name, but
     // internally in MachOObjectFile.cpp gets treated separately.
-    let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,");
+    let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,");
     let mut len = 0;
     let data = unsafe {
         llvm::LLVMRustGetSliceFromObjectDataByName(
             obj.as_ptr(),
             obj.len(),
             section_name.as_ptr(),
+            section_name.len(),
             &mut len,
         )
     };
@@ -502,9 +503,9 @@ fn thin_lto(
         // upstream...
         let data = llvm::LLVMRustCreateThinLTOData(
             thin_modules.as_ptr(),
-            thin_modules.len() as u32,
+            thin_modules.len(),
             symbols_below_threshold.as_ptr(),
-            symbols_below_threshold.len() as u32,
+            symbols_below_threshold.len(),
         )
         .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?;
 
@@ -569,7 +570,7 @@ fn thin_lto(
 
             info!(" - {}: re-compiled", module_name);
             opt_jobs.push(LtoModuleCodegen::Thin(ThinModule {
-                shared: shared.clone(),
+                shared: Arc::clone(&shared),
                 idx: module_index,
             }));
         }
@@ -601,23 +602,9 @@ pub(crate) fn run_pass_manager(
     // This code is based off the code found in llvm's LTO code generator:
     //      llvm/lib/LTO/LTOCodeGenerator.cpp
     debug!("running the pass manager");
-    unsafe {
-        if !llvm::LLVMRustHasModuleFlag(
-            module.module_llvm.llmod(),
-            "LTOPostLink".as_ptr().cast(),
-            11,
-        ) {
-            llvm::LLVMRustAddModuleFlagU32(
-                module.module_llvm.llmod(),
-                llvm::LLVMModFlagBehavior::Error,
-                c"LTOPostLink".as_ptr(),
-                1,
-            );
-        }
-        let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
-        let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
-        write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?;
-    }
+    let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
+    let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
+    unsafe { write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage) }?;
     debug!("lto done");
     Ok(())
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index afdd2b581b8..bfa9e8b82a0 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1,4 +1,4 @@
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
 use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use std::sync::Arc;
@@ -34,6 +34,7 @@ use crate::back::owned_target_machine::OwnedTargetMachine;
 use crate::back::profiling::{
     LlvmSelfProfiler, selfprofile_after_pass_callback, selfprofile_before_pass_callback,
 };
+use crate::common::AsCCharPtr;
 use crate::errors::{
     CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
     WithLlvmError, WriteBytecode,
@@ -596,9 +597,9 @@ pub(crate) unsafe fn llvm_optimize(
             llvm_selfprofiler,
             selfprofile_before_pass_callback,
             selfprofile_after_pass_callback,
-            extra_passes.as_ptr().cast(),
+            extra_passes.as_c_char_ptr(),
             extra_passes.len(),
-            llvm_plugins.as_ptr().cast(),
+            llvm_plugins.as_c_char_ptr(),
             llvm_plugins.len(),
         )
     };
@@ -957,14 +958,13 @@ fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
     cgcx.opts.target_triple.triple().contains("-aix")
 }
 
-//FIXME use c string literals here too
-pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str {
+pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static CStr {
     if target_is_apple(cgcx) {
-        "__LLVM,__bitcode\0"
+        c"__LLVM,__bitcode"
     } else if target_is_aix(cgcx) {
-        ".ipa\0"
+        c".ipa"
     } else {
-        ".llvmbc\0"
+        c".llvmbc"
     }
 }
 
@@ -1041,9 +1041,8 @@ unsafe fn embed_bitcode(
             );
             llvm::LLVMSetInitializer(llglobal, llconst);
 
-            let section = bitcode_section_name(cgcx);
-            llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_section(llglobal, bitcode_section_name(cgcx));
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
             llvm::LLVMSetGlobalConstant(llglobal, llvm::True);
 
             let llconst = common::bytes_in_context(llcx, cmdline.as_bytes());
@@ -1060,15 +1059,15 @@ unsafe fn embed_bitcode(
             } else {
                 c".llvmcmd"
             };
-            llvm::LLVMSetSection(llglobal, section.as_ptr());
-            llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
+            llvm::set_section(llglobal, section);
+            llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage);
         } else {
             // We need custom section flags, so emit module-level inline assembly.
             let section_flags = if cgcx.is_pe_coff { "n" } else { "e" };
             let asm = create_section_with_flags_asm(".llvmbc", section_flags, bitcode);
-            llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+            llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
             let asm = create_section_with_flags_asm(".llvmcmd", section_flags, cmdline.as_bytes());
-            llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len());
+            llvm::LLVMAppendModuleInlineAsm(llmod, asm.as_c_char_ptr(), asm.len());
         }
     }
 }
@@ -1096,7 +1095,7 @@ fn create_msvc_imps(
         let ptr_ty = Type::ptr_llcx(llcx);
         let globals = base::iter_globals(llmod)
             .filter(|&val| {
-                llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage
+                llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage
                     && llvm::LLVMIsDeclaration(val) == 0
             })
             .filter_map(|val| {
@@ -1115,7 +1114,7 @@ fn create_msvc_imps(
         for (imp_name, val) in globals {
             let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr());
             llvm::LLVMSetInitializer(imp, val);
-            llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
+            llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage);
         }
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 0ba8d82406a..32793894794 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -145,10 +145,8 @@ pub(crate) fn compile_codegen_unit(
 
 pub(crate) fn set_link_section(llval: &Value, attrs: &CodegenFnAttrs) {
     let Some(sect) = attrs.link_section else { return };
-    unsafe {
-        let buf = SmallCStr::new(sect.as_str());
-        llvm::LLVMSetSection(llval, buf.as_ptr());
-    }
+    let buf = SmallCStr::new(sect.as_str());
+    llvm::set_section(llval, &buf);
 }
 
 pub(crate) fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8702532c36e..f8eb3e0c982 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -239,7 +239,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("invoke", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -250,13 +249,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let invoke = unsafe {
-            llvm::LLVMRustBuildInvoke(
+            llvm::LLVMBuildInvokeWithOperandBundles(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1179,7 +1177,6 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("call", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -1190,13 +1187,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let call = unsafe {
-            llvm::LLVMRustBuildCall(
+            llvm::LLVMBuildCallWithOperandBundles(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1204,6 +1200,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 args.len() as c_uint,
                 bundles.as_ptr(),
                 bundles.len() as c_uint,
+                c"".as_ptr(),
             )
         };
         if let Some(fn_abi) = fn_abi {
@@ -1509,7 +1506,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         let args = self.check_call("callbr", llty, llfn, args);
         let funclet_bundle = funclet.map(|funclet| funclet.bundle());
-        let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
         let mut bundles: SmallVec<[_; 2]> = SmallVec::new();
         if let Some(funclet_bundle) = funclet_bundle {
             bundles.push(funclet_bundle);
@@ -1520,13 +1516,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
 
         // Emit KCFI operand bundle
         let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
-        let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
-        if let Some(kcfi_bundle) = kcfi_bundle {
+        if let Some(kcfi_bundle) = kcfi_bundle.as_deref() {
             bundles.push(kcfi_bundle);
         }
 
         let callbr = unsafe {
-            llvm::LLVMRustBuildCallBr(
+            llvm::LLVMBuildCallBr(
                 self.llbuilder,
                 llty,
                 llfn,
@@ -1601,7 +1596,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
         fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
         instance: Option<Instance<'tcx>>,
         llfn: &'ll Value,
-    ) -> Option<llvm::OperandBundleDef<'ll>> {
+    ) -> Option<llvm::OperandBundleOwned<'ll>> {
         let is_indirect_call = unsafe { llvm::LLVMRustIsNonGVFunctionPointerTy(llfn) };
         let kcfi_bundle = if self.tcx.sess.is_sanitizer_kcfi_enabled()
             && let Some(fn_abi) = fn_abi
@@ -1627,7 +1622,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
                 kcfi::typeid_for_fnabi(self.tcx, fn_abi, options)
             };
 
-            Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
+            Some(llvm::OperandBundleOwned::new("kcfi", &[self.const_u32(kcfi_typeid)]))
         } else {
             None
         };
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index a51ef8d7b85..25037b97375 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -95,9 +95,9 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
         // whether we are sharing generics or not. The important thing here is
         // that the visibility we apply to the declaration is the same one that
         // has been applied to the definition (wherever that definition may be).
-        unsafe {
-            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
 
+        llvm::set_linkage(llfn, llvm::Linkage::ExternalLinkage);
+        unsafe {
             let is_generic = instance.args.non_erasable_generics().next().is_some();
 
             let is_hidden = if is_generic {
@@ -135,7 +135,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t
                         || !cx.tcx.is_reachable_non_generic(instance_def_id))
             };
             if is_hidden {
-                llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+                llvm::set_visibility(llfn, llvm::Visibility::Hidden);
             }
 
             // MinGW: For backward compatibility we rely on the linker to decide whether it
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 0ced37b53a8..8852dec7d9f 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -17,7 +17,7 @@ use tracing::debug;
 
 use crate::consts::const_alloc_to_llvm;
 pub(crate) use crate::context::CodegenCx;
-use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, OperandBundleDef, True};
+use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True};
 use crate::type_::Type;
 use crate::value::Value;
 
@@ -63,19 +63,19 @@ use crate::value::Value;
 /// the `OperandBundleDef` value created for MSVC landing pads.
 pub(crate) struct Funclet<'ll> {
     cleanuppad: &'ll Value,
-    operand: OperandBundleDef<'ll>,
+    operand: llvm::OperandBundleOwned<'ll>,
 }
 
 impl<'ll> Funclet<'ll> {
     pub(crate) fn new(cleanuppad: &'ll Value) -> Self {
-        Funclet { cleanuppad, operand: OperandBundleDef::new("funclet", &[cleanuppad]) }
+        Funclet { cleanuppad, operand: llvm::OperandBundleOwned::new("funclet", &[cleanuppad]) }
     }
 
     pub(crate) fn cleanuppad(&self) -> &'ll Value {
         self.cleanuppad
     }
 
-    pub(crate) fn bundle(&self) -> &OperandBundleDef<'ll> {
+    pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> {
         &self.operand
     }
 }
@@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     llvm::LLVMSetInitializer(g, sc);
                     llvm::LLVMSetGlobalConstant(g, True);
                     llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global);
-                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
                 }
+                llvm::set_linkage(g, llvm::Linkage::InternalLinkage);
                 (s.to_owned(), g)
             })
             .1;
@@ -392,3 +392,21 @@ pub(crate) fn get_dllimport<'tcx>(
     tcx.native_library(id)
         .and_then(|lib| lib.dll_imports.iter().find(|di| di.name.as_str() == name))
 }
+
+/// Extension trait for explicit casts to `*const c_char`.
+pub(crate) trait AsCCharPtr {
+    /// Equivalent to `self.as_ptr().cast()`, but only casts to `*const c_char`.
+    fn as_c_char_ptr(&self) -> *const c_char;
+}
+
+impl AsCCharPtr for str {
+    fn as_c_char_ptr(&self) -> *const c_char {
+        self.as_ptr().cast()
+    }
+}
+
+impl AsCCharPtr for [u8] {
+    fn as_c_char_ptr(&self) -> *const c_char {
+        self.as_ptr().cast()
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 33a85adeb87..21d996ef460 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -19,7 +19,7 @@ use rustc_target::abi::{
 };
 use tracing::{debug, instrument, trace};
 
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::errors::{
     InvalidMinimumAlignmentNotPowerOfTwo, InvalidMinimumAlignmentTooLarge, SymbolAlreadyDefined,
 };
@@ -172,29 +172,27 @@ fn check_and_apply_linkage<'ll, 'tcx>(
     if let Some(linkage) = attrs.import_linkage {
         debug!("get_static: sym={} linkage={:?}", sym, linkage);
 
-        unsafe {
-            // Declare a symbol `foo` with the desired linkage.
-            let g1 = cx.declare_global(sym, cx.type_i8());
-            llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
-
-            // Declare an internal global `extern_with_linkage_foo` which
-            // is initialized with the address of `foo`. If `foo` is
-            // discarded during linking (for example, if `foo` has weak
-            // linkage and there are no definitions), then
-            // `extern_with_linkage_foo` will instead be initialized to
-            // zero.
-            let mut real_name = "_rust_extern_with_linkage_".to_string();
-            real_name.push_str(sym);
-            let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
-                    span: cx.tcx.def_span(def_id),
-                    symbol_name: sym,
-                })
-            });
-            llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
-            llvm::LLVMSetInitializer(g2, g1);
-            g2
-        }
+        // Declare a symbol `foo` with the desired linkage.
+        let g1 = cx.declare_global(sym, cx.type_i8());
+        llvm::set_linkage(g1, base::linkage_to_llvm(linkage));
+
+        // Declare an internal global `extern_with_linkage_foo` which
+        // is initialized with the address of `foo`. If `foo` is
+        // discarded during linking (for example, if `foo` has weak
+        // linkage and there are no definitions), then
+        // `extern_with_linkage_foo` will instead be initialized to
+        // zero.
+        let mut real_name = "_rust_extern_with_linkage_".to_string();
+        real_name.push_str(sym);
+        let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
+            cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
+                span: cx.tcx.def_span(def_id),
+                symbol_name: sym,
+            })
+        });
+        llvm::set_linkage(g2, llvm::Linkage::InternalLinkage);
+        unsafe { llvm::LLVMSetInitializer(g2, g1) };
+        g2
     } else if cx.tcx.sess.target.arch == "x86"
         && let Some(dllimport) = crate::common::get_dllimport(cx.tcx, def_id, sym)
     {
@@ -224,23 +222,21 @@ impl<'ll> CodegenCx<'ll, '_> {
         align: Align,
         kind: Option<&str>,
     ) -> &'ll Value {
-        unsafe {
-            let gv = match kind {
-                Some(kind) if !self.tcx.sess.fewer_names() => {
-                    let name = self.generate_local_symbol_name(kind);
-                    let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
-                        bug!("symbol `{}` is already defined", name);
-                    });
-                    llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage);
-                    gv
-                }
-                _ => self.define_private_global(self.val_ty(cv)),
-            };
-            llvm::LLVMSetInitializer(gv, cv);
-            set_global_alignment(self, gv, align);
-            llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
-            gv
-        }
+        let gv = match kind {
+            Some(kind) if !self.tcx.sess.fewer_names() => {
+                let name = self.generate_local_symbol_name(kind);
+                let gv = self.define_global(&name, self.val_ty(cv)).unwrap_or_else(|| {
+                    bug!("symbol `{}` is already defined", name);
+                });
+                llvm::set_linkage(gv, llvm::Linkage::PrivateLinkage);
+                gv
+            }
+            _ => self.define_private_global(self.val_ty(cv)),
+        };
+        unsafe { llvm::LLVMSetInitializer(gv, cv) };
+        set_global_alignment(self, gv, align);
+        llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global);
+        gv
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -292,9 +288,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             let g = self.declare_global(sym, llty);
 
             if !self.tcx.is_reachable_non_generic(def_id) {
-                unsafe {
-                    llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
-                }
+                llvm::set_visibility(g, llvm::Visibility::Hidden);
             }
 
             g
@@ -312,7 +306,7 @@ impl<'ll> CodegenCx<'ll, '_> {
             llvm::set_thread_local_mode(g, self.tls_model);
         }
 
-        let dso_local = unsafe { self.should_assume_dso_local(g, true) };
+        let dso_local = self.should_assume_dso_local(g, true);
         if dso_local {
             unsafe {
                 llvm::LLVMRustSetDSOLocal(g, true);
@@ -401,18 +395,18 @@ impl<'ll> CodegenCx<'ll, '_> {
                 let name = llvm::get_value_name(g).to_vec();
                 llvm::set_value_name(g, b"");
 
-                let linkage = llvm::LLVMRustGetLinkage(g);
-                let visibility = llvm::LLVMRustGetVisibility(g);
+                let linkage = llvm::get_linkage(g);
+                let visibility = llvm::get_visibility(g);
 
                 let new_g = llvm::LLVMRustGetOrInsertGlobal(
                     self.llmod,
-                    name.as_ptr().cast(),
+                    name.as_c_char_ptr(),
                     name.len(),
                     val_llty,
                 );
 
-                llvm::LLVMRustSetLinkage(new_g, linkage);
-                llvm::LLVMRustSetVisibility(new_g, visibility);
+                llvm::set_linkage(new_g, linkage);
+                llvm::set_visibility(new_g, visibility);
 
                 // The old global has had its name removed but is returned by
                 // get_static since it is in the instance cache. Provide an
@@ -457,7 +451,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                 if let Some(section) = attrs.link_section {
                     let section = llvm::LLVMMDStringInContext2(
                         self.llcx,
-                        section.as_str().as_ptr().cast(),
+                        section.as_str().as_c_char_ptr(),
                         section.as_str().len(),
                     );
                     assert!(alloc.provenance().ptrs().is_empty());
@@ -468,7 +462,7 @@ impl<'ll> CodegenCx<'ll, '_> {
                     let bytes =
                         alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len());
                     let alloc =
-                        llvm::LLVMMDStringInContext2(self.llcx, bytes.as_ptr().cast(), bytes.len());
+                        llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len());
                     let data = [section, alloc];
                     let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len());
                     let val = llvm::LLVMMetadataAsValue(self.llcx, meta);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3fc153c6cd4..9778ff4918c 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -29,6 +29,7 @@ use smallvec::SmallVec;
 
 use crate::back::write::to_llvm_code_model;
 use crate::callee::get_fn;
+use crate::common::AsCCharPtr;
 use crate::debuginfo::metadata::apply_vcall_visibility_metadata;
 use crate::llvm::{Metadata, MetadataType};
 use crate::type_::Type;
@@ -209,133 +210,111 @@ pub(crate) unsafe fn create_module<'ll>(
     // If skipping the PLT is enabled, we need to add some module metadata
     // to ensure intrinsic calls don't use it.
     if !sess.needs_plt() {
-        let avoid_plt = c"RtLibUseGOT".as_ptr();
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
-        }
+        llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "RtLibUseGOT", 1);
     }
 
     // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
     if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
-        let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr();
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                canonical_jump_tables,
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "CFI Canonical Jump Tables",
+            1,
+        );
     }
 
     // If we're normalizing integers with CFI, ensure LLVM generated functions do the same.
     // See https://github.com/llvm/llvm-project/pull/104826
     if sess.is_sanitizer_cfi_normalize_integers_enabled() {
-        let cfi_normalize_integers = c"cfi-normalize-integers".as_ptr().cast();
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                cfi_normalize_integers,
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "cfi-normalize-integers",
+            1,
+        );
     }
 
     // Enable LTO unit splitting if specified or if CFI is enabled. (See
     // https://reviews.llvm.org/D53891.)
     if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
-        let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr();
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                enable_split_lto_unit,
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "EnableSplitLTOUnit",
+            1,
+        );
     }
 
     // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
     if sess.is_sanitizer_kcfi_enabled() {
-        let kcfi = c"kcfi".as_ptr();
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
-        }
+        llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Override, "kcfi", 1);
 
         // Add "kcfi-offset" module flag with -Z patchable-function-entry (See
         // https://reviews.llvm.org/D141172).
         let pfe =
             PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
         if pfe.prefix() > 0 {
-            let kcfi_offset = c"kcfi-offset".as_ptr().cast();
-            unsafe {
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Override,
-                    kcfi_offset,
-                    pfe.prefix().into(),
-                );
-            }
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Override,
+                "kcfi-offset",
+                pfe.prefix().into(),
+            );
         }
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
     if sess.target.is_like_msvc {
-        unsafe {
-            match sess.opts.cg.control_flow_guard {
-                CFGuard::Disabled => {}
-                CFGuard::NoChecks => {
-                    // Set `cfguard=1` module flag to emit metadata only.
-                    llvm::LLVMRustAddModuleFlagU32(
-                        llmod,
-                        llvm::LLVMModFlagBehavior::Warning,
-                        c"cfguard".as_ptr() as *const _,
-                        1,
-                    )
-                }
-                CFGuard::Checks => {
-                    // Set `cfguard=2` module flag to emit metadata and checks.
-                    llvm::LLVMRustAddModuleFlagU32(
-                        llmod,
-                        llvm::LLVMModFlagBehavior::Warning,
-                        c"cfguard".as_ptr() as *const _,
-                        2,
-                    )
-                }
+        match sess.opts.cg.control_flow_guard {
+            CFGuard::Disabled => {}
+            CFGuard::NoChecks => {
+                // Set `cfguard=1` module flag to emit metadata only.
+                llvm::add_module_flag_u32(
+                    llmod,
+                    llvm::ModuleFlagMergeBehavior::Warning,
+                    "cfguard",
+                    1,
+                );
+            }
+            CFGuard::Checks => {
+                // Set `cfguard=2` module flag to emit metadata and checks.
+                llvm::add_module_flag_u32(
+                    llmod,
+                    llvm::ModuleFlagMergeBehavior::Warning,
+                    "cfguard",
+                    2,
+                );
             }
         }
     }
 
     if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
         if sess.target.arch == "aarch64" {
-            unsafe {
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Min,
-                    c"branch-target-enforcement".as_ptr(),
-                    bti.into(),
-                );
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Min,
-                    c"sign-return-address".as_ptr(),
-                    pac_ret.is_some().into(),
-                );
-                let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Min,
-                    c"sign-return-address-all".as_ptr(),
-                    pac_opts.leaf.into(),
-                );
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Min,
-                    c"sign-return-address-with-bkey".as_ptr(),
-                    u32::from(pac_opts.key == PAuthKey::B),
-                );
-            }
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "branch-target-enforcement",
+                bti.into(),
+            );
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "sign-return-address",
+                pac_ret.is_some().into(),
+            );
+            let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "sign-return-address-all",
+                pac_opts.leaf.into(),
+            );
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Min,
+                "sign-return-address-with-bkey",
+                u32::from(pac_opts.key == PAuthKey::B),
+            );
         } else {
             bug!(
                 "branch-protection used on non-AArch64 target; \
@@ -346,59 +325,46 @@ pub(crate) unsafe fn create_module<'ll>(
 
     // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
     if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                c"cf-protection-branch".as_ptr(),
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "cf-protection-branch",
+            1,
+        );
     }
     if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                c"cf-protection-return".as_ptr(),
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Override,
+            "cf-protection-return",
+            1,
+        );
     }
 
     if sess.opts.unstable_opts.virtual_function_elimination {
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Error,
-                c"Virtual Function Elim".as_ptr(),
-                1,
-            );
-        }
+        llvm::add_module_flag_u32(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Error,
+            "Virtual Function Elim",
+            1,
+        );
     }
 
     // Set module flag to enable Windows EHCont Guard (/guard:ehcont).
     if sess.opts.unstable_opts.ehcont_guard {
-        unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
-                llmod,
-                llvm::LLVMModFlagBehavior::Warning,
-                c"ehcontguard".as_ptr() as *const _,
-                1,
-            )
-        }
+        llvm::add_module_flag_u32(llmod, llvm::ModuleFlagMergeBehavior::Warning, "ehcontguard", 1);
     }
 
     match sess.opts.unstable_opts.function_return {
         FunctionReturn::Keep => {}
-        FunctionReturn::ThunkExtern => unsafe {
-            llvm::LLVMRustAddModuleFlagU32(
+        FunctionReturn::ThunkExtern => {
+            llvm::add_module_flag_u32(
                 llmod,
-                llvm::LLVMModFlagBehavior::Override,
-                c"function_return_thunk_extern".as_ptr(),
+                llvm::ModuleFlagMergeBehavior::Override,
+                "function_return_thunk_extern",
                 1,
-            )
-        },
+            );
+        }
     }
 
     match (sess.opts.unstable_opts.small_data_threshold, sess.target.small_data_threshold_support())
@@ -406,15 +372,12 @@ pub(crate) unsafe fn create_module<'ll>(
         // Set up the small-data optimization limit for architectures that use
         // an LLVM module flag to control this.
         (Some(threshold), SmallDataThresholdSupport::LlvmModuleFlag(flag)) => {
-            let flag = SmallCStr::new(flag.as_ref());
-            unsafe {
-                llvm::LLVMRustAddModuleFlagU32(
-                    llmod,
-                    llvm::LLVMModFlagBehavior::Error,
-                    flag.as_c_str().as_ptr(),
-                    threshold as u32,
-                )
-            }
+            llvm::add_module_flag_u32(
+                llmod,
+                llvm::ModuleFlagMergeBehavior::Error,
+                &flag,
+                threshold as u32,
+            );
         }
         _ => (),
     };
@@ -429,7 +392,7 @@ pub(crate) unsafe fn create_module<'ll>(
     let name_metadata = unsafe {
         llvm::LLVMMDStringInContext2(
             llcx,
-            rustc_producer.as_ptr().cast(),
+            rustc_producer.as_c_char_ptr(),
             rustc_producer.as_bytes().len(),
         )
     };
@@ -448,33 +411,29 @@ pub(crate) unsafe fn create_module<'ll>(
     // If llvm_abiname is empty, emit nothing.
     let llvm_abiname = &sess.target.options.llvm_abiname;
     if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
-        unsafe {
-            llvm::LLVMRustAddModuleFlagString(
-                llmod,
-                llvm::LLVMModFlagBehavior::Error,
-                c"target-abi".as_ptr(),
-                llvm_abiname.as_ptr().cast(),
-                llvm_abiname.len(),
-            );
-        }
+        llvm::add_module_flag_str(
+            llmod,
+            llvm::ModuleFlagMergeBehavior::Error,
+            "target-abi",
+            llvm_abiname,
+        );
     }
 
     // Add module flags specified via -Z llvm_module_flag
-    for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
-        let key = format!("{key}\0");
-        let behavior = match behavior.as_str() {
-            "error" => llvm::LLVMModFlagBehavior::Error,
-            "warning" => llvm::LLVMModFlagBehavior::Warning,
-            "require" => llvm::LLVMModFlagBehavior::Require,
-            "override" => llvm::LLVMModFlagBehavior::Override,
-            "append" => llvm::LLVMModFlagBehavior::Append,
-            "appendunique" => llvm::LLVMModFlagBehavior::AppendUnique,
-            "max" => llvm::LLVMModFlagBehavior::Max,
-            "min" => llvm::LLVMModFlagBehavior::Min,
+    for (key, value, merge_behavior) in &sess.opts.unstable_opts.llvm_module_flag {
+        let merge_behavior = match merge_behavior.as_str() {
+            "error" => llvm::ModuleFlagMergeBehavior::Error,
+            "warning" => llvm::ModuleFlagMergeBehavior::Warning,
+            "require" => llvm::ModuleFlagMergeBehavior::Require,
+            "override" => llvm::ModuleFlagMergeBehavior::Override,
+            "append" => llvm::ModuleFlagMergeBehavior::Append,
+            "appendunique" => llvm::ModuleFlagMergeBehavior::AppendUnique,
+            "max" => llvm::ModuleFlagMergeBehavior::Max,
+            "min" => llvm::ModuleFlagMergeBehavior::Min,
             // We already checked this during option parsing
             _ => unreachable!(),
         };
-        unsafe { llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) }
+        llvm::add_module_flag_u32(llmod, merge_behavior, key, *value);
     }
 
     llmod
@@ -605,8 +564,8 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         unsafe {
             let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
             llvm::LLVMSetInitializer(g, array);
-            llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
-            llvm::LLVMSetSection(g, c"llvm.metadata".as_ptr());
+            llvm::set_linkage(g, llvm::Linkage::AppendingLinkage);
+            llvm::set_section(g, c"llvm.metadata");
         }
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index c6b2a623ea6..a298ed86276 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -14,7 +14,7 @@ use rustc_target::abi::Size;
 use tracing::{debug, instrument};
 
 use crate::builder::Builder;
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::coverageinfo::map_data::FunctionCoverageCollector;
 use crate::llvm;
 
@@ -236,7 +236,7 @@ fn create_pgo_func_name_var<'ll, 'tcx>(
     unsafe {
         llvm::LLVMRustCoverageCreatePGOFuncNameVar(
             llfn,
-            mangled_fn_name.as_ptr().cast(),
+            mangled_fn_name.as_c_char_ptr(),
             mangled_fn_name.len(),
         )
     }
@@ -248,7 +248,7 @@ pub(crate) fn write_filenames_section_to_buffer<'a>(
 ) {
     let (pointers, lengths) = filenames
         .into_iter()
-        .map(|s: &str| (s.as_ptr().cast(), s.len()))
+        .map(|s: &str| (s.as_c_char_ptr(), s.len()))
         .unzip::<_, _, Vec<_>, Vec<_>>();
 
     unsafe {
@@ -291,7 +291,7 @@ pub(crate) fn write_mapping_to_buffer(
 }
 
 pub(crate) fn hash_bytes(bytes: &[u8]) -> u64 {
-    unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_ptr().cast(), bytes.len()) }
+    unsafe { llvm::LLVMRustCoverageHashByteArray(bytes.as_c_char_ptr(), bytes.len()) }
 }
 
 pub(crate) fn mapping_version() -> u32 {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index f93d3e40b20..aef8642f199 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -72,11 +72,11 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>(
             let section_var = cx
                 .define_global(section_var_name, llvm_type)
                 .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name));
-            llvm::LLVMSetSection(section_var, c".debug_gdb_scripts".as_ptr());
+            llvm::set_section(section_var, c".debug_gdb_scripts");
             llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global);
-            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
             llvm::LLVMSetAlignment(section_var, 1);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 15d441a986d..9064cfaeb29 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -32,7 +32,7 @@ use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_na
 use super::utils::{
     DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
 };
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::metadata::type_map::build_type_with_children;
 use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
 use crate::llvm::debuginfo::{
@@ -190,7 +190,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>(
                     data_layout.pointer_size.bits(),
                     data_layout.pointer_align.abi.bits() as u32,
                     0, // Ignore DWARF address space.
-                    ptr_type_debuginfo_name.as_ptr().cast(),
+                    ptr_type_debuginfo_name.as_c_char_ptr(),
                     ptr_type_debuginfo_name.len(),
                 )
             };
@@ -348,7 +348,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
             size,
             align,
             0, // Ignore DWARF address space.
-            name.as_ptr().cast(),
+            name.as_c_char_ptr(),
             name.len(),
         )
     };
@@ -518,7 +518,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
             let name = "<recur_type>";
             llvm::LLVMRustDIBuilderCreateBasicType(
                 DIB(cx),
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
                 cx.tcx.data_layout.pointer_size.bits(),
                 DW_ATE_unsigned,
@@ -640,14 +640,14 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
         unsafe {
             llvm::LLVMRustDIBuilderCreateFile(
                 DIB(cx),
-                file_name.as_ptr().cast(),
+                file_name.as_c_char_ptr(),
                 file_name.len(),
-                directory.as_ptr().cast(),
+                directory.as_c_char_ptr(),
                 directory.len(),
                 hash_kind,
-                hash_value.as_ptr().cast(),
+                hash_value.as_c_char_ptr(),
                 hash_value.len(),
-                source.map_or(ptr::null(), |x| x.as_ptr().cast()),
+                source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
                 source.map_or(0, |x| x.len()),
             )
         }
@@ -662,12 +662,12 @@ fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
 
         llvm::LLVMRustDIBuilderCreateFile(
             DIB(cx),
-            file_name.as_ptr().cast(),
+            file_name.as_c_char_ptr(),
             file_name.len(),
-            directory.as_ptr().cast(),
+            directory.as_c_char_ptr(),
             directory.len(),
             llvm::ChecksumKind::None,
-            hash_value.as_ptr().cast(),
+            hash_value.as_c_char_ptr(),
             hash_value.len(),
             ptr::null(),
             0,
@@ -788,7 +788,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(
     let ty_di_node = unsafe {
         llvm::LLVMRustDIBuilderCreateBasicType(
             DIB(cx),
-            name.as_ptr().cast(),
+            name.as_c_char_ptr(),
             name.len(),
             cx.size_of(t).bits(),
             encoding,
@@ -810,7 +810,7 @@ fn build_basic_type_di_node<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateTypedef(
             DIB(cx),
             ty_di_node,
-            typedef_name.as_ptr().cast(),
+            typedef_name.as_c_char_ptr(),
             typedef_name.len(),
             unknown_file_metadata(cx),
             0,
@@ -861,7 +861,7 @@ fn build_param_type_di_node<'ll, 'tcx>(
         di_node: unsafe {
             llvm::LLVMRustDIBuilderCreateBasicType(
                 DIB(cx),
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
                 Size::ZERO.bits(),
                 DW_ATE_unsigned,
@@ -948,9 +948,9 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
     unsafe {
         let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
             debug_context.builder,
-            name_in_debuginfo.as_ptr().cast(),
+            name_in_debuginfo.as_c_char_ptr(),
             name_in_debuginfo.len(),
-            work_dir.as_ptr().cast(),
+            work_dir.as_c_char_ptr(),
             work_dir.len(),
             llvm::ChecksumKind::None,
             ptr::null(),
@@ -963,7 +963,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
             debug_context.builder,
             DW_LANG_RUST,
             compile_unit_file,
-            producer.as_ptr().cast(),
+            producer.as_c_char_ptr(),
             producer.len(),
             tcx.sess.opts.optimize != config::OptLevel::No,
             c"".as_ptr(),
@@ -971,7 +971,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
             // NB: this doesn't actually have any perceptible effect, it seems. LLVM will instead
             // put the path supplied to `MCSplitDwarfFile` into the debug info of the final
             // output(s).
-            split_name.as_ptr().cast(),
+            split_name.as_c_char_ptr(),
             split_name.len(),
             kind,
             0,
@@ -1022,7 +1022,7 @@ fn build_field_di_node<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateMemberType(
             DIB(cx),
             owner,
-            name.as_ptr().cast(),
+            name.as_c_char_ptr(),
             name.len(),
             unknown_file_metadata(cx),
             UNKNOWN_LINE_NUMBER,
@@ -1306,7 +1306,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
                             llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
                                 DIB(cx),
                                 None,
-                                name.as_ptr().cast(),
+                                name.as_c_char_ptr(),
                                 name.len(),
                                 actual_type_di_node,
                             )
@@ -1382,9 +1382,9 @@ pub(crate) fn build_global_var_di_node<'ll>(
         llvm::LLVMRustDIBuilderCreateStaticVariable(
             DIB(cx),
             Some(var_scope),
-            var_name.as_ptr().cast(),
+            var_name.as_c_char_ptr(),
             var_name.len(),
-            linkage_name.as_ptr().cast(),
+            linkage_name.as_c_char_ptr(),
             linkage_name.len(),
             file_metadata,
             line_number,
@@ -1602,9 +1602,9 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateStaticVariable(
             DIB(cx),
             NO_SCOPE_METADATA,
-            vtable_name.as_ptr().cast(),
+            vtable_name.as_c_char_ptr(),
             vtable_name.len(),
-            linkage_name.as_ptr().cast(),
+            linkage_name.as_c_char_ptr(),
             linkage_name.len(),
             unknown_file_metadata(cx),
             UNKNOWN_LINE_NUMBER,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 966788cf32f..5385d3a9212 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
 use rustc_target::abi::{Align, Endian, Size, TagEncoding, VariantIdx, Variants};
 use smallvec::smallvec;
 
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::metadata::enums::DiscrResult;
 use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
 use crate::debuginfo::metadata::{
@@ -359,7 +359,7 @@ fn build_single_variant_union_fields<'ll, 'tcx>(
             llvm::LLVMRustDIBuilderCreateStaticMemberType(
                 DIB(cx),
                 enum_type_di_node,
-                TAG_FIELD_NAME.as_ptr().cast(),
+                TAG_FIELD_NAME.as_c_char_ptr(),
                 TAG_FIELD_NAME.len(),
                 unknown_file_metadata(cx),
                 UNKNOWN_LINE_NUMBER,
@@ -537,7 +537,7 @@ fn build_variant_struct_wrapper_type_di_node<'ll, 'tcx>(
                     llvm::LLVMRustDIBuilderCreateStaticMemberType(
                         DIB(cx),
                         wrapper_struct_type_di_node,
-                        name.as_ptr().cast(),
+                        name.as_c_char_ptr(),
                         name.len(),
                         unknown_file_metadata(cx),
                         UNKNOWN_LINE_NUMBER,
@@ -785,7 +785,7 @@ fn build_union_fields_for_direct_tag_enum_or_coroutine<'ll, 'tcx>(
             llvm::LLVMRustDIBuilderCreateMemberType(
                 DIB(cx),
                 enum_type_di_node,
-                field_name.as_ptr().cast(),
+                field_name.as_c_char_ptr(),
                 field_name.len(),
                 file_di_node,
                 line_number,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index fe1634146ff..4c848027b55 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -13,7 +13,7 @@ use rustc_target::abi::{FieldIdx, TagEncoding, VariantIdx, Variants};
 
 use super::type_map::{DINodeCreationResult, UniqueTypeId};
 use super::{SmallVec, size_and_align_of};
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::metadata::type_map::{self, Stub};
 use crate::debuginfo::metadata::{
     UNKNOWN_LINE_NUMBER, build_field_di_node, build_generic_type_param_di_nodes, type_di_node,
@@ -106,7 +106,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
             let value = [value as u64, (value >> 64) as u64];
             Some(llvm::LLVMRustDIBuilderCreateEnumerator(
                 DIB(cx),
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
                 value.as_ptr(),
                 size.bits() as libc::c_uint,
@@ -119,7 +119,7 @@ fn build_enumeration_type_di_node<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateEnumerationType(
             DIB(cx),
             containing_scope,
-            type_name.as_ptr().cast(),
+            type_name.as_c_char_ptr(),
             type_name.len(),
             unknown_file_metadata(cx),
             UNKNOWN_LINE_NUMBER,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
index 5e7dbdd921a..b7400c5aeb2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs
@@ -10,7 +10,7 @@ use rustc_middle::ty::{self};
 use rustc_target::abi::{Size, TagEncoding, VariantIdx, Variants};
 use smallvec::smallvec;
 
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::metadata::type_map::{self, Stub, StubInfo, UniqueTypeId};
 use crate::debuginfo::metadata::{
     DINodeCreationResult, NO_GENERICS, SmallVec, UNKNOWN_LINE_NUMBER, file_metadata,
@@ -244,7 +244,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
             llvm::LLVMRustDIBuilderCreateVariantPart(
                 DIB(cx),
                 enum_type_di_node,
-                variant_part_name.as_ptr().cast(),
+                variant_part_name.as_c_char_ptr(),
                 variant_part_name.len(),
                 unknown_file_metadata(cx),
                 UNKNOWN_LINE_NUMBER,
@@ -253,7 +253,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>(
                 DIFlags::FlagZero,
                 tag_member_di_node,
                 create_DIArray(DIB(cx), &[]),
-                variant_part_unique_type_id_str.as_ptr().cast(),
+                variant_part_unique_type_id_str.as_c_char_ptr(),
                 variant_part_unique_type_id_str.len(),
             )
         },
@@ -327,7 +327,7 @@ fn build_discr_member_di_node<'ll, 'tcx>(
                 Some(llvm::LLVMRustDIBuilderCreateMemberType(
                     DIB(cx),
                     containing_scope,
-                    tag_name.as_ptr().cast(),
+                    tag_name.as_c_char_ptr(),
                     tag_name.len(),
                     unknown_file_metadata(cx),
                     UNKNOWN_LINE_NUMBER,
@@ -399,7 +399,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateVariantMemberType(
             DIB(cx),
             variant_part_di_node,
-            variant_member_info.variant_name.as_ptr().cast(),
+            variant_member_info.variant_name.as_c_char_ptr(),
             variant_member_info.variant_name.len(),
             file_di_node,
             line_number,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 714e3c0b145..d050dc9b406 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
 use rustc_target::abi::{Align, Size, VariantIdx};
 
 use super::{SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata};
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::debuginfo::utils::{DIB, create_DIArray, debug_context};
 use crate::llvm::debuginfo::{DIFlags, DIScope, DIType};
 use crate::llvm::{self};
@@ -191,7 +191,7 @@ pub(super) fn stub<'ll, 'tcx>(
                 llvm::LLVMRustDIBuilderCreateStructType(
                     DIB(cx),
                     containing_scope,
-                    name.as_ptr().cast(),
+                    name.as_c_char_ptr(),
                     name.len(),
                     unknown_file_metadata(cx),
                     UNKNOWN_LINE_NUMBER,
@@ -202,7 +202,7 @@ pub(super) fn stub<'ll, 'tcx>(
                     empty_array,
                     0,
                     vtable_holder,
-                    unique_type_id_str.as_ptr().cast(),
+                    unique_type_id_str.as_c_char_ptr(),
                     unique_type_id_str.len(),
                 )
             }
@@ -211,7 +211,7 @@ pub(super) fn stub<'ll, 'tcx>(
             llvm::LLVMRustDIBuilderCreateUnionType(
                 DIB(cx),
                 containing_scope,
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
                 unknown_file_metadata(cx),
                 UNKNOWN_LINE_NUMBER,
@@ -220,7 +220,7 @@ pub(super) fn stub<'ll, 'tcx>(
                 flags,
                 Some(empty_array),
                 0,
-                unique_type_id_str.as_ptr().cast(),
+                unique_type_id_str.as_c_char_ptr(),
                 unique_type_id_str.len(),
             )
         },
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 3de4ca77e7d..72e723aa849 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -31,7 +31,7 @@ use self::namespace::mangled_name_of_instance;
 use self::utils::{DIB, create_DIArray, is_node_local_to_unit};
 use crate::abi::FnAbi;
 use crate::builder::Builder;
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::llvm;
 use crate::llvm::debuginfo::{
     DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
@@ -91,45 +91,39 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
     }
 
     pub(crate) fn finalize(&self, sess: &Session) {
-        unsafe {
-            llvm::LLVMRustDIBuilderFinalize(self.builder);
-
-            if !sess.target.is_like_msvc {
-                // Debuginfo generation in LLVM by default uses a higher
-                // version of dwarf than macOS currently understands. We can
-                // instruct LLVM to emit an older version of dwarf, however,
-                // for macOS to understand. For more info see #11352
-                // This can be overridden using --llvm-opts -dwarf-version,N.
-                // Android has the same issue (#22398)
-                let dwarf_version = sess
-                    .opts
-                    .unstable_opts
-                    .dwarf_version
-                    .unwrap_or(sess.target.default_dwarf_version);
-                llvm::LLVMRustAddModuleFlagU32(
-                    self.llmod,
-                    llvm::LLVMModFlagBehavior::Warning,
-                    c"Dwarf Version".as_ptr(),
-                    dwarf_version,
-                );
-            } else {
-                // Indicate that we want CodeView debug information on MSVC
-                llvm::LLVMRustAddModuleFlagU32(
-                    self.llmod,
-                    llvm::LLVMModFlagBehavior::Warning,
-                    c"CodeView".as_ptr(),
-                    1,
-                )
-            }
-
-            // Prevent bitcode readers from deleting the debug info.
-            llvm::LLVMRustAddModuleFlagU32(
+        unsafe { llvm::LLVMRustDIBuilderFinalize(self.builder) };
+        if !sess.target.is_like_msvc {
+            // Debuginfo generation in LLVM by default uses a higher
+            // version of dwarf than macOS currently understands. We can
+            // instruct LLVM to emit an older version of dwarf, however,
+            // for macOS to understand. For more info see #11352
+            // This can be overridden using --llvm-opts -dwarf-version,N.
+            // Android has the same issue (#22398)
+            let dwarf_version =
+                sess.opts.unstable_opts.dwarf_version.unwrap_or(sess.target.default_dwarf_version);
+            llvm::add_module_flag_u32(
                 self.llmod,
-                llvm::LLVMModFlagBehavior::Warning,
-                c"Debug Info Version".as_ptr(),
-                llvm::LLVMRustDebugMetadataVersion(),
+                llvm::ModuleFlagMergeBehavior::Warning,
+                "Dwarf Version",
+                dwarf_version,
+            );
+        } else {
+            // Indicate that we want CodeView debug information on MSVC
+            llvm::add_module_flag_u32(
+                self.llmod,
+                llvm::ModuleFlagMergeBehavior::Warning,
+                "CodeView",
+                1,
             );
         }
+
+        // Prevent bitcode readers from deleting the debug info.
+        llvm::add_module_flag_u32(
+            self.llmod,
+            llvm::ModuleFlagMergeBehavior::Warning,
+            "Debug Info Version",
+            unsafe { llvm::LLVMRustDebugMetadataVersion() },
+        );
     }
 }
 
@@ -364,7 +358,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
         let mut flags = DIFlags::FlagPrototyped;
 
-        if fn_abi.ret.layout.abi.is_uninhabited() {
+        if fn_abi.ret.layout.is_uninhabited() {
             flags |= DIFlags::FlagNoReturn;
         }
 
@@ -389,9 +383,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             llvm::LLVMRustDIBuilderCreateMethod(
                 DIB(self),
                 containing_scope,
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
-                linkage_name.as_ptr().cast(),
+                linkage_name.as_c_char_ptr(),
                 linkage_name.len(),
                 file_metadata,
                 loc.line,
@@ -406,9 +400,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             llvm::LLVMRustDIBuilderCreateFunction(
                 DIB(self),
                 containing_scope,
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
-                linkage_name.as_ptr().cast(),
+                linkage_name.as_c_char_ptr(),
                 linkage_name.len(),
                 file_metadata,
                 loc.line,
@@ -494,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                                 Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
                                     DIB(cx),
                                     None,
-                                    name.as_ptr().cast(),
+                                    name.as_c_char_ptr(),
                                     name.len(),
                                     actual_type_metadata,
                                 ))
@@ -635,7 +629,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 DIB(self),
                 dwarf_tag,
                 scope_metadata,
-                name.as_ptr().cast(),
+                name.as_c_char_ptr(),
                 name.len(),
                 file_metadata,
                 loc.line,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
index 3578755aae0..33d9bc23890 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, Instance};
 
 use super::utils::{DIB, debug_context};
-use crate::common::CodegenCx;
+use crate::common::{AsCCharPtr, CodegenCx};
 use crate::llvm;
 use crate::llvm::debuginfo::DIScope;
 
@@ -36,7 +36,7 @@ pub(crate) fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'l
         llvm::LLVMRustDIBuilderCreateNameSpace(
             DIB(cx),
             parent_scope,
-            namespace_name_string.as_ptr().cast(),
+            namespace_name_string.as_c_char_ptr(),
             namespace_name_string.len(),
             false, // ExportSymbols (only relevant for C++ anonymous namespaces)
         )
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 33258cb46fa..d338c848754 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -20,6 +20,7 @@ use smallvec::SmallVec;
 use tracing::debug;
 
 use crate::abi::{FnAbi, FnAbiLlvmExt};
+use crate::common::AsCCharPtr;
 use crate::context::CodegenCx;
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::Visibility;
@@ -41,7 +42,7 @@ fn declare_raw_fn<'ll>(
 ) -> &'ll Value {
     debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
     let llfn = unsafe {
-        llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty)
+        llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_c_char_ptr(), name.len(), ty)
     };
 
     llvm::SetFunctionCallConv(llfn, callconv);
@@ -68,7 +69,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     /// return its Value instead.
     pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value {
         debug!("declare_global(name={:?})", name);
-        unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) }
+        unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) }
     }
 
     /// Declare a C ABI function.
@@ -209,7 +210,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
     /// Gets declared value by name.
     pub(crate) fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
         debug!("get_declared_value(name={:?})", name);
-        unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) }
+        unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_c_char_ptr(), name.len()) }
     }
 
     /// Gets defined or externally defined (AvailableExternally linkage) value by
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index c9a17c9852d..d04b5257619 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -785,13 +785,12 @@ fn codegen_msvc_try<'ll>(
         let type_info =
             bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
         let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
-        unsafe {
-            llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
-            if bx.cx.tcx.sess.target.supports_comdat() {
-                llvm::SetUniqueComdat(bx.llmod, tydesc);
-            }
-            llvm::LLVMSetInitializer(tydesc, type_info);
+
+        llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
+        if bx.cx.tcx.sess.target.supports_comdat() {
+            llvm::SetUniqueComdat(bx.llmod, tydesc);
         }
+        unsafe { llvm::LLVMSetInitializer(tydesc, type_info) };
 
         // The flag value of 8 indicates that we are catching the exception by
         // reference instead of by value. We can't use catch by value because
@@ -1064,7 +1063,7 @@ fn gen_fn<'ll, 'tcx>(
     cx.set_frame_pointer_type(llfn);
     cx.apply_target_cpu_attr(llfn);
     // FIXME(eddyb) find a nicer way to do this.
-    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
+    llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
     let llbb = Builder::append_block(cx, llfn, "entry-block");
     let bx = Builder::build(cx, llbb);
     codegen(bx);
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 10e55a4f7f6..8fc586d2c8f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1,9 +1,12 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
+use std::fmt::Debug;
 use std::marker::PhantomData;
+use std::ptr;
 
 use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
+use rustc_macros::TryFromU32;
 use rustc_target::spec::SymbolVisibility;
 
 use super::RustString;
@@ -19,6 +22,30 @@ pub type Bool = c_uint;
 pub const True: Bool = 1 as Bool;
 pub const False: Bool = 0 as Bool;
 
+/// Wrapper for a raw enum value returned from LLVM's C APIs.
+///
+/// For C enums returned by LLVM, it's risky to use a Rust enum as the return
+/// type, because it would be UB if a later version of LLVM adds a new enum
+/// value and returns it. Instead, return this raw wrapper, then convert to the
+/// Rust-side enum explicitly.
+#[repr(transparent)]
+pub struct RawEnum<T> {
+    value: u32,
+    /// We don't own or consume a `T`, but we can produce one.
+    _rust_side_type: PhantomData<fn() -> T>,
+}
+
+impl<T: TryFrom<u32>> RawEnum<T> {
+    #[track_caller]
+    pub(crate) fn to_rust(self) -> T
+    where
+        T::Error: Debug,
+    {
+        // If this fails, the Rust-side enum is out of sync with LLVM's enum.
+        T::try_from(self.value).expect("enum value returned by LLVM should be known")
+    }
+}
+
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 #[allow(dead_code)] // Variants constructed by C++.
@@ -59,7 +86,7 @@ pub enum LLVMMachineType {
     ARM = 0x01c0,
 }
 
-/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h.
+/// Must match the layout of `LLVMRustModuleFlagMergeBehavior`.
 ///
 /// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
 /// resolved according to the merge behaviors specified here. Flags differing only in merge
@@ -67,9 +94,13 @@ pub enum LLVMMachineType {
 ///
 /// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably,
 /// 'Error' and 'Warning' cannot be mixed for a given flag.
+///
+/// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`),
+/// but as of LLVM 19 it does not support all of the enum values in the unstable
+/// C++ API.
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
-pub enum LLVMModFlagBehavior {
+pub enum ModuleFlagMergeBehavior {
     Error = 1,
     Warning = 2,
     Require = 3,
@@ -108,26 +139,36 @@ pub enum CallConv {
     AvrInterrupt = 85,
 }
 
-/// LLVMRustLinkage
-#[derive(Copy, Clone, PartialEq)]
+/// Must match the layout of `LLVMLinkage`.
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 #[repr(C)]
 pub enum Linkage {
     ExternalLinkage = 0,
     AvailableExternallyLinkage = 1,
     LinkOnceAnyLinkage = 2,
     LinkOnceODRLinkage = 3,
-    WeakAnyLinkage = 4,
-    WeakODRLinkage = 5,
-    AppendingLinkage = 6,
-    InternalLinkage = 7,
-    PrivateLinkage = 8,
-    ExternalWeakLinkage = 9,
-    CommonLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    LinkOnceODRAutoHideLinkage = 4,
+    WeakAnyLinkage = 5,
+    WeakODRLinkage = 6,
+    AppendingLinkage = 7,
+    InternalLinkage = 8,
+    PrivateLinkage = 9,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLImportLinkage = 10,
+    #[deprecated = "marked obsolete by LLVM"]
+    DLLExportLinkage = 11,
+    ExternalWeakLinkage = 12,
+    #[deprecated = "marked obsolete by LLVM"]
+    GhostLinkage = 13,
+    CommonLinkage = 14,
+    LinkerPrivateLinkage = 15,
+    LinkerPrivateWeakLinkage = 16,
 }
 
-// LLVMRustVisibility
+/// Must match the layout of `LLVMVisibility`.
 #[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, PartialEq, TryFromU32)]
 pub enum Visibility {
     Default = 0,
     Hidden = 1,
@@ -668,8 +709,9 @@ unsafe extern "C" {
 }
 #[repr(C)]
 pub struct RustArchiveMember<'a>(InvariantOpaque<'a>);
+/// Opaque pointee of `LLVMOperandBundleRef`.
 #[repr(C)]
-pub struct OperandBundleDef<'a>(InvariantOpaque<'a>);
+pub(crate) struct OperandBundle<'a>(InvariantOpaque<'a>);
 #[repr(C)]
 pub struct Linker<'a>(InvariantOpaque<'a>);
 
@@ -945,7 +987,11 @@ unsafe extern "C" {
 
     // Operations on global variables, functions, and aliases (globals)
     pub fn LLVMIsDeclaration(Global: &Value) -> Bool;
+    pub fn LLVMGetLinkage(Global: &Value) -> RawEnum<Linkage>;
+    pub fn LLVMSetLinkage(Global: &Value, RustLinkage: Linkage);
     pub fn LLVMSetSection(Global: &Value, Section: *const c_char);
+    pub fn LLVMGetVisibility(Global: &Value) -> RawEnum<Visibility>;
+    pub fn LLVMSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMGetAlignment(Global: &Value) -> c_uint;
     pub fn LLVMSetAlignment(Global: &Value, Bytes: c_uint);
     pub fn LLVMSetDLLStorageClass(V: &Value, C: DLLStorageClass);
@@ -1494,6 +1540,50 @@ unsafe extern "C" {
 
     pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat;
     pub fn LLVMSetComdat(V: &Value, C: &Comdat);
+
+    pub(crate) fn LLVMCreateOperandBundle(
+        Tag: *const c_char,
+        TagLen: size_t,
+        Args: *const &'_ Value,
+        NumArgs: c_uint,
+    ) -> *mut OperandBundle<'_>;
+    pub(crate) fn LLVMDisposeOperandBundle(Bundle: ptr::NonNull<OperandBundle<'_>>);
+
+    pub(crate) fn LLVMBuildCallWithOperandBundles<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
+    pub(crate) fn LLVMBuildInvokeWithOperandBundles<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Then: &'a BasicBlock,
+        Catch: &'a BasicBlock,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
+    pub(crate) fn LLVMBuildCallBr<'a>(
+        B: &Builder<'a>,
+        Ty: &'a Type,
+        Fn: &'a Value,
+        DefaultDest: &'a BasicBlock,
+        IndirectDests: *const &'a BasicBlock,
+        NumIndirectDests: c_uint,
+        Args: *const &'a Value,
+        NumArgs: c_uint,
+        Bundles: *const &OperandBundle<'a>,
+        NumBundles: c_uint,
+        Name: *const c_char,
+    ) -> &'a Value;
 }
 
 #[link(name = "llvm-wrapper", kind = "static")]
@@ -1521,10 +1611,6 @@ unsafe extern "C" {
     ) -> bool;
 
     // Operations on global variables, functions, and aliases (globals)
-    pub fn LLVMRustGetLinkage(Global: &Value) -> Linkage;
-    pub fn LLVMRustSetLinkage(Global: &Value, RustLinkage: Linkage);
-    pub fn LLVMRustGetVisibility(Global: &Value) -> Visibility;
-    pub fn LLVMRustSetVisibility(Global: &Value, Viz: Visibility);
     pub fn LLVMRustSetDSOLocal(Global: &Value, is_dso_local: bool);
 
     // Operations on global variables
@@ -1583,47 +1669,11 @@ unsafe extern "C" {
         AttrsLen: size_t,
     );
 
-    pub fn LLVMRustBuildInvoke<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        Then: &'a BasicBlock,
-        Catch: &'a BasicBlock,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-        Name: *const c_char,
-    ) -> &'a Value;
-
-    pub fn LLVMRustBuildCallBr<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        DefaultDest: &'a BasicBlock,
-        IndirectDests: *const &'a BasicBlock,
-        NumIndirectDests: c_uint,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-        Name: *const c_char,
-    ) -> &'a Value;
-
     pub fn LLVMRustSetFastMath(Instr: &Value);
     pub fn LLVMRustSetAlgebraicMath(Instr: &Value);
     pub fn LLVMRustSetAllowReassoc(Instr: &Value);
 
     // Miscellaneous instructions
-    pub fn LLVMRustBuildCall<'a>(
-        B: &Builder<'a>,
-        Ty: &'a Type,
-        Fn: &'a Value,
-        Args: *const &'a Value,
-        NumArgs: c_uint,
-        OpBundles: *const &OperandBundleDef<'a>,
-        NumOpBundles: c_uint,
-    ) -> &'a Value;
     pub fn LLVMRustBuildMemCpy<'a>(
         B: &Builder<'a>,
         Dst: &'a Value,
@@ -1793,21 +1843,21 @@ unsafe extern "C" {
     /// "compatible" means depends on the merge behaviors involved.
     pub fn LLVMRustAddModuleFlagU32(
         M: &Module,
-        merge_behavior: LLVMModFlagBehavior,
-        name: *const c_char,
-        value: u32,
+        MergeBehavior: ModuleFlagMergeBehavior,
+        Name: *const c_char,
+        NameLen: size_t,
+        Value: u32,
     );
 
     pub fn LLVMRustAddModuleFlagString(
         M: &Module,
-        merge_behavior: LLVMModFlagBehavior,
-        name: *const c_char,
-        value: *const c_char,
-        value_len: size_t,
+        MergeBehavior: ModuleFlagMergeBehavior,
+        Name: *const c_char,
+        NameLen: size_t,
+        Value: *const c_char,
+        ValueLen: size_t,
     );
 
-    pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
-
     pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
 
     pub fn LLVMRustDIBuilderDispose<'a>(Builder: &'a mut DIBuilder<'a>);
@@ -2317,13 +2367,6 @@ unsafe extern "C" {
 
     pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine);
 
-    pub fn LLVMRustBuildOperandBundleDef(
-        Name: *const c_char,
-        Inputs: *const &'_ Value,
-        NumInputs: c_uint,
-    ) -> &mut OperandBundleDef<'_>;
-    pub fn LLVMRustFreeOperandBundleDef<'a>(Bundle: &'a mut OperandBundleDef<'a>);
-
     pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
 
     pub fn LLVMRustSetModulePICLevel(M: &Module);
@@ -2349,9 +2392,9 @@ unsafe extern "C" {
     pub fn LLVMRustThinLTOBufferThinLinkDataLen(M: &ThinLTOBuffer) -> size_t;
     pub fn LLVMRustCreateThinLTOData(
         Modules: *const ThinLTOModule,
-        NumModules: c_uint,
+        NumModules: size_t,
         PreservedSymbols: *const *const c_char,
-        PreservedSymbolsLen: c_uint,
+        PreservedSymbolsLen: size_t,
     ) -> Option<&'static mut ThinLTOData>;
     pub fn LLVMRustPrepareThinLTORename(
         Data: &ThinLTOData,
@@ -2376,6 +2419,7 @@ unsafe extern "C" {
         data: *const u8,
         len: usize,
         name: *const u8,
+        name_len: usize,
         out_len: &mut usize,
     ) -> *const u8;
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index e837022044e..00a5cd3b859 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -2,11 +2,12 @@
 
 use std::cell::RefCell;
 use std::ffi::{CStr, CString};
+use std::ops::Deref;
+use std::ptr;
 use std::str::FromStr;
 use std::string::FromUtf8Error;
 
 use libc::c_uint;
-use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_llvm::RustString;
 use rustc_target::abi::{Align, Size, WrappingRange};
 
@@ -17,13 +18,13 @@ pub use self::IntPredicate::*;
 pub use self::Linkage::*;
 pub use self::MetadataType::*;
 pub use self::RealPredicate::*;
+pub use self::ffi::*;
+use crate::common::AsCCharPtr;
 
 pub mod archive_ro;
 pub mod diagnostic;
 mod ffi;
 
-pub use self::ffi::*;
-
 impl LLVMRustResult {
     pub fn into_result(self) -> Result<(), ()> {
         match self {
@@ -53,9 +54,9 @@ pub fn CreateAttrStringValue<'ll>(llcx: &'ll Context, attr: &str, value: &str) -
     unsafe {
         LLVMCreateStringAttribute(
             llcx,
-            attr.as_ptr().cast(),
+            attr.as_c_char_ptr(),
             attr.len().try_into().unwrap(),
-            value.as_ptr().cast(),
+            value.as_c_char_ptr(),
             value.len().try_into().unwrap(),
         )
     }
@@ -65,7 +66,7 @@ pub fn CreateAttrString<'ll>(llcx: &'ll Context, attr: &str) -> &'ll Attribute {
     unsafe {
         LLVMCreateStringAttribute(
             llcx,
-            attr.as_ptr().cast(),
+            attr.as_c_char_ptr(),
             attr.len().try_into().unwrap(),
             std::ptr::null(),
             0,
@@ -232,15 +233,23 @@ pub fn set_global_constant(llglobal: &Value, is_constant: bool) {
     }
 }
 
+pub fn get_linkage(llglobal: &Value) -> Linkage {
+    unsafe { LLVMGetLinkage(llglobal) }.to_rust()
+}
+
 pub fn set_linkage(llglobal: &Value, linkage: Linkage) {
     unsafe {
-        LLVMRustSetLinkage(llglobal, linkage);
+        LLVMSetLinkage(llglobal, linkage);
     }
 }
 
+pub fn get_visibility(llglobal: &Value) -> Visibility {
+    unsafe { LLVMGetVisibility(llglobal) }.to_rust()
+}
+
 pub fn set_visibility(llglobal: &Value, visibility: Visibility) {
     unsafe {
-        LLVMRustSetVisibility(llglobal, visibility);
+        LLVMSetVisibility(llglobal, visibility);
     }
 }
 
@@ -286,7 +295,7 @@ pub fn get_value_name(value: &Value) -> &[u8] {
 /// Safe wrapper for `LLVMSetValueName2` from a byte slice
 pub fn set_value_name(value: &Value, name: &[u8]) {
     unsafe {
-        let data = name.as_ptr().cast();
+        let data = name.as_c_char_ptr();
         LLVMSetValueName2(value, data, name.len());
     }
 }
@@ -323,24 +332,68 @@ pub fn last_error() -> Option<String> {
     }
 }
 
-pub struct OperandBundleDef<'a> {
-    pub raw: &'a mut ffi::OperandBundleDef<'a>,
+/// Owns an [`OperandBundle`], and will dispose of it when dropped.
+pub(crate) struct OperandBundleOwned<'a> {
+    raw: ptr::NonNull<OperandBundle<'a>>,
 }
 
-impl<'a> OperandBundleDef<'a> {
-    pub fn new(name: &str, vals: &[&'a Value]) -> Self {
-        let name = SmallCStr::new(name);
-        let def = unsafe {
-            LLVMRustBuildOperandBundleDef(name.as_ptr(), vals.as_ptr(), vals.len() as c_uint)
+impl<'a> OperandBundleOwned<'a> {
+    pub(crate) fn new(name: &str, vals: &[&'a Value]) -> Self {
+        let raw = unsafe {
+            LLVMCreateOperandBundle(
+                name.as_c_char_ptr(),
+                name.len(),
+                vals.as_ptr(),
+                vals.len() as c_uint,
+            )
         };
-        OperandBundleDef { raw: def }
+        OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() }
     }
 }
 
-impl Drop for OperandBundleDef<'_> {
+impl Drop for OperandBundleOwned<'_> {
     fn drop(&mut self) {
         unsafe {
-            LLVMRustFreeOperandBundleDef(&mut *(self.raw as *mut _));
+            LLVMDisposeOperandBundle(self.raw);
         }
     }
 }
+
+impl<'a> Deref for OperandBundleOwned<'a> {
+    type Target = OperandBundle<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The returned reference is opaque and can only used for FFI.
+        // It is valid for as long as `&self` is.
+        unsafe { self.raw.as_ref() }
+    }
+}
+
+pub(crate) fn add_module_flag_u32(
+    module: &Module,
+    merge_behavior: ModuleFlagMergeBehavior,
+    key: &str,
+    value: u32,
+) {
+    unsafe {
+        LLVMRustAddModuleFlagU32(module, merge_behavior, key.as_c_char_ptr(), key.len(), value);
+    }
+}
+
+pub(crate) fn add_module_flag_str(
+    module: &Module,
+    merge_behavior: ModuleFlagMergeBehavior,
+    key: &str,
+    value: &str,
+) {
+    unsafe {
+        LLVMRustAddModuleFlagString(
+            module,
+            merge_behavior,
+            key.as_c_char_ptr(),
+            key.len(),
+            value.as_c_char_ptr(),
+            value.len(),
+        );
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 57936215ff1..9adb1299b3d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -248,6 +248,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")),
         ("aarch64", "paca") => Some(LLVMFeature::new("pauth")),
         ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")),
+        ("aarch64", "pauth-lr") if get_version().0 < 19 => None,
         // Before LLVM 20 those two features were packaged together as b16b16
         ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
         ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
@@ -697,12 +698,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
     let feature = s
         .strip_prefix(&['+', '-'][..])
         .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
-    if s.is_empty() {
-        return None;
-    }
     // Rustc-specific feature requests like `+crt-static` or `-crt-static`
     // are not passed down to LLVM.
-    if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
+    if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
         return None;
     }
     Some(feature)
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index bf6ef219873..ea8857b4739 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -39,9 +39,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
                 .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
+        llvm::set_linkage(g, base::linkage_to_llvm(linkage));
+        llvm::set_visibility(g, base::visibility_to_llvm(visibility));
         unsafe {
-            llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
-            llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
             if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
@@ -61,7 +61,7 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
 
         let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
-        unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
+        llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
         base::set_link_section(lldecl, attrs);
         if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
@@ -78,21 +78,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
             && linkage != Linkage::Private
             && self.tcx.is_compiler_builtins(LOCAL_CRATE)
         {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
-            }
+            llvm::set_visibility(lldecl, llvm::Visibility::Hidden);
         } else {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
-            }
+            llvm::set_visibility(lldecl, base::visibility_to_llvm(visibility));
         }
 
         debug!("predefine_fn: instance = {:?}", instance);
 
-        unsafe {
-            if self.should_assume_dso_local(lldecl, false) {
-                llvm::LLVMRustSetDSOLocal(lldecl, true);
-            }
+        if self.should_assume_dso_local(lldecl, false) {
+            unsafe { llvm::LLVMRustSetDSOLocal(lldecl, true) };
         }
 
         self.instances.borrow_mut().insert(instance, lldecl);
@@ -102,13 +96,13 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
 impl CodegenCx<'_, '_> {
     /// Whether a definition or declaration can be assumed to be local to a group of
     /// libraries that form a single DSO or executable.
-    pub(crate) unsafe fn should_assume_dso_local(
+    pub(crate) fn should_assume_dso_local(
         &self,
         llval: &llvm::Value,
         is_declaration: bool,
     ) -> bool {
-        let linkage = unsafe { llvm::LLVMRustGetLinkage(llval) };
-        let visibility = unsafe { llvm::LLVMRustGetVisibility(llval) };
+        let linkage = llvm::get_linkage(llval);
+        let visibility = llvm::get_visibility(llval);
 
         if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
             return true;
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index e3d11cfaf4f..8445d16befb 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -514,7 +514,7 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
             future: Some(coordinator_thread),
             phantom: PhantomData,
         },
-        output_filenames: tcx.output_filenames(()).clone(),
+        output_filenames: Arc::clone(tcx.output_filenames(())),
     }
 }
 
@@ -1203,7 +1203,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         coordinator_send,
         expanded_args: tcx.sess.expanded_args.clone(),
         diag_emitter: shared_emitter.clone(),
-        output_filenames: tcx.output_filenames(()).clone(),
+        output_filenames: Arc::clone(tcx.output_filenames(())),
         regular_module_config: regular_config,
         metadata_module_config: metadata_config,
         allocator_module_config: allocator_config,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index a726ee73aaa..cb4c9c078b1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -7,7 +7,7 @@ use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_n
 use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
-use rustc_data_structures::sync::par_map;
+use rustc_data_structures::sync::{Lrc, par_map};
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
@@ -21,7 +21,7 @@ use rustc_middle::mir::BinOp;
 use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypingMode};
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
 use rustc_span::symbol::sym;
@@ -119,7 +119,7 @@ pub fn validate_trivial_unsize<'tcx>(
 ) -> bool {
     match (source_data.principal(), target_data.principal()) {
         (Some(hr_source_principal), Some(hr_target_principal)) => {
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
             let universe = infcx.universe();
             let ocx = ObligationCtxt::new(&infcx);
             infcx.enter_forall(hr_target_principal, |target_principal| {
@@ -923,7 +923,7 @@ impl CrateInfo {
             crate_name: UnordMap::with_capacity(n_crates),
             used_crates,
             used_crate_source: UnordMap::with_capacity(n_crates),
-            dependency_formats: tcx.dependency_formats(()).clone(),
+            dependency_formats: Lrc::clone(tcx.dependency_formats(())),
             windows_subsystem,
             natvis_debugger_visualizers: Default::default(),
         };
@@ -936,7 +936,7 @@ impl CrateInfo {
             info.crate_name.insert(cnum, tcx.crate_name(cnum));
 
             let used_crate_source = tcx.used_crate_source(cnum);
-            info.used_crate_source.insert(cnum, used_crate_source.clone());
+            info.used_crate_source.insert(cnum, Lrc::clone(used_crate_source));
             if tcx.is_profiler_runtime(cnum) {
                 info.profiler_runtime = Some(cnum);
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e3553dc03e1..a17a127f014 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -438,7 +438,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 _ => bug!("C-variadic function must have a `VaList` place"),
             }
         }
-        if self.fn_abi.ret.layout.abi.is_uninhabited() {
+        if self.fn_abi.ret.layout.is_uninhabited() {
             // Functions with uninhabited return values are marked `noreturn`,
             // so we should make sure that we never actually do.
             // We play it safe by using a well-defined `abort`, but we could go for immediate UB
@@ -774,7 +774,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             Some(if do_panic {
                 let msg_str = with_no_visible_paths!({
                     with_no_trimmed_paths!({
-                        if layout.abi.is_uninhabited() {
+                        if layout.is_uninhabited() {
                             // Use this error even for the other intrinsics as it is more precise.
                             format!("attempted to instantiate uninhabited type `{ty}`")
                         } else if requirement == ValidityRequirement::Zero {
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index a7d5541481a..15c8e534461 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -55,7 +55,7 @@ impl<V: CodegenObject> PlaceValue<V> {
     /// Creates a `PlaceRef` to this location with the given type.
     pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
         assert!(
-            layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
+            layout.is_unsized() || layout.is_uninhabited() || self.llextra.is_none(),
             "Had pointer metadata {:?} for sized type {layout:?}",
             self.llextra,
         );
@@ -239,7 +239,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         let dl = &bx.tcx().data_layout;
         let cast_to_layout = bx.cx().layout_of(cast_to);
         let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
-        if self.layout.abi.is_uninhabited() {
+        if self.layout.is_uninhabited() {
             return bx.cx().const_poison(cast_to);
         }
         let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
@@ -358,7 +358,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
         bx: &mut Bx,
         variant_index: VariantIdx,
     ) {
-        if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
+        if self.layout.for_variant(bx.cx(), variant_index).is_uninhabited() {
             // We play it safe by using a well-defined `abort`, but we could go for immediate UB
             // if that turns out to be helpful.
             bx.abort();
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 82fea4c58e1..6e8c193cd75 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -203,10 +203,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Option<OperandValue<Bx::Value>> {
         // Check for transmutes that are always UB.
         if operand.layout.size != cast.size
-            || operand.layout.abi.is_uninhabited()
-            || cast.abi.is_uninhabited()
+            || operand.layout.is_uninhabited()
+            || cast.is_uninhabited()
         {
-            if !operand.layout.abi.is_uninhabited() {
+            if !operand.layout.is_uninhabited() {
                 // Since this is known statically and the input could have existed
                 // without already having hit UB, might as well trap for it.
                 bx.abort();
@@ -555,7 +555,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
                         assert!(bx.cx().is_backend_immediate(cast));
                         let to_backend_ty = bx.cx().immediate_backend_type(cast);
-                        if operand.layout.abi.is_uninhabited() {
+                        if operand.layout.is_uninhabited() {
                             let val = OperandValue::Immediate(bx.cx().const_poison(to_backend_ty));
                             return OperandRef { val, layout: cast };
                         }
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 004fb12419f..5210241d5e4 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -16,7 +16,7 @@ use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt, TypingMode};
 use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -64,8 +64,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsDrop, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -94,8 +93,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -124,8 +122,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
             let ConstCx { tcx, body, .. } = *ccx;
 
             FlowSensitiveAnalysis::new(HasMutInterior, ccx)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, None)
                 .into_results_cursor(body)
         });
 
@@ -240,8 +237,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
                 let always_live_locals = &always_storage_live_locals(&ccx.body);
                 let mut maybe_storage_live =
                     MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
-                        .into_engine(ccx.tcx, &ccx.body)
-                        .iterate_to_fixpoint()
+                        .iterate_to_fixpoint(ccx.tcx, &ccx.body, None)
                         .into_results_cursor(&ccx.body);
 
                 // And then check all `Return` in the MIR, and if a local is "maybe live" at a
@@ -593,7 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
                 // which path expressions are getting called on and which path expressions are only used
                 // as function pointers. This is required for correctness.
-                let infcx = tcx.infer_ctxt().build();
+                let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
                 let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 3ac06ae6491..3f977dc4b05 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::CallSource;
 use rustc_middle::span_bug;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty,
+    self, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, TypingMode,
     suggest_constraining_type_param,
 };
 use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind};
@@ -116,7 +116,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     let obligation =
                         Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
 
-                    let infcx = tcx.infer_ctxt().build();
+                    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
                     let mut selcx = SelectionContext::new(&infcx);
                     let implsrc = selcx.select(&obligation);
 
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 547030a1854..e8637ba45cf 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -114,11 +114,11 @@ impl Qualif for HasMutInterior {
             ty::TraitRef::new(cx.tcx, freeze_def_id, [ty::GenericArg::from(ty)]),
         );
 
-        let infcx = cx
-            .tcx
-            .infer_ctxt()
-            .with_opaque_type_inference(cx.body.source.def_id().expect_local())
-            .build();
+        // FIXME(#132279): This should eventually use the already defined hidden types.
+        let infcx = cx.tcx.infer_ctxt().build(ty::TypingMode::analysis_in_body(
+            cx.tcx,
+            cx.body.source.def_id().expect_local(),
+        ));
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(obligation);
         let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index d54c5b750f0..5f0bc8539ee 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -395,7 +395,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
 
     #[inline(always)]
     fn enforce_validity(ecx: &InterpCx<'tcx, Self>, layout: TyAndLayout<'tcx>) -> bool {
-        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.abi.is_uninhabited()
+        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks || layout.is_uninhabited()
     }
 
     fn load_mir(
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 81e0b1e12ca..feed0860679 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -27,7 +27,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // discriminant, so we cannot do anything here.
         // When evaluating we will always error before even getting here, but ConstProp 'executes'
         // dead code, so we cannot ICE here.
-        if dest.layout().for_variant(self, variant_index).abi.is_uninhabited() {
+        if dest.layout().for_variant(self, variant_index).is_uninhabited() {
             throw_ub!(UninhabitedEnumVariantWritten(variant_index))
         }
 
@@ -86,7 +86,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     // For consistency with `write_discriminant`, and to make sure that
                     // `project_downcast` cannot fail due to strange layouts, we declare immediate UB
                     // for uninhabited variants.
-                    if op.layout().for_variant(self, index).abi.is_uninhabited() {
+                    if op.layout().for_variant(self, index).is_uninhabited() {
                         throw_ub!(UninhabitedEnumVariantRead(index))
                     }
                 }
@@ -203,7 +203,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         // Reading the discriminant of an uninhabited variant is UB. This is the basis for the
         // `uninhabited_enum_branching` MIR pass. It also ensures consistency with
         // `write_discriminant`.
-        if op.layout().for_variant(self, index).abi.is_uninhabited() {
+        if op.layout().for_variant(self, index).is_uninhabited() {
             throw_ub!(UninhabitedEnumVariantRead(index))
         }
         interp_ok(index)
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index a1c773a4b80..d81368e9fcc 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -9,7 +9,9 @@ use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::{
     self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
 };
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
+use rustc_middle::ty::{
+    self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypingMode, Variance,
+};
 use rustc_middle::{mir, span_bug};
 use rustc_session::Limit;
 use rustc_span::Span;
@@ -325,7 +327,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             return true;
         }
         // Slow path: spin up an inference context to check if these traits are sufficiently equal.
-        let infcx = self.tcx.infer_ctxt().build();
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
         let ocx = ObligationCtxt::new(&infcx);
         let cause = ObligationCause::dummy_with_span(self.cur_span());
         // equate the two trait refs after normalization
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 4e603f57c56..6148123bdfe 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -364,7 +364,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     let msg = match requirement {
                         // For *all* intrinsics we first check `is_uninhabited` to give a more specific
                         // error message.
-                        _ if layout.abi.is_uninhabited() => format!(
+                        _ if layout.is_uninhabited() => format!(
                             "aborted execution: attempted to instantiate uninhabited type `{ty}`"
                         ),
                         ValidityRequirement::Inhabited => bug!("handled earlier"),
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index b28ac68ac54..380db907481 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -315,7 +315,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 let ptr = left.to_scalar().to_pointer(self)?;
                 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
                 let pointee_layout = self.layout_of(pointee_ty)?;
-                assert!(pointee_layout.abi.is_sized());
+                assert!(pointee_layout.is_sized());
 
                 // The size always fits in `i64` as it can be at most `isize::MAX`.
                 let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
@@ -518,14 +518,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         interp_ok(match null_op {
             SizeOf => {
-                if !layout.abi.is_sized() {
+                if !layout.is_sized() {
                     span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`");
                 }
                 let val = layout.size.bytes();
                 ImmTy::from_uint(val, usize_layout())
             }
             AlignOf => {
-                if !layout.abi.is_sized() {
+                if !layout.is_sized() {
                     span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`");
                 }
                 let val = layout.align.abi.bytes();
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index b6120ce82fe..8b5bb1332e7 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -542,7 +542,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
             throw_validation_failure!(self.path, NullPtr { ptr_kind })
         }
         // Do not allow references to uninhabited types.
-        if place.layout.abi.is_uninhabited() {
+        if place.layout.is_uninhabited() {
             let ty = place.layout.ty;
             throw_validation_failure!(self.path, PtrToUninhabited { ptr_kind, ty })
         }
@@ -867,7 +867,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
     /// Add the entire given place to the "data" range of this visit.
     fn add_data_range_place(&mut self, place: &PlaceTy<'tcx, M::Provenance>) {
         // Only sized places can be added this way.
-        debug_assert!(place.layout.abi.is_sized());
+        debug_assert!(place.layout.is_sized());
         if let Some(data_bytes) = self.data_bytes.as_mut() {
             let offset = Self::data_range_offset(self.ecx, place);
             data_bytes.add_range(offset, place.layout.size);
@@ -945,7 +945,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
         layout: TyAndLayout<'tcx>,
     ) -> Cow<'e, RangeSet> {
         assert!(layout.ty.is_union());
-        assert!(layout.abi.is_sized(), "there are no unsized unions");
+        assert!(layout.is_sized(), "there are no unsized unions");
         let layout_cx = LayoutCx::new(*ecx.tcx, ecx.param_env);
         return M::cached_union_data_range(ecx, layout.ty, || {
             let mut out = RangeSet(Vec::new());
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 649179d5b1e..7a8b976dfc4 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -29,7 +29,7 @@ pub fn check_validity_requirement<'tcx>(
 
     // There is nothing strict or lax about inhabitedness.
     if kind == ValidityRequirement::Inhabited {
-        return Ok(!layout.abi.is_uninhabited());
+        return Ok(!layout.is_uninhabited());
     }
 
     let layout_cx = LayoutCx::new(tcx, param_env_and_ty.param_env);
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 3ea54146fc7..7af977bab4d 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -5,7 +5,7 @@
 
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, TypingMode, Variance};
 use rustc_trait_selection::traits::ObligationCtxt;
 
 /// Returns whether the two types are equal up to subtyping.
@@ -45,7 +45,8 @@ pub fn relate_types<'tcx>(
     }
 
     let mut builder = tcx.infer_ctxt().ignoring_regions();
-    let infcx = builder.build();
+    // FIXME(#132279): This should eventually use the already defined hidden types.
+    let infcx = builder.build(TypingMode::from_param_env(param_env));
     let ocx = ObligationCtxt::new(&infcx);
     let cause = ObligationCause::dummy();
     let src = ocx.normalize(&cause, param_env, src);
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index a59dea557bb..e2585c02388 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -1395,7 +1395,7 @@ pub fn install_ice_hook(
     }
 
     let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
-    let using_internal_features_hook = using_internal_features.clone();
+    let using_internal_features_hook = Arc::clone(&using_internal_features);
     panic::update_hook(Box::new(
         move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static),
               info: &PanicHookInfo<'_>| {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index cd28afbc48d..6b2e23ba2d8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -45,6 +45,7 @@ const fn unstable_fn() {}
 #[stable(feature = "stable_struct", since = "1.39.0")] // ok!
 struct Stable;
 
+#[stable(feature = "stable_fn", since = "1.39.0")]
 #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
 const fn stable_fn() {}
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
index be186dbd2cc..70590f2e48e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0542.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -30,6 +30,7 @@ To fix this issue, you need to provide the `since` field. Example:
 #[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
 fn _stable_fn() {}
 
+#[stable(feature = "_stable_const_fn", since = "1.0.0")]
 #[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
 const fn _stable_const_fn() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0667.md b/compiler/rustc_error_codes/src/error_codes/E0667.md
index 0709a24c433..339bc068610 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0667.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0667.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 `impl Trait` is not allowed in path parameters.
 
 Erroneous code example:
 
-```compile_fail,E0667
+```ignore (removed error code)
 fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
     x.next().unwrap()
 }
@@ -11,7 +13,7 @@ fn some_fn(mut x: impl Iterator) -> <impl Iterator>::Item { // error!
 You cannot use `impl Trait` in path parameters. If you want something
 equivalent, you can do this instead:
 
-```
+```ignore (removed error code)
 fn some_fn<T: Iterator>(mut x: T) -> T::Item { // ok!
     x.next().unwrap()
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0801.md b/compiler/rustc_error_codes/src/error_codes/E0801.md
new file mode 100644
index 00000000000..c89feb9b308
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0801.md
@@ -0,0 +1,51 @@
+The `self` parameter in a method has an invalid generic "receiver type".
+
+Erroneous code example:
+
+```compile_fail,E0801
+struct Foo;
+
+impl Foo {
+    fn foo<R: std::ops::Deref<Target=Self>>(self: R) {}
+}
+```
+
+or alternatively,
+
+```compile_fail,E0801
+struct Foo;
+
+impl Foo {
+    fn foo(self: impl std::ops::Deref<Target=Self>) {}
+}
+```
+
+Methods take a special first parameter, termed `self`. It's normal to
+use `self`, `&self` or `&mut self`, which are syntactic sugar for
+`self: Self`, `self: &Self`, and `self: &mut Self` respectively.
+But it's also possible to use more sophisticated types of `self`
+parameter, for instance `std::rc::Rc<Self>`. The set of allowable
+`Self` types is extensible using the nightly feature
+[Arbitrary self types][AST].
+This will extend the valid set of `Self` types to anything which implements
+`std::ops::Deref<Target=Self>`, for example `Rc<Self>`, `Box<Self>`, or
+your own smart pointers that do the same.
+
+However, even with that feature, the `self` type must be concrete.
+Generic `self` types are not permitted. Specifically, a `self` type will
+be rejected if it is a type parameter defined on the method.
+
+These are OK:
+
+```
+struct Foo;
+
+impl Foo {
+    fn foo(self) {}
+    fn foo2(self: std::rc::Rc<Self>) {} // or some other similar
+        // smart pointer if you enable arbitrary self types and
+        // the pointer implements Deref<Target=Self>
+}
+```
+
+[AST]: https://doc.rust-lang.org/unstable-book/language-features/arbitrary-self-types.html
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 27a34d6003d..29f3277d399 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -540,6 +540,7 @@ E0797: 0797,
 E0798: 0798,
 E0799: 0799,
 E0800: 0800,
+E0801: 0801,
         );
     )
 }
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 00eaf4d5a86..41ebe4ae267 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 # tidy-alphabetical-start
 annotate-snippets = "0.11"
 derive_setters = "0.1.6"
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 335432c9cfe..b4a651b10b1 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -173,7 +173,7 @@ impl AnnotateSnippetEmitter {
                             source_map.ensure_source_file_source_present(&file);
                             (
                                 format!("{}", source_map.filename_for_diagnostics(&file.name)),
-                                source_string(file.clone(), &line),
+                                source_string(Lrc::clone(&file), &line),
                                 line.line_index,
                                 line.annotations,
                             )
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 19529f06ef1..09a608dda7b 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -5,12 +5,12 @@ use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
 use std::process::ExitStatus;
 
+use rustc_abi::TargetDataLayoutErrors;
 use rustc_ast_pretty::pprust;
 use rustc_macros::Subdiagnostic;
 use rustc_span::Span;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
-use rustc_target::abi::TargetDataLayoutErrors;
 use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
 use rustc_type_ir::{ClosureKind, FloatTy};
 use {rustc_ast as ast, rustc_hir as hir};
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 0ccc71ae06c..6552cf224ea 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1555,7 +1555,7 @@ impl HumanEmitter {
                 // Get the left-side margin to remove it
                 let mut whitespace_margin = usize::MAX;
                 for line_idx in 0..annotated_file.lines.len() {
-                    let file = annotated_file.file.clone();
+                    let file = Lrc::clone(&annotated_file.file);
                     let line = &annotated_file.lines[line_idx];
                     if let Some(source_string) =
                         line.line_index.checked_sub(1).and_then(|l| file.get_line(l))
@@ -1646,7 +1646,7 @@ impl HumanEmitter {
 
                     let depths = self.render_source_line(
                         &mut buffer,
-                        annotated_file.file.clone(),
+                        Lrc::clone(&annotated_file.file),
                         &annotated_file.lines[line_idx],
                         width_offset,
                         code_offset,
@@ -2529,7 +2529,12 @@ impl FileWithAnnotatedLines {
                 //  | |      |
                 //  | |______foo
                 //  |        baz
-                add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start());
+                add_annotation_to_file(
+                    &mut output,
+                    Lrc::clone(&file),
+                    ann.line_start,
+                    ann.as_start(),
+                );
                 // 4 is the minimum vertical length of a multiline span when presented: two lines
                 // of code and two lines of underline. This is not true for the special case where
                 // the beginning doesn't have an underline, but the current logic seems to be
@@ -2545,11 +2550,11 @@ impl FileWithAnnotatedLines {
                     .unwrap_or(ann.line_start);
                 for line in ann.line_start + 1..until {
                     // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
-                    add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
+                    add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line());
                 }
                 let line_end = ann.line_end - 1;
                 if middle < line_end {
-                    add_annotation_to_file(&mut output, file.clone(), line_end, ann.as_line());
+                    add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line());
                 }
             } else {
                 end_ann.annotation_type = AnnotationType::Singleline;
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1534e256520..91e2b9996cd 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -367,9 +367,9 @@ impl Diagnostic {
             ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)),
             ColorConfig::Never => {}
         }
-        HumanEmitter::new(dst, je.fallback_bundle.clone())
+        HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle))
             .short_message(short)
-            .sm(Some(je.sm.clone()))
+            .sm(Some(Lrc::clone(&je.sm)))
             .fluent_bundle(je.fluent_bundle.clone())
             .diagnostic_width(je.diagnostic_width)
             .macro_backtrace(je.macro_backtrace)
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index fcf3352bfc5..f26c7c1ba0b 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -74,7 +74,7 @@ expand_helper_attribute_name_invalid =
     `{$name}` cannot be a name of derive helper attribute
 
 expand_incomplete_parse =
-    macro expansion ignores token `{$token}` and any following
+    macro expansion ignores {$descr} and any tokens following
     .label = caused by the macro expansion here
     .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
     .suggestion_add_semi = you might be missing a semicolon here
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 5682c574552..7bd7c305539 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -275,7 +275,7 @@ pub(crate) struct UnsupportedKeyValue {
 pub(crate) struct IncompleteParse<'a> {
     #[primary_span]
     pub span: Span,
-    pub token: Cow<'a, str>,
+    pub descr: String,
     #[label]
     pub label_span: Span,
     pub macro_path: &'a ast::Path,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5ffafcaa542..04ac7891023 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -21,6 +21,7 @@ use rustc_errors::PResult;
 use rustc_feature::Features;
 use rustc_parse::parser::{
     AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma,
+    token_descr,
 };
 use rustc_parse::validate_attr;
 use rustc_session::lint::BuiltinLintDiag;
@@ -1013,7 +1014,7 @@ pub(crate) fn ensure_complete_parse<'a>(
     span: Span,
 ) {
     if parser.token != token::Eof {
-        let token = pprust::token_to_string(&parser.token);
+        let descr = token_descr(&parser.token);
         // Avoid emitting backtrace info twice.
         let def_site_span = parser.token.span.with_ctxt(SyntaxContext::root());
 
@@ -1029,7 +1030,7 @@ pub(crate) fn ensure_complete_parse<'a>(
 
         parser.dcx().emit_err(IncompleteParse {
             span: def_site_span,
-            token,
+            descr,
             label_span: span,
             macro_path,
             kind_name,
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 103bbb05e7f..ffcce1e52f6 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -2,10 +2,9 @@ use std::borrow::Cow;
 
 use rustc_ast::token::{self, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
 use rustc_macros::Subdiagnostic;
-use rustc_parse::parser::{Parser, Recovery};
+use rustc_parse::parser::{Parser, Recovery, token_descr};
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Ident;
@@ -336,17 +335,11 @@ pub(super) fn annotate_doc_comment(err: &mut Diag<'_>, sm: &SourceMap, span: Spa
 /// other tokens, this is "unexpected token...".
 pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
     if let Some(expected_token) = expected_token {
-        Cow::from(format!(
-            "expected `{}`, found `{}`",
-            pprust::token_to_string(expected_token),
-            pprust::token_to_string(tok),
-        ))
+        Cow::from(format!("expected {}, found {}", token_descr(expected_token), token_descr(tok)))
     } else {
         match tok.kind {
             token::Eof => Cow::from("unexpected end of macro invocation"),
-            _ => {
-                Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok)))
-            }
+            _ => Cow::from(format!("no rules expected {}", token_descr(tok))),
         }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 3903203da3d..2a8dddc1e00 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -78,11 +78,10 @@ use std::rc::Rc;
 pub(crate) use NamedMatch::*;
 pub(crate) use ParseResult::*;
 use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
-use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
-use rustc_parse::parser::{ParseNtResult, Parser};
+use rustc_parse::parser::{ParseNtResult, Parser, token_descr};
 use rustc_span::Span;
 use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent};
 
@@ -150,7 +149,7 @@ impl Display for MatcherLoc {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => {
-                write!(f, "`{}`", pprust::token_to_string(token))
+                write!(f, "{}", token_descr(token))
             }
             MatcherLoc::MetaVarDecl { bind, kind, .. } => {
                 write!(f, "meta-variable `${bind}")?;
@@ -622,7 +621,7 @@ impl TtParser {
         // possible next positions into `next_mps`. After some post-processing, the contents of
         // `next_mps` replenish `cur_mps` and we start over again.
         self.cur_mps.clear();
-        self.cur_mps.push(MatcherPos { idx: 0, matches: self.empty_matches.clone() });
+        self.cur_mps.push(MatcherPos { idx: 0, matches: Rc::clone(&self.empty_matches) });
 
         loop {
             self.next_mps.clear();
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f40f99b6ea1..fcc90c3ce0d 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -3,12 +3,11 @@ use std::collections::hash_map::Entry;
 use std::{mem, slice};
 
 use ast::token::IdentIsRaw;
-use rustc_ast as ast;
 use rustc_ast::token::NtPatKind::*;
 use rustc_ast::token::TokenKind::*;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::{DUMMY_NODE_ID, NodeId};
+use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
@@ -370,34 +369,32 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
 pub fn compile_declarative_macro(
     sess: &Session,
     features: &Features,
-    def: &ast::Item,
+    macro_def: &ast::MacroDef,
+    ident: Ident,
+    attrs: &[ast::Attribute],
+    span: Span,
+    node_id: NodeId,
     edition: Edition,
 ) -> (SyntaxExtension, Vec<(usize, Span)>) {
-    debug!("compile_declarative_macro: {:?}", def);
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
             sess,
             features,
             SyntaxExtensionKind::LegacyBang(expander),
-            def.span,
+            span,
             Vec::new(),
             edition,
-            def.ident.name,
-            &def.attrs,
-            def.id != DUMMY_NODE_ID,
+            ident.name,
+            attrs,
+            node_id != DUMMY_NODE_ID,
         )
     };
     let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new());
 
     let dcx = sess.dcx();
-    let lhs_nm = Ident::new(sym::lhs, def.span);
-    let rhs_nm = Ident::new(sym::rhs, def.span);
+    let lhs_nm = Ident::new(sym::lhs, span);
+    let rhs_nm = Ident::new(sym::rhs, span);
     let tt_spec = Some(NonterminalKind::TT);
-
-    let macro_def = match &def.kind {
-        ast::ItemKind::MacroDef(def) => def,
-        _ => unreachable!(),
-    };
     let macro_rules = macro_def.macro_rules;
 
     // Parse the macro_rules! invocation
@@ -410,25 +407,22 @@ pub fn compile_declarative_macro(
     let argument_gram = vec![
         mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
             tts: vec![
-                mbe::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
-                mbe::TokenTree::token(token::FatArrow, def.span),
-                mbe::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
+                mbe::TokenTree::MetaVarDecl(span, lhs_nm, tt_spec),
+                mbe::TokenTree::token(token::FatArrow, span),
+                mbe::TokenTree::MetaVarDecl(span, rhs_nm, tt_spec),
             ],
-            separator: Some(Token::new(
-                if macro_rules { token::Semi } else { token::Comma },
-                def.span,
-            )),
-            kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, def.span),
+            separator: Some(Token::new(if macro_rules { token::Semi } else { token::Comma }, span)),
+            kleene: mbe::KleeneToken::new(mbe::KleeneOp::OneOrMore, span),
             num_captures: 2,
         }),
         // to phase into semicolon-termination instead of semicolon-separation
         mbe::TokenTree::Sequence(DelimSpan::dummy(), mbe::SequenceRepetition {
             tts: vec![mbe::TokenTree::token(
                 if macro_rules { token::Semi } else { token::Comma },
-                def.span,
+                span,
             )],
             separator: None,
-            kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, def.span),
+            kleene: mbe::KleeneToken::new(mbe::KleeneOp::ZeroOrMore, span),
             num_captures: 0,
         }),
     ];
@@ -460,7 +454,7 @@ pub fn compile_declarative_macro(
                 };
 
                 let s = parse_failure_msg(&token, track.get_expected_token());
-                let sp = token.span.substitute_dummy(def.span);
+                let sp = token.span.substitute_dummy(span);
                 let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
                 annotate_doc_comment(&mut err, sess.source_map(), sp);
@@ -468,7 +462,7 @@ pub fn compile_declarative_macro(
                 return dummy_syn_ext(guar);
             }
             Error(sp, msg) => {
-                let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg);
+                let guar = sess.dcx().span_err(sp.substitute_dummy(span), msg);
                 return dummy_syn_ext(guar);
             }
             ErrorReported(guar) => {
@@ -489,7 +483,7 @@ pub fn compile_declarative_macro(
                         &TokenStream::new(vec![tt.clone()]),
                         true,
                         sess,
-                        def.id,
+                        node_id,
                         features,
                         edition,
                     )
@@ -497,13 +491,13 @@ pub fn compile_declarative_macro(
                     .unwrap();
                     // We don't handle errors here, the driver will abort
                     // after parsing/expansion. We can report every error in every macro this way.
-                    check_emission(check_lhs_nt_follows(sess, def, &tt));
+                    check_emission(check_lhs_nt_follows(sess, node_id, &tt));
                     return tt;
                 }
-                sess.dcx().span_bug(def.span, "wrong-structured lhs")
+                sess.dcx().span_bug(span, "wrong-structured lhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"),
+        _ => sess.dcx().span_bug(span, "wrong-structured lhs"),
     };
 
     let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -515,17 +509,17 @@ pub fn compile_declarative_macro(
                         &TokenStream::new(vec![tt.clone()]),
                         false,
                         sess,
-                        def.id,
+                        node_id,
                         features,
                         edition,
                     )
                     .pop()
                     .unwrap();
                 }
-                sess.dcx().span_bug(def.span, "wrong-structured rhs")
+                sess.dcx().span_bug(span, "wrong-structured rhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"),
+        _ => sess.dcx().span_bug(span, "wrong-structured rhs"),
     };
 
     for rhs in &rhses {
@@ -537,15 +531,9 @@ pub fn compile_declarative_macro(
         check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs)));
     }
 
-    check_emission(macro_check::check_meta_variables(
-        &sess.psess,
-        def.id,
-        def.span,
-        &lhses,
-        &rhses,
-    ));
+    check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses));
 
-    let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
+    let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules);
     match transparency_error {
         Some(TransparencyError::UnknownTransparency(value, span)) => {
             dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
@@ -564,7 +552,7 @@ pub fn compile_declarative_macro(
 
     // Compute the spans of the macro rules for unused rule linting.
     // Also, we are only interested in non-foreign macros.
-    let rule_spans = if def.id != DUMMY_NODE_ID {
+    let rule_spans = if node_id != DUMMY_NODE_ID {
         lhses
             .iter()
             .zip(rhses.iter())
@@ -590,15 +578,15 @@ pub fn compile_declarative_macro(
                 mbe::TokenTree::Delimited(.., delimited) => {
                     mbe::macro_parser::compute_locs(&delimited.tts)
                 }
-                _ => sess.dcx().span_bug(def.span, "malformed macro lhs"),
+                _ => sess.dcx().span_bug(span, "malformed macro lhs"),
             }
         })
         .collect();
 
     let expander = Box::new(MacroRulesMacroExpander {
-        name: def.ident,
-        span: def.span,
-        node_id: def.id,
+        name: ident,
+        span,
+        node_id,
         transparency,
         lhses,
         rhses,
@@ -608,13 +596,13 @@ pub fn compile_declarative_macro(
 
 fn check_lhs_nt_follows(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     lhs: &mbe::TokenTree,
 ) -> Result<(), ErrorGuaranteed> {
     // lhs is going to be like TokenTree::Delimited(...), where the
     // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
     if let mbe::TokenTree::Delimited(.., delimited) = lhs {
-        check_matcher(sess, def, &delimited.tts)
+        check_matcher(sess, node_id, &delimited.tts)
     } else {
         let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
         Err(sess.dcx().span_err(lhs.span(), msg))
@@ -686,12 +674,12 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed
 
 fn check_matcher(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     matcher: &[mbe::TokenTree],
 ) -> Result<(), ErrorGuaranteed> {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
-    check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix)?;
+    check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?;
     Ok(())
 }
 
@@ -1028,7 +1016,7 @@ impl<'tt> TokenSet<'tt> {
 // see `FirstSets::new`.
 fn check_matcher_core<'tt>(
     sess: &Session,
-    def: &ast::Item,
+    node_id: NodeId,
     first_sets: &FirstSets<'tt>,
     matcher: &'tt [mbe::TokenTree],
     follow: &TokenSet<'tt>,
@@ -1082,7 +1070,7 @@ fn check_matcher_core<'tt>(
                     token::CloseDelim(d.delim),
                     span.close,
                 ));
-                check_matcher_core(sess, def, first_sets, &d.tts, &my_suffix)?;
+                check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
                 // don't track non NT tokens
                 last.replace_with_irrelevant();
 
@@ -1114,7 +1102,7 @@ fn check_matcher_core<'tt>(
                 // At this point, `suffix_first` is built, and
                 // `my_suffix` is some TokenSet that we can use
                 // for checking the interior of `seq_rep`.
-                let next = check_matcher_core(sess, def, first_sets, &seq_rep.tts, my_suffix)?;
+                let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?;
                 if next.maybe_empty {
                     last.add_all(&next);
                 } else {
@@ -1144,7 +1132,7 @@ fn check_matcher_core<'tt>(
                     // macro. (See #86567.)
                     // Macros defined in the current crate have a real node id,
                     // whereas macros from an external crate have a dummy id.
-                    if def.id != DUMMY_NODE_ID
+                    if node_id != DUMMY_NODE_ID
                         && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
                         && matches!(
                             next_token,
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 34811ca2b35..b77d02e630a 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -5,6 +5,7 @@ use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::token::{self, Delimiter, IdentIsRaw, Lit, LitKind, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
 use rustc_parse::lexer::nfc_normalize;
 use rustc_parse::parser::ParseNtResult;
@@ -293,7 +294,7 @@ pub(super) fn transcribe<'a>(
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
-                            TokenTree::token_alone(token::Interpolated(nt.clone()), sp)
+                            TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp)
                         }
                         MatchedSeq(..) => {
                             // We were unable to descend far enough. This is an error.
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index ac922f184dd..e910415c345 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -224,6 +224,8 @@ declare_features! (
     (accepted, i128_type, "1.26.0", Some(35118)),
     /// Allows the use of `if let` expressions.
     (accepted, if_let, "1.0.0", None),
+    /// Rescoping temporaries in `if let` to align with Rust 2024.
+    (accepted, if_let_rescope, "CURRENT_RUSTC_VERSION", Some(124085)),
     /// Allows top level or-patterns (`p | q`) in `if let` and `while let`.
     (accepted, if_while_or_patterns, "1.33.0", Some(48215)),
     /// Allows lifetime elision in `impl` headers. For example:
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index fe3a67fd667..8d2e1e8c804 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -85,6 +85,8 @@ declare_features! (
     /// Allows default type parameters to influence type inference.
     (removed, default_type_parameter_fallback, "1.82.0", Some(27336),
      Some("never properly implemented; requires significant design work")),
+    /// Allows deriving traits as per `SmartPointer` specification
+    (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")),
     /// Allows using `#[doc(keyword = "...")]`.
     (removed, doc_keyword, "1.28.0", Some(51315),
      Some("merged into `#![feature(rustdoc_internals)]`")),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index a81058e6ea1..a99d9048886 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -450,8 +450,6 @@ declare_features! (
     (unstable, deprecated_suggestion, "1.61.0", Some(94785)),
     /// Allows deref patterns.
     (incomplete, deref_patterns, "1.79.0", Some(87121)),
-    /// Allows deriving `SmartPointer` traits
-    (unstable, derive_smart_pointer, "1.79.0", Some(123430)),
     /// Controls errors in trait implementations.
     (unstable, do_not_recommend, "1.67.0", Some(51992)),
     /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
@@ -507,8 +505,6 @@ declare_features! (
     (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
     /// Allows `if let` guard in match arms.
     (unstable, if_let_guard, "1.47.0", Some(51114)),
-    /// Rescoping temporaries in `if let` to align with Rust 2024.
-    (unstable, if_let_rescope, "1.83.0", Some(124085)),
     /// Allows `impl Trait` to be used inside associated types (RFC 2515).
     (unstable, impl_trait_in_assoc_type, "1.70.0", Some(63063)),
     /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1c268c8bbe0..12b01266a93 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2627,7 +2627,6 @@ impl<'hir> Ty<'hir> {
             }
             TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
             TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
-            TyKind::OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
             TyKind::Path(QPath::TypeRelative(ty, segment)) => {
                 ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
             }
@@ -2746,19 +2745,8 @@ pub struct BareFnTy<'hir> {
 pub struct OpaqueTy<'hir> {
     pub hir_id: HirId,
     pub def_id: LocalDefId,
-    pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
-    /// Return-position impl traits (and async futures) must "reify" any late-bound
-    /// lifetimes that are captured from the function signature they originate from.
-    ///
-    /// This is done by generating a new early-bound lifetime parameter local to the
-    /// opaque which is instantiated in the function signature with the late-bound
-    /// lifetime.
-    ///
-    /// This mapping associated a captured lifetime (first parameter) with the new
-    /// early-bound lifetime that was generated for the opaque.
-    pub lifetime_mapping: &'hir [(&'hir Lifetime, LocalDefId)],
     pub span: Span,
 }
 
@@ -2861,12 +2849,7 @@ pub enum TyKind<'hir> {
     /// Type parameters may be stored in each `PathSegment`.
     Path(QPath<'hir>),
     /// An opaque type definition itself. This is only used for `impl Trait`.
-    ///
-    /// The generic argument list contains the lifetimes (and in the future
-    /// possibly parameters) that are actually bound on the `impl Trait`.
-    ///
-    /// The last parameter specifies whether this opaque appears in a trait definition.
-    OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]),
+    OpaqueDef(&'hir OpaqueTy<'hir>),
     /// A trait object type `Bound1 + Bound2 + Bound3`
     /// where `Bound` is a trait or a lifetime.
     TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
@@ -3991,7 +3974,6 @@ impl<'hir> Node<'hir> {
             | Node::TraitItem(TraitItem { generics, .. })
             | Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
             Node::Item(item) => item.kind.generics(),
-            Node::OpaqueTy(opaque) => Some(opaque.generics),
             _ => None,
         }
     }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 322f8e2a517..a453af3f7fd 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -896,9 +896,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
         TyKind::Path(ref qpath) => {
             try_visit!(visitor.visit_qpath(qpath, typ.hir_id, typ.span));
         }
-        TyKind::OpaqueDef(opaque, lifetimes) => {
+        TyKind::OpaqueDef(opaque) => {
             try_visit!(visitor.visit_opaque_ty(opaque));
-            walk_list!(visitor, visit_generic_arg, lifetimes);
         }
         TyKind::Array(ref ty, ref length) => {
             try_visit!(visitor.visit_ty(ty));
@@ -1188,10 +1187,8 @@ pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(
 }
 
 pub fn walk_opaque_ty<'v, V: Visitor<'v>>(visitor: &mut V, opaque: &'v OpaqueTy<'v>) -> V::Result {
-    let &OpaqueTy { hir_id, def_id: _, generics, bounds, origin: _, lifetime_mapping: _, span: _ } =
-        opaque;
+    let &OpaqueTy { hir_id, def_id: _, bounds, origin: _, span: _ } = opaque;
     try_visit!(visitor.visit_id(hir_id));
-    try_visit!(walk_generics(visitor, generics));
     walk_list!(visitor, visit_param_bound, bounds);
     V::Result::output()
 }
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index 04ca7f123d3..3c8887f08bc 100644
--- a/compiler/rustc_hir_analysis/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -10,6 +10,7 @@ doctest = false
 [dependencies]
 # tidy-alphabetical-start
 itertools = "0.12"
+rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 507297ce162..38b11aa4017 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -149,10 +149,6 @@ hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
 hir_analysis_duplicate_precise_capture = cannot capture parameter `{$name}` twice
     .label = parameter captured again here
 
-hir_analysis_effects_without_next_solver = using `#![feature(effects)]` without enabling next trait solver globally
-    .note = the next trait solver must be enabled globally for the effects feature to work correctly
-    .help = use `-Znext-solver` to enable
-
 hir_analysis_empty_specialization = specialization impl does not specialize any associated items
     .note = impl is a specialization of this impl
 
@@ -238,6 +234,12 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a
     .help = consider moving this inherent impl into the crate defining the type if possible
     .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items
 
+hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}`
+    .note = type of `self` must not be a method generic parameter type
+
+hir_analysis_invalid_generic_receiver_ty_help =
+    use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
 hir_analysis_invalid_receiver_ty = invalid `self` parameter type: `{$receiver_ty}`
     .note = type of `self` must be `Self` or a type that dereferences to it
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 97f3f1c8ef2..f830108a02f 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -1,6 +1,7 @@
 use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
+use rustc_abi::FieldIdx;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
@@ -23,13 +24,13 @@ use rustc_middle::ty::{
     TypeVisitableExt,
 };
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
-use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_type_ir::fold::TypeFoldable;
 use tracing::{debug, instrument};
+use ty::TypingMode;
 use {rustc_attr as attr, rustc_hir as hir};
 
 use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty};
@@ -172,7 +173,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             return;
         }
     };
-    if layout.abi.is_uninhabited() {
+    if layout.is_uninhabited() {
         tcx.node_span_lint(
             UNINHABITED_STATIC,
             tcx.local_def_id_to_hir_id(def_id),
@@ -276,7 +277,8 @@ fn check_opaque_meets_bounds<'tcx>(
     };
     let param_env = tcx.param_env(defining_use_anchor);
 
-    let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build();
+    // FIXME(#132279): This should eventually use the already defined hidden types.
+    let infcx = tcx.infer_ctxt().build(TypingMode::analysis_in_body(tcx, defining_use_anchor));
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let args = match *origin {
@@ -1675,8 +1677,8 @@ pub(super) fn check_coroutine_obligations(
         // typeck writeback gives us predicates with their regions erased.
         // As borrowck already has checked lifetimes, we do not need to do it again.
         .ignoring_regions()
-        .with_opaque_type_inference(def_id)
-        .build();
+        // FIXME(#132279): This should eventually use the already defined hidden types.
+        .build(TypingMode::analysis_in_body(tcx, def_id));
 
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     for (predicate, cause) in &typeck_results.coroutine_stalled_predicates {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 02cf1a502f1..db2c44fd29d 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
 use rustc_middle::ty::{
     self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder,
-    TypeSuperFoldable, TypeVisitableExt, Upcast,
+    TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
@@ -228,7 +228,7 @@ fn compare_method_predicate_entailment<'tcx>(
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     debug!(caller_bounds=?param_env.caller_bounds());
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     // Create obligations for each predicate declared by the impl
@@ -516,7 +516,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         ObligationCause::misc(tcx.def_span(impl_m_def_id), impl_m_def_id),
     );
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     // Normalize the impl signature with fresh variables for lifetime inference.
@@ -611,7 +611,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         Err(terr) => {
             let mut diag = struct_span_code_err!(
                 tcx.dcx(),
-                cause.span(),
+                cause.span,
                 E0053,
                 "method `{}` has an incompatible return type for trait",
                 trait_m.name
@@ -1169,7 +1169,7 @@ fn extract_spans_for_error_reporting<'tcx>(
         TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => {
             (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i)))
         }
-        _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)),
+        _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)),
     }
 }
 
@@ -1196,7 +1196,7 @@ fn compare_self_type<'tcx>(
         let self_arg_ty = tcx.fn_sig(method.def_id).instantiate_identity().input(0);
         let param_env = ty::ParamEnv::reveal_all();
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let self_arg_ty = tcx.liberate_late_bound_regions(method.def_id, self_arg_ty);
         let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty);
         match ExplicitSelf::determine(self_arg_ty, can_eq_self) {
@@ -1801,7 +1801,7 @@ fn compare_const_predicate_entailment<'tcx>(
         ObligationCause::misc(impl_ct_span, impl_ct_def_id),
     );
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_ct_own_bounds = impl_ct_predicates.instantiate_own_identity();
@@ -1951,7 +1951,7 @@ fn compare_type_predicate_entailment<'tcx>(
     let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
     debug!(caller_bounds=?param_env.caller_bounds());
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     for (predicate, span) in impl_ty_own_bounds {
@@ -2036,7 +2036,7 @@ pub(super) fn check_type_bounds<'tcx>(
     let impl_ty_args = GenericArgs::identity_for_item(tcx, impl_ty.def_id);
     let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     // A synthetic impl Trait for RPITIT desugaring or assoc type for effects desugaring has no HIR,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 2d6b9813271..646c104f1f5 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -8,7 +8,7 @@ use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor,
+    TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_span::Span;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -132,7 +132,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     let param_env = ty::ParamEnv::new(tcx.mk_clauses_from_iter(hybrid_preds), Reveal::UserFacing);
     let param_env = normalize_param_env_or_error(tcx, param_env, ObligationCause::dummy());
 
-    let ref infcx = tcx.infer_ctxt().build();
+    let ref infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new(infcx);
 
     // Normalize the bounds. This has two purposes:
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 97a29b32c01..1c9bbe627fb 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::util::CheckRegions;
-use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 
@@ -124,7 +124,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     adt_def_id: LocalDefId,
     adt_to_impl_args: GenericArgsRef<'tcx>,
 ) -> Result<(), ErrorGuaranteed> {
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
     let impl_span = tcx.def_span(drop_impl_def_id.to_def_id());
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 7da2cd93d4e..0beb1f98d56 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -4,7 +4,7 @@ use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_session::config::EntryFnType;
 use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -128,7 +128,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
             tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
             return;
         };
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let cause = traits::ObligationCause::new(
             return_ty_span,
             main_diagnostics_def_id,
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index bbff00cd3b3..e95669c9d40 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,5 +1,6 @@
 use std::assert_matches::debug_assert_matches;
 
+use rustc_abi::FieldIdx;
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::{self as hir, LangItem};
@@ -8,7 +9,6 @@ use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintT
 use rustc_session::lint;
 use rustc_span::Symbol;
 use rustc_span::def_id::LocalDefId;
-use rustc_target::abi::FieldIdx;
 use rustc_target::asm::{
     InlineAsmReg, InlineAsmRegClass, InlineAsmRegOrRegClass, InlineAsmType, ModifierInfo,
 };
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index f2f9c69e49f..e9eea36a0e6 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,6 +74,7 @@ pub mod wfcheck;
 use std::num::NonZero;
 
 pub use check::{check_abi, check_abi_fn_ptr};
+use rustc_abi::VariantIdx;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -84,13 +85,12 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _};
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::symbol::{Ident, kw, sym};
 use rustc_span::{BytePos, DUMMY_SP, Span, Symbol};
-use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _;
@@ -530,7 +530,7 @@ fn suggestion_signature<'tcx>(
             let ty = tcx.type_of(assoc.def_id).instantiate_identity();
             let val = tcx
                 .infer_ctxt()
-                .build()
+                .build(TypingMode::non_body_analysis())
                 .err_ctxt()
                 .ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
                 .unwrap_or_else(|| "value".to_string());
@@ -612,7 +612,7 @@ pub fn check_function_signature<'tcx>(
         match err {
             TypeError::ArgumentMutability(i)
             | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
-            _ => cause.span(),
+            _ => cause.span,
         }
     }
 
@@ -620,7 +620,7 @@ pub fn check_function_signature<'tcx>(
 
     let param_env = ty::ParamEnv::empty();
 
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index bfa088fdefc..679f6ccb816 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -464,8 +464,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
 
         hir::ExprKind::If(cond, then, Some(otherwise)) => {
             let expr_cx = visitor.cx;
-            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
-            {
+            let data = if expr.span.at_least_rust_2024() {
                 ScopeData::IfThenRescope
             } else {
                 ScopeData::IfThen
@@ -480,8 +479,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
 
         hir::ExprKind::If(cond, then, None) => {
             let expr_cx = visitor.cx;
-            let data = if expr.span.at_least_rust_2024() && visitor.tcx.features().if_let_rescope()
-            {
+            let data = if expr.span.at_least_rust_2024() {
                 ScopeData::IfThenRescope
             } else {
                 ScopeData::IfThen
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 499e42d31c9..b20fa49eadb 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
     self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
-    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
+    TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
@@ -106,7 +106,7 @@ where
     F: for<'a> FnOnce(&WfCheckingCtxt<'a, 'tcx>) -> Result<(), ErrorGuaranteed>,
 {
     let param_env = tcx.param_env(body_def_id);
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
 
     let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env };
@@ -765,7 +765,7 @@ fn test_region_obligations<'tcx>(
     // Unfortunately, we have to use a new `InferCtxt` each call, because
     // region constraints get added and solved there and we need to test each
     // call individually.
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
 
     add_constraints(&infcx);
 
@@ -904,7 +904,6 @@ fn check_impl_item<'tcx>(
         hir::ImplItemKind::Type(ty) if ty.span != DUMMY_SP => (None, ty.span),
         _ => (None, impl_item.span),
     };
-
     check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig)
 }
 
@@ -1725,8 +1724,11 @@ fn check_method_receiver<'tcx>(
     } else {
         None
     };
+    let generics = tcx.generics_of(method.def_id);
 
-    if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level) {
+    let receiver_validity =
+        receiver_is_valid(wfcx, span, receiver_ty, self_ty, arbitrary_self_types_level, generics);
+    if let Err(receiver_validity_err) = receiver_validity {
         return Err(match arbitrary_self_types_level {
             // Wherever possible, emit a message advising folks that the features
             // `arbitrary_self_types` or `arbitrary_self_types_pointers` might
@@ -1737,7 +1739,9 @@ fn check_method_receiver<'tcx>(
                 receiver_ty,
                 self_ty,
                 Some(ArbitrarySelfTypesLevel::Basic),
-            ) =>
+                generics,
+            )
+            .is_ok() =>
             {
                 // Report error; would have worked with `arbitrary_self_types`.
                 feature_err(
@@ -1759,7 +1763,9 @@ fn check_method_receiver<'tcx>(
                     receiver_ty,
                     self_ty,
                     Some(ArbitrarySelfTypesLevel::WithPointers),
-                ) =>
+                    generics,
+                )
+                .is_ok() =>
             {
                 // Report error; would have worked with `arbitrary_self_types_pointers`.
                 feature_err(
@@ -1777,13 +1783,45 @@ fn check_method_receiver<'tcx>(
             _ =>
             // Report error; would not have worked with `arbitrary_self_types[_pointers]`.
             {
-                tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
+                match receiver_validity_err {
+                    ReceiverValidityError::DoesNotDeref => {
+                        tcx.dcx().emit_err(errors::InvalidReceiverTy { span, receiver_ty })
+                    }
+                    ReceiverValidityError::MethodGenericParamUsed => {
+                        tcx.dcx().emit_err(errors::InvalidGenericReceiverTy { span, receiver_ty })
+                    }
+                }
             }
         });
     }
     Ok(())
 }
 
+/// Error cases which may be returned from `receiver_is_valid`. These error
+/// cases are generated in this function as they may be unearthed as we explore
+/// the `autoderef` chain, but they're converted to diagnostics in the caller.
+enum ReceiverValidityError {
+    /// The self type does not get to the receiver type by following the
+    /// autoderef chain.
+    DoesNotDeref,
+    /// A type was found which is a method type parameter, and that's not allowed.
+    MethodGenericParamUsed,
+}
+
+/// Confirms that a type is not a type parameter referring to one of the
+/// method's type params.
+fn confirm_type_is_not_a_method_generic_param(
+    ty: Ty<'_>,
+    method_generics: &ty::Generics,
+) -> Result<(), ReceiverValidityError> {
+    if let ty::Param(param) = ty.kind() {
+        if (param.index as usize) >= method_generics.parent_count {
+            return Err(ReceiverValidityError::MethodGenericParamUsed);
+        }
+    }
+    Ok(())
+}
+
 /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
 /// `arbitrary_self_types` is enabled, `receiver_ty` must transitively deref to `self_ty`, possibly
 /// through a `*const/mut T` raw pointer if  `arbitrary_self_types_pointers` is also enabled.
@@ -1799,7 +1837,8 @@ fn receiver_is_valid<'tcx>(
     receiver_ty: Ty<'tcx>,
     self_ty: Ty<'tcx>,
     arbitrary_self_types_enabled: Option<ArbitrarySelfTypesLevel>,
-) -> bool {
+    method_generics: &ty::Generics,
+) -> Result<(), ReceiverValidityError> {
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
     let cause =
@@ -1811,9 +1850,11 @@ fn receiver_is_valid<'tcx>(
         ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?;
         if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
     }) {
-        return true;
+        return Ok(());
     }
 
+    confirm_type_is_not_a_method_generic_param(receiver_ty, method_generics)?;
+
     let mut autoderef = Autoderef::new(infcx, wfcx.param_env, wfcx.body_def_id, span, receiver_ty);
 
     // The `arbitrary_self_types_pointers` feature allows raw pointer receivers like `self: *const Self`.
@@ -1830,6 +1871,8 @@ fn receiver_is_valid<'tcx>(
             potential_self_ty, self_ty
         );
 
+        confirm_type_is_not_a_method_generic_param(potential_self_ty, method_generics)?;
+
         // Check if the self type unifies. If it does, then commit the result
         // since it may have region side-effects.
         if let Ok(()) = wfcx.infcx.commit_if_ok(|_| {
@@ -1838,7 +1881,7 @@ fn receiver_is_valid<'tcx>(
             if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) }
         }) {
             wfcx.register_obligations(autoderef.into_obligations());
-            return true;
+            return Ok(());
         }
 
         // Without `feature(arbitrary_self_types)`, we require that each step in the
@@ -1865,7 +1908,7 @@ fn receiver_is_valid<'tcx>(
     }
 
     debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty);
-    false
+    Err(ReceiverValidityError::DoesNotDeref)
 }
 
 fn receiver_is_implemented<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b4f6b5a9dd2..5ff52376837 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -15,7 +15,9 @@ use rustc_infer::infer::{self, RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_params};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
+};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::misc::{
@@ -213,7 +215,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
 
     let param_env = tcx.param_env(impl_did);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::misc(span, impl_did);
 
     // Later parts of the compiler rely on all DispatchFromDyn types to be ABI-compatible with raw
@@ -354,7 +356,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
 
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)", source, target);
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::misc(span, impl_did);
     let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
                        mt_b: ty::TypeAndMut<'tcx>,
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 04770469132..8a1a887766c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -7,7 +7,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
@@ -302,7 +302,7 @@ fn orphan_check<'tcx>(
     }
 
     // (1)  Instantiate all generic params with fresh inference vars.
-    let infcx = tcx.infer_ctxt().intercrate(true).build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::Coherence);
     let cause = traits::ObligationCause::dummy();
     let args = infcx.fresh_args_for_item(cause.span, impl_def_id.to_def_id());
     let trait_ref = trait_ref.instantiate(tcx, args);
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 3add801cf56..c41117d213f 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -34,7 +34,7 @@ use rustc_infer::traits::ObligationCause;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{Ident, Symbol, kw, sym};
 use rustc_span::{DUMMY_SP, Span};
@@ -1302,7 +1302,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     }
 }
 
-#[instrument(level = "debug", skip(tcx))]
+#[instrument(level = "debug", skip(tcx), ret)]
 fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
     use rustc_hir::*;
@@ -1438,9 +1438,11 @@ fn infer_return_ty_for_fn_sig<'tcx>(
                     Applicability::MachineApplicable,
                 );
                 recovered_ret_ty = Some(suggestable_ret_ty);
-            } else if let Some(sugg) =
-                suggest_impl_trait(&tcx.infer_ctxt().build(), tcx.param_env(def_id), ret_ty)
-            {
+            } else if let Some(sugg) = suggest_impl_trait(
+                &tcx.infer_ctxt().build(TypingMode::non_body_analysis()),
+                tcx.param_env(def_id),
+                ret_ty,
+            ) {
                 diag.span_suggestion(
                     ty.span,
                     "replace with an appropriate return type",
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 3eec0e12665..c31bff28fd3 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -426,6 +426,21 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
         });
     }
 
+    if let Node::OpaqueTy(&hir::OpaqueTy { .. }) = node {
+        assert!(own_params.is_empty());
+
+        let lifetimes = tcx.opaque_captured_lifetimes(def_id);
+        debug!(?lifetimes);
+
+        own_params.extend(lifetimes.iter().map(|&(_, param)| ty::GenericParamDef {
+            name: tcx.item_name(param.to_def_id()),
+            index: next_index(),
+            def_id: param.to_def_id(),
+            pure_wrt_drop: false,
+            kind: ty::GenericParamDefKind::Lifetime,
+        }))
+    }
+
     let param_def_id_to_index =
         own_params.iter().map(|param| (param.def_id, param.index)).collect();
 
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index b2ad42be6c7..5c4cecc02f0 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -367,20 +367,8 @@ pub(super) fn explicit_item_bounds_with_filter(
         // a projection self type.
         Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
             let opaque_ty = tcx.hir_node_by_def_id(opaque_def_id.expect_local()).expect_opaque_ty();
-            let item_ty = Ty::new_projection_from_args(
-                tcx,
-                def_id.to_def_id(),
-                ty::GenericArgs::identity_for_item(tcx, def_id),
-            );
-            let bounds = opaque_type_bounds(
-                tcx,
-                opaque_def_id.expect_local(),
-                opaque_ty.bounds,
-                item_ty,
-                opaque_ty.span,
-                filter,
-            );
-            assert_only_contains_predicates_from(filter, bounds, item_ty);
+            let bounds =
+                associated_type_bounds(tcx, def_id, opaque_ty.bounds, opaque_ty.span, filter);
             return ty::EarlyBinder::bind(bounds);
         }
         Some(ty::ImplTraitInTraitData::Impl { .. }) => span_bug!(
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 644ff0c667c..0b018053855 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -329,13 +329,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // We create bi-directional Outlives predicates between the original
     // and the duplicated parameter, to ensure that they do not get out of sync.
     if let Node::OpaqueTy(..) = node {
-        let opaque_ty_node = tcx.parent_hir_node(hir_id);
-        let Node::Ty(&hir::Ty { kind: TyKind::OpaqueDef(_, lifetimes), .. }) = opaque_ty_node
-        else {
-            bug!("unexpected {opaque_ty_node:?}")
-        };
-        debug!(?lifetimes);
-
         compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates);
         debug!(?predicates);
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 95e07244a6b..9483439ae4e 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -6,12 +6,14 @@
 //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
 //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
 
-use core::ops::ControlFlow;
+use std::cell::RefCell;
 use std::fmt;
+use std::ops::ControlFlow;
 
 use rustc_ast::visit::walk_list;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{self, Visitor};
@@ -25,7 +27,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::{DefId, LocalDefId, LocalDefIdMap};
 use rustc_span::symbol::{Ident, sym};
 use tracing::{debug, debug_span, instrument};
 
@@ -33,18 +35,12 @@ use crate::errors;
 
 #[extension(trait RegionExt)]
 impl ResolvedArg {
-    fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
-        debug!("ResolvedArg::early: def_id={:?}", param.def_id);
-        (param.def_id, ResolvedArg::EarlyBound(param.def_id))
+    fn early(param: &GenericParam<'_>) -> ResolvedArg {
+        ResolvedArg::EarlyBound(param.def_id)
     }
 
-    fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) {
-        let depth = ty::INNERMOST;
-        debug!(
-            "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}",
-            idx, param, depth, param.def_id,
-        );
-        (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id))
+    fn late(idx: u32, param: &GenericParam<'_>) -> ResolvedArg {
+        ResolvedArg::LateBound(ty::INNERMOST, idx, param.def_id)
     }
 
     fn id(&self) -> Option<LocalDefId> {
@@ -86,6 +82,9 @@ struct NamedVarMap {
     // - trait refs
     // - bound types (like `T` in `for<'a> T<'a>: Foo`)
     late_bound_vars: ItemLocalMap<Vec<ty::BoundVariableKind>>,
+
+    // List captured variables for each opaque type.
+    opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
 }
 
 struct BoundVarContext<'a, 'tcx> {
@@ -153,6 +152,23 @@ enum Scope<'a> {
         s: ScopeRef<'a>,
     },
 
+    /// Remap lifetimes that appear in opaque types to fresh lifetime parameters. Given:
+    /// `fn foo<'a>() -> impl MyTrait<'a> { ... }`
+    ///
+    /// HIR tells us that `'a` refer to the lifetime bound on `foo`.
+    /// However, typeck and borrowck for opaques work based on using a new generic type.
+    /// `type MyAnonTy<'b> = impl MyTrait<'b>;`
+    ///
+    /// This scope collects the mapping `'a -> 'b`.
+    Opaque {
+        /// The opaque type we are traversing.
+        def_id: LocalDefId,
+        /// Mapping from each captured lifetime `'a` to the duplicate generic parameter `'b`.
+        captures: &'a RefCell<FxIndexMap<ResolvedArg, LocalDefId>>,
+
+        s: ScopeRef<'a>,
+    },
+
     /// Disallows capturing late-bound vars from parent scopes.
     ///
     /// This is necessary for something like `for<T> [(); { /* references T */ }]:`,
@@ -198,6 +214,12 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
                 .field("where_bound_origin", where_bound_origin)
                 .field("s", &"..")
                 .finish(),
+            Scope::Opaque { captures, def_id, s: _ } => f
+                .debug_struct("Opaque")
+                .field("def_id", def_id)
+                .field("captures", &captures.borrow())
+                .field("s", &"..")
+                .finish(),
             Scope::Body { id, s: _ } => {
                 f.debug_struct("Body").field("id", id).field("s", &"..").finish()
             }
@@ -232,6 +254,12 @@ pub(crate) fn provide(providers: &mut Providers) {
         is_late_bound_map,
         object_lifetime_default,
         late_bound_vars_map: |tcx, id| &tcx.resolve_bound_vars(id).late_bound_vars,
+        opaque_captured_lifetimes: |tcx, id| {
+            &tcx.resolve_bound_vars(tcx.local_def_id_to_hir_id(id).owner)
+                .opaque_captured_lifetimes
+                .get(&id)
+                .map_or(&[][..], |x| &x[..])
+        },
 
         ..*providers
     };
@@ -242,8 +270,11 @@ pub(crate) fn provide(providers: &mut Providers) {
 /// `named_variable_map`, `is_late_bound_map`, etc.
 #[instrument(level = "debug", skip(tcx))]
 fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
-    let mut named_variable_map =
-        NamedVarMap { defs: Default::default(), late_bound_vars: Default::default() };
+    let mut named_variable_map = NamedVarMap {
+        defs: Default::default(),
+        late_bound_vars: Default::default(),
+        opaque_captured_lifetimes: Default::default(),
+    };
     let mut visitor = BoundVarContext {
         tcx,
         map: &mut named_variable_map,
@@ -270,36 +301,68 @@ fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBou
 
     let defs = named_variable_map.defs.into_sorted_stable_ord();
     let late_bound_vars = named_variable_map.late_bound_vars.into_sorted_stable_ord();
+    let opaque_captured_lifetimes = named_variable_map.opaque_captured_lifetimes;
     let rl = ResolveBoundVars {
         defs: SortedMap::from_presorted_elements(defs),
         late_bound_vars: SortedMap::from_presorted_elements(late_bound_vars),
+        opaque_captured_lifetimes,
     };
 
     debug!(?rl.defs);
     debug!(?rl.late_bound_vars);
+    debug!(?rl.opaque_captured_lifetimes);
     rl
 }
 
 fn late_arg_as_bound_arg<'tcx>(
     tcx: TyCtxt<'tcx>,
-    arg: &ResolvedArg,
     param: &GenericParam<'tcx>,
 ) -> ty::BoundVariableKind {
-    match arg {
-        ResolvedArg::LateBound(_, _, def_id) => {
-            let def_id = def_id.to_def_id();
-            let name = tcx.item_name(def_id);
-            match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
-                }
-                GenericParamKind::Type { .. } => {
-                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
-                }
-                GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
-            }
+    let def_id = param.def_id.to_def_id();
+    let name = tcx.item_name(def_id);
+    match param.kind {
+        GenericParamKind::Lifetime { .. } => {
+            ty::BoundVariableKind::Region(ty::BrNamed(def_id, name))
+        }
+        GenericParamKind::Type { .. } => {
+            ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name))
+        }
+        GenericParamKind::Const { .. } => ty::BoundVariableKind::Const,
+    }
+}
+
+/// Turn a [`ty::GenericParamDef`] into a bound arg. Generally, this should only
+/// be used when turning early-bound vars into late-bound vars when lowering
+/// return type notation.
+fn generic_param_def_as_bound_arg(param: &ty::GenericParamDef) -> ty::BoundVariableKind {
+    match param.kind {
+        ty::GenericParamDefKind::Lifetime => {
+            ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(param.def_id, param.name))
+        }
+        ty::GenericParamDefKind::Type { .. } => {
+            ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
+        }
+        ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
+    }
+}
+
+/// Whether this opaque always captures lifetimes in scope.
+/// Right now, this is all RPITIT and TAITs, and when `lifetime_capture_rules_2024`
+/// is enabled. We don't check the span of the edition, since this is done
+/// on a per-opaque basis to account for nested opaques.
+fn opaque_captures_all_in_scope_lifetimes<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    opaque: &'tcx hir::OpaqueTy<'tcx>,
+) -> bool {
+    match opaque.origin {
+        // if the opaque has the `use<...>` syntax, the user is telling us that they only want
+        // to account for those lifetimes, so do not try to be clever.
+        _ if opaque.bounds.iter().any(|bound| matches!(bound, hir::GenericBound::Use(..))) => false,
+        hir::OpaqueTyOrigin::AsyncFn { .. } | hir::OpaqueTyOrigin::TyAlias { .. } => true,
+        _ if tcx.features().lifetime_capture_rules_2024() || opaque.span.at_least_rust_2024() => {
+            true
         }
-        _ => bug!("{:?} is not a late argument", arg),
+        hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl, .. } => in_trait_or_impl.is_some(),
     }
 }
 
@@ -314,7 +377,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     break (vec![], BinderScopeType::Normal);
                 }
 
-                Scope::ObjectLifetimeDefault { s, .. } | Scope::LateBoundary { s, .. } => {
+                Scope::Opaque { s, .. }
+                | Scope::ObjectLifetimeDefault { s, .. }
+                | Scope::LateBoundary { s, .. } => {
                     scope = s;
                 }
 
@@ -360,10 +425,9 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         let mut bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = FxIndexMap::default();
         let binders_iter =
             trait_ref.bound_generic_params.iter().enumerate().map(|(late_bound_idx, param)| {
-                let pair = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
-                let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                bound_vars.insert(pair.0, pair.1);
-                r
+                let arg = ResolvedArg::late(initial_bound_vars + late_bound_idx as u32, param);
+                bound_vars.insert(param.def_id, arg);
+                late_arg_as_bound_arg(self.tcx, param)
             });
         binders.extend(binders_iter);
 
@@ -458,9 +522,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     .iter()
                     .enumerate()
                     .map(|(late_bound_idx, param)| {
-                        let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                        let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                        (pair, r)
+                        (
+                            (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                            late_arg_as_bound_arg(self.tcx, param),
+                        )
                     })
                     .unzip();
 
@@ -485,29 +550,85 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
         }
     }
 
+    /// Resolve the lifetimes inside the opaque type, and save them into
+    /// `opaque_captured_lifetimes`.
+    ///
+    /// This method has special handling for opaques that capture all lifetimes,
+    /// like async desugaring.
     #[instrument(level = "debug", skip(self))]
     fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
-        // We want to start our early-bound indices at the end of the parent scope,
-        // not including any parent `impl Trait`s.
-        let mut bound_vars = FxIndexMap::default();
-        debug!(?opaque.generics.params);
-        for param in opaque.generics.params {
-            let (def_id, reg) = ResolvedArg::early(param);
-            bound_vars.insert(def_id, reg);
+        let captures = RefCell::new(FxIndexMap::default());
+
+        let capture_all_in_scope_lifetimes =
+            opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
+        if capture_all_in_scope_lifetimes {
+            let lifetime_ident = |def_id: LocalDefId| {
+                let name = self.tcx.item_name(def_id.to_def_id());
+                let span = self.tcx.def_span(def_id);
+                Ident::new(name, span)
+            };
+
+            // We list scopes outwards, this causes us to see lifetime parameters in reverse
+            // declaration order. In order to make it consistent with what `generics_of` might
+            // give, we will reverse the IndexMap after early captures.
+            let mut scope = self.scope;
+            let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
+            loop {
+                match *scope {
+                    Scope::Binder { ref bound_vars, s, .. } => {
+                        for (&original_lifetime, &def) in bound_vars.iter().rev() {
+                            if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
+                                let ident = lifetime_ident(original_lifetime);
+                                self.remap_opaque_captures(&opaque_capture_scopes, def, ident);
+                            }
+                        }
+                        scope = s;
+                    }
+
+                    Scope::Root { mut opt_parent_item } => {
+                        while let Some(parent_item) = opt_parent_item {
+                            let parent_generics = self.tcx.generics_of(parent_item);
+                            for param in parent_generics.own_params.iter().rev() {
+                                if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                    let def = ResolvedArg::EarlyBound(param.def_id.expect_local());
+                                    let ident = lifetime_ident(param.def_id.expect_local());
+                                    self.remap_opaque_captures(&opaque_capture_scopes, def, ident);
+                                }
+                            }
+                            opt_parent_item = parent_generics.parent.and_then(DefId::as_local);
+                        }
+                        break;
+                    }
+
+                    Scope::Opaque { captures, def_id, s } => {
+                        opaque_capture_scopes.push((def_id, captures));
+                        scope = s;
+                    }
+
+                    Scope::Body { .. } => {
+                        bug!("{:?}", scope)
+                    }
+
+                    Scope::ObjectLifetimeDefault { s, .. }
+                    | Scope::Supertrait { s, .. }
+                    | Scope::TraitRefBoundary { s, .. }
+                    | Scope::LateBoundary { s, .. } => {
+                        scope = s;
+                    }
+                }
+            }
+            captures.borrow_mut().reverse();
         }
 
-        let hir_id = self.tcx.local_def_id_to_hir_id(opaque.def_id);
-        let scope = Scope::Binder {
-            hir_id,
-            bound_vars,
-            s: self.scope,
-            scope_type: BinderScopeType::Normal,
-            where_bound_origin: None,
-        };
+        let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
         self.with(scope, |this| {
             let scope = Scope::TraitRefBoundary { s: this.scope };
             this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
-        })
+        });
+
+        let captures = captures.into_inner().into_iter().collect();
+        debug!(?captures);
+        self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -618,9 +739,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     .iter()
                     .enumerate()
                     .map(|(late_bound_idx, param)| {
-                        let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                        let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                        (pair, r)
+                        (
+                            (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                            late_arg_as_bound_arg(self.tcx, param),
+                        )
                     })
                     .unzip();
 
@@ -681,67 +803,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                 };
                 self.with(scope, |this| this.visit_ty(mt.ty));
             }
-            hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
-                self.visit_opaque_ty(opaque_ty);
-
-                // Resolve the lifetimes in the bounds to the lifetime defs in the generics.
-                // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
-                // `type MyAnonTy<'b> = impl MyTrait<'b>;`
-                //                 ^                  ^ this gets resolved in the scope of
-                //                                      the opaque_ty generics
-
-                // Resolve the lifetimes that are applied to the opaque type.
-                // These are resolved in the current scope.
-                // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to
-                // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
-                //          ^                 ^this gets resolved in the current scope
-                for lifetime in lifetimes {
-                    let hir::GenericArg::Lifetime(lifetime) = lifetime else { continue };
-                    self.visit_lifetime(lifetime);
-
-                    // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
-                    // and ban them. Type variables instantiated inside binders aren't
-                    // well-supported at the moment, so this doesn't work.
-                    // In the future, this should be fixed and this error should be removed.
-                    let def = self.map.defs.get(&lifetime.hir_id.local_id).copied();
-                    let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue };
-                    let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
-
-                    let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id))
-                    {
-                        // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
-                        // it must be a reified late-bound lifetime from a trait goal.
-                        hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`",
-                        // Other items are fine.
-                        hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => {
-                            continue;
-                        }
-                        hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => {
-                            "higher-ranked lifetime from function pointer"
-                        }
-                        hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => {
-                            "higher-ranked lifetime from `dyn` type"
-                        }
-                        _ => "higher-ranked lifetime",
-                    };
-
-                    let (span, label) = if lifetime.ident.span == self.tcx.def_span(lifetime_def_id)
-                    {
-                        (opaque_ty.span, Some(opaque_ty.span))
-                    } else {
-                        (lifetime.ident.span, None)
-                    };
-
-                    // Ensure that the parent of the def is an item, not HRTB
-                    self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime {
-                        span,
-                        label,
-                        decl_span: self.tcx.def_span(lifetime_def_id),
-                        bad_place,
-                    });
-                    self.uninsert_lifetime_on_error(lifetime, def.unwrap());
-                }
-            }
             _ => intravisit::walk_ty(self, ty),
         }
     }
@@ -870,9 +931,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                         .iter()
                         .enumerate()
                         .map(|(late_bound_idx, param)| {
-                            let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                            let r = late_arg_as_bound_arg(self.tcx, &pair.1, param);
-                            (pair, r)
+                            (
+                                (param.def_id, ResolvedArg::late(late_bound_idx as u32, param)),
+                                late_arg_as_bound_arg(self.tcx, param),
+                            )
                         })
                         .unzip();
 
@@ -1052,19 +1114,21 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> = generics
             .params
             .iter()
-            .map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    if self.tcx.is_late_bound(param.hir_id) {
-                        let late_bound_idx = named_late_bound_vars;
-                        named_late_bound_vars += 1;
-                        ResolvedArg::late(late_bound_idx, param)
-                    } else {
+            .map(|param| {
+                (param.def_id, match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        if self.tcx.is_late_bound(param.hir_id) {
+                            let late_bound_idx = named_late_bound_vars;
+                            named_late_bound_vars += 1;
+                            ResolvedArg::late(late_bound_idx, param)
+                        } else {
+                            ResolvedArg::early(param)
+                        }
+                    }
+                    GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                         ResolvedArg::early(param)
                     }
-                }
-                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                    ResolvedArg::early(param)
-                }
+                })
             })
             .collect();
 
@@ -1075,11 +1139,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 matches!(param.kind, GenericParamKind::Lifetime { .. })
                     && self.tcx.is_late_bound(param.hir_id)
             })
-            .enumerate()
-            .map(|(late_bound_idx, param)| {
-                let pair = ResolvedArg::late(late_bound_idx as u32, param);
-                late_arg_as_bound_arg(self.tcx, &pair.1, param)
-            })
+            .map(|param| late_arg_as_bound_arg(self.tcx, param))
             .collect();
         self.record_late_bound_vars(hir_id, binders);
         let scope = Scope::Binder {
@@ -1096,7 +1156,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     where
         F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
     {
-        let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
+        let bound_vars =
+            generics.params.iter().map(|param| (param.def_id, ResolvedArg::early(param))).collect();
         self.record_late_bound_vars(hir_id, vec![]);
         let scope = Scope::Binder {
             hir_id,
@@ -1125,6 +1186,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         let mut scope = self.scope;
         let mut outermost_body = None;
         let mut crossed_late_boundary = None;
+        let mut opaque_capture_scopes = vec![];
         let result = loop {
             match *scope {
                 Scope::Body { id, s } => {
@@ -1200,6 +1262,12 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     scope = s;
                 }
 
+                Scope::Opaque { captures, def_id, s } => {
+                    opaque_capture_scopes.push((def_id, captures));
+                    late_depth = 0;
+                    scope = s;
+                }
+
                 Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. } => {
@@ -1214,6 +1282,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         };
 
         if let Some(mut def) = result {
+            def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident);
+
             if let ResolvedArg::EarlyBound(..) = def {
                 // Do not free early-bound regions, only late-bound ones.
             } else if let ResolvedArg::LateBound(_, _, param_def_id) = def
@@ -1287,6 +1357,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Root { .. } => break,
                 Scope::Binder { s, .. }
                 | Scope::Body { s, .. }
+                | Scope::Opaque { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
@@ -1302,6 +1373,79 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         );
     }
 
+    /// Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
+    /// and ban them. Type variables instantiated inside binders aren't
+    /// well-supported at the moment, so this doesn't work.
+    /// In the future, this should be fixed and this error should be removed.
+    fn check_lifetime_is_capturable(
+        &self,
+        opaque_def_id: LocalDefId,
+        lifetime: ResolvedArg,
+        capture_span: Span,
+    ) -> Result<(), ErrorGuaranteed> {
+        let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) };
+        let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
+        let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) {
+            // Opaques do not declare their own lifetimes, so if a lifetime comes from an opaque
+            // it must be a reified late-bound lifetime from a trait goal.
+            hir::Node::OpaqueTy(_) => "higher-ranked lifetime from outer `impl Trait`",
+            // Other items are fine.
+            hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => return Ok(()),
+            hir::Node::Ty(hir::Ty { kind: hir::TyKind::BareFn(_), .. }) => {
+                "higher-ranked lifetime from function pointer"
+            }
+            hir::Node::Ty(hir::Ty { kind: hir::TyKind::TraitObject(..), .. }) => {
+                "higher-ranked lifetime from `dyn` type"
+            }
+            _ => "higher-ranked lifetime",
+        };
+
+        let decl_span = self.tcx.def_span(lifetime_def_id);
+        let (span, label) = if capture_span != decl_span {
+            (capture_span, None)
+        } else {
+            let opaque_span = self.tcx.def_span(opaque_def_id);
+            (opaque_span, Some(opaque_span))
+        };
+
+        // Ensure that the parent of the def is an item, not HRTB
+        let guar = self.tcx.dcx().emit_err(errors::OpaqueCapturesHigherRankedLifetime {
+            span,
+            label,
+            decl_span,
+            bad_place,
+        });
+        Err(guar)
+    }
+
+    #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)]
+    fn remap_opaque_captures(
+        &self,
+        opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
+        mut lifetime: ResolvedArg,
+        ident: Ident,
+    ) -> ResolvedArg {
+        if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() {
+            if let Err(guar) =
+                self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span)
+            {
+                lifetime = ResolvedArg::Error(guar);
+            }
+        }
+
+        for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() {
+            let mut captures = captures.borrow_mut();
+            let remapped = *captures.entry(lifetime).or_insert_with(|| {
+                let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam);
+                feed.def_span(ident.span);
+                feed.def_ident_span(Some(ident.span));
+                feed.def_id()
+            });
+            lifetime = ResolvedArg::EarlyBound(remapped);
+        }
+        lifetime
+    }
+
     fn resolve_type_ref(&mut self, param_def_id: LocalDefId, hir_id: HirId) {
         // Walk up the scope chain, tracking the number of fn scopes
         // that we pass through, until we find a lifetime with the
@@ -1341,6 +1485,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 }
 
                 Scope::ObjectLifetimeDefault { s, .. }
+                | Scope::Opaque { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. } => {
                     scope = s;
@@ -1421,6 +1566,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Root { .. } => break,
                 Scope::Binder { s, .. }
                 | Scope::Body { s, .. }
+                | Scope::Opaque { s, .. }
                 | Scope::ObjectLifetimeDefault { s, .. }
                 | Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
@@ -1497,6 +1643,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
 
                         Scope::Binder { s, .. }
                         | Scope::ObjectLifetimeDefault { s, .. }
+                        | Scope::Opaque { s, .. }
                         | Scope::Supertrait { s, .. }
                         | Scope::TraitRefBoundary { s, .. }
                         | Scope::LateBoundary { s, .. } => {
@@ -1639,17 +1786,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         constraint.ident,
                         ty::AssocKind::Fn,
                     ) {
-                    bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map(
-                        |param| match param.kind {
-                            ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
-                                ty::BoundRegionKind::BrNamed(param.def_id, param.name),
-                            ),
-                            ty::GenericParamDefKind::Type { .. } => ty::BoundVariableKind::Ty(
-                                ty::BoundTyKind::Param(param.def_id, param.name),
-                            ),
-                            ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
-                        },
-                    ));
+                    bound_vars.extend(
+                        self.tcx
+                            .generics_of(assoc_fn.def_id)
+                            .own_params
+                            .iter()
+                            .map(|param| generic_param_def_as_bound_arg(param)),
+                    );
                     bound_vars.extend(
                         self.tcx.fn_sig(assoc_fn.def_id).instantiate_identity().bound_vars(),
                     );
@@ -1786,7 +1929,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
     fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
         let mut late_depth = 0;
         let mut scope = self.scope;
-        let lifetime = loop {
+        let mut opaque_capture_scopes = vec![];
+        let mut lifetime = loop {
             match *scope {
                 Scope::Binder { s, scope_type, .. } => {
                     match scope_type {
@@ -1800,7 +1944,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
 
                 Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return,
 
-                Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l,
+                Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => {
+                    break l.shifted(late_depth);
+                }
+
+                Scope::Opaque { captures, def_id, s } => {
+                    opaque_capture_scopes.push((def_id, captures));
+                    late_depth = 0;
+                    scope = s;
+                }
 
                 Scope::Supertrait { s, .. }
                 | Scope::TraitRefBoundary { s, .. }
@@ -1809,7 +1961,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 }
             }
         };
-        self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth));
+
+        lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident);
+
+        self.insert_lifetime(lifetime_ref, lifetime);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1818,18 +1973,6 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         self.map.defs.insert(lifetime_ref.hir_id.local_id, def);
     }
 
-    /// Sometimes we resolve a lifetime, but later find that it is an
-    /// error (esp. around impl trait). In that case, we remove the
-    /// entry into `map.defs` so as not to confuse later code.
-    fn uninsert_lifetime_on_error(
-        &mut self,
-        lifetime_ref: &'tcx hir::Lifetime,
-        bad_def: ResolvedArg,
-    ) {
-        let old_value = self.map.defs.remove(&lifetime_ref.hir_id.local_id);
-        assert_eq!(old_value, Some(bad_def));
-    }
-
     // When we have a return type notation type in a where clause, like
     // `where <T as Trait>::method(..): Send`, we need to introduce new bound
     // vars to the existing where clause's binder, to represent the lifetimes
@@ -1968,17 +2111,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
         // Append the early-bound vars on the function, and then the late-bound ones.
         // We actually turn type parameters into higher-ranked types here, but we
         // deny them later in HIR lowering.
-        bound_vars.extend(self.tcx.generics_of(item_def_id).own_params.iter().map(|param| {
-            match param.kind {
-                ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
-                    ty::BoundRegionKind::BrNamed(param.def_id, param.name),
-                ),
-                ty::GenericParamDefKind::Type { .. } => {
-                    ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(param.def_id, param.name))
-                }
-                ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
-            }
-        }));
+        bound_vars.extend(
+            self.tcx
+                .generics_of(item_def_id)
+                .own_params
+                .iter()
+                .map(|param| generic_param_def_as_bound_arg(param)),
+        );
         bound_vars.extend(self.tcx.fn_sig(item_def_id).instantiate_identity().bound_vars());
 
         // SUBTLE: Stash the old bound vars onto the *item segment* before appending
@@ -2017,18 +2156,22 @@ fn is_late_bound_map(
     tcx: TyCtxt<'_>,
     owner_id: hir::OwnerId,
 ) -> Option<&FxIndexSet<hir::ItemLocalId>> {
-    let decl = tcx.hir().fn_decl_by_hir_id(owner_id.into())?;
+    let sig = tcx.hir().fn_sig_by_hir_id(owner_id.into())?;
     let generics = tcx.hir().get_generics(owner_id.def_id)?;
 
     let mut late_bound = FxIndexSet::default();
 
     let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
-    for arg_ty in decl.inputs {
+    for arg_ty in sig.decl.inputs {
         constrained_by_input.visit_ty(arg_ty);
     }
 
-    let mut appears_in_output = AllCollector::default();
-    intravisit::walk_fn_ret_ty(&mut appears_in_output, &decl.output);
+    let mut appears_in_output =
+        AllCollector { tcx, has_fully_capturing_opaque: false, regions: Default::default() };
+    intravisit::walk_fn_ret_ty(&mut appears_in_output, &sig.decl.output);
+    if appears_in_output.has_fully_capturing_opaque {
+        appears_in_output.regions.extend(generics.params.iter().map(|param| param.def_id));
+    }
 
     debug!(?constrained_by_input.regions);
 
@@ -2036,7 +2179,8 @@ fn is_late_bound_map(
     //
     // Subtle point: because we disallow nested bindings, we can just
     // ignore binders here and scrape up all names we see.
-    let mut appears_in_where_clause = AllCollector::default();
+    let mut appears_in_where_clause =
+        AllCollector { tcx, has_fully_capturing_opaque: true, regions: Default::default() };
     appears_in_where_clause.visit_generics(generics);
     debug!(?appears_in_where_clause.regions);
 
@@ -2202,17 +2346,26 @@ fn is_late_bound_map(
         }
     }
 
-    #[derive(Default)]
-    struct AllCollector {
+    struct AllCollector<'tcx> {
+        tcx: TyCtxt<'tcx>,
+        has_fully_capturing_opaque: bool,
         regions: FxHashSet<LocalDefId>,
     }
 
-    impl<'v> Visitor<'v> for AllCollector {
+    impl<'v> Visitor<'v> for AllCollector<'v> {
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
             if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
                 self.regions.insert(def_id);
             }
         }
+
+        fn visit_opaque_ty(&mut self, opaque: &'v hir::OpaqueTy<'v>) {
+            if !self.has_fully_capturing_opaque {
+                self.has_fully_capturing_opaque =
+                    opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
+            }
+            intravisit::walk_opaque_ty(self, opaque);
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 77e81af3ca9..a92a5e4278c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1624,10 +1624,14 @@ pub(crate) struct InvalidReceiverTy<'tcx> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_effects_without_next_solver)]
+#[diag(hir_analysis_invalid_generic_receiver_ty, code = E0801)]
 #[note]
-#[help]
-pub(crate) struct EffectsWithoutNextSolver;
+#[help(hir_analysis_invalid_generic_receiver_ty_help)]
+pub(crate) struct InvalidGenericReceiverTy<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub receiver_ty: Ty<'tcx>,
+}
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_cmse_inputs_stack_spill, code = E0798)]
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 c902e85c267..a5709089db6 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -168,13 +168,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             match hir_bound {
                 hir::GenericBound::Trait(poly_trait_ref) => {
                     let hir::TraitBoundModifiers { constness, polarity } = poly_trait_ref.modifiers;
-                    // FIXME: We could pass these directly into `lower_poly_trait_ref`
-                    // so that we could use these spans in diagnostics within that function...
-                    let constness = match constness {
-                        hir::BoundConstness::Never => None,
-                        hir::BoundConstness::Always(_) => Some(ty::BoundConstness::Const),
-                        hir::BoundConstness::Maybe(_) => Some(ty::BoundConstness::ConstIfConst),
-                    };
                     let polarity = match polarity {
                         rustc_ast::BoundPolarity::Positive => ty::PredicatePolarity::Positive,
                         rustc_ast::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 890e8fa99e6..f2ee4b0ccd4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -50,7 +50,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             } = self.lower_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
-                None,
+                hir::BoundConstness::Never,
                 ty::PredicatePolarity::Positive,
                 dummy_self,
                 &mut bounds,
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 863c077a9e0..f2bc17051ab 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -39,7 +39,7 @@ use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
     self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
-    TypeVisitableExt,
+    TypeVisitableExt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -294,13 +294,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         lifetime: &hir::Lifetime,
         reason: RegionInferReason<'_>,
     ) -> ty::Region<'tcx> {
+        if let Some(resolved) = self.tcx().named_bound_var(lifetime.hir_id) {
+            self.lower_resolved_lifetime(resolved)
+        } else {
+            self.re_infer(lifetime.ident.span, reason)
+        }
+    }
+
+    /// Lower a lifetime from the HIR to our internal notion of a lifetime called a *region*.
+    #[instrument(level = "debug", skip(self), ret)]
+    pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> {
         let tcx = self.tcx();
         let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id));
 
-        match tcx.named_bound_var(lifetime.hir_id) {
-            Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static,
+        match resolved {
+            rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static,
 
-            Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => {
+            rbv::ResolvedArg::LateBound(debruijn, index, def_id) => {
                 let name = lifetime_name(def_id);
                 let br = ty::BoundRegion {
                     var: ty::BoundVar::from_u32(index),
@@ -309,7 +319,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 ty::Region::new_bound(tcx, debruijn, br)
             }
 
-            Some(rbv::ResolvedArg::EarlyBound(def_id)) => {
+            rbv::ResolvedArg::EarlyBound(def_id) => {
                 let name = tcx.hir().ty_param_name(def_id);
                 let item_def_id = tcx.hir().ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
@@ -317,7 +327,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name })
             }
 
-            Some(rbv::ResolvedArg::Free(scope, id)) => {
+            rbv::ResolvedArg::Free(scope, id) => {
                 let name = lifetime_name(id);
                 ty::Region::new_late_param(
                     tcx,
@@ -328,9 +338,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 // (*) -- not late-bound, won't change
             }
 
-            Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar),
-
-            None => self.re_infer(lifetime.ident.span, reason),
+            rbv::ResolvedArg::Error(guar) => ty::Region::new_error(tcx, guar),
         }
     }
 
@@ -658,7 +666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         trait_ref: &hir::TraitRef<'tcx>,
         span: Span,
-        constness: Option<ty::BoundConstness>,
+        constness: hir::BoundConstness,
         polarity: ty::PredicatePolarity,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
@@ -681,11 +689,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(self_ty),
         );
 
-        if let Some(constness) = constness
+        if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness
             && !self.tcx().is_const_trait(trait_def_id)
         {
             self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
-                span: trait_ref.path.span,
+                span,
                 modifier: constness.as_str(),
             });
         }
@@ -708,7 +716,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity);
 
                 match constness {
-                    Some(ty::BoundConstness::Const) => {
+                    hir::BoundConstness::Always(span) => {
                         if polarity == ty::PredicatePolarity::Positive {
                             bounds.push_const_bound(
                                 tcx,
@@ -718,13 +726,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                             );
                         }
                     }
-                    Some(ty::BoundConstness::ConstIfConst) => {
+                    hir::BoundConstness::Maybe(_) => {
                         // We don't emit a const bound here, since that would mean that we
                         // unconditionally need to prove a `HostEffect` predicate, even when
                         // the predicates are being instantiated in a non-const context. This
                         // is instead handled in the `const_conditions` query.
                     }
-                    None => {}
+                    hir::BoundConstness::Never => {}
                 }
             }
             // On the flip side, when filtering `ConstIfConst` bounds, we only need to convert
@@ -734,12 +742,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             // here because we only call this on self bounds, and deal with the recursive case
             // in `lower_assoc_item_constraint`.
             PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => match constness {
-                Some(ty::BoundConstness::ConstIfConst) => {
+                hir::BoundConstness::Maybe(span) => {
                     if polarity == ty::PredicatePolarity::Positive {
                         bounds.push_const_bound(tcx, poly_trait_ref, ty::HostPolarity::Maybe, span);
                     }
                 }
-                None | Some(ty::BoundConstness::Const) => {}
+                hir::BoundConstness::Always(_) | hir::BoundConstness::Never => {}
             },
         }
 
@@ -1203,15 +1211,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     err.emit()
                 } else if let Err(reported) = qself_ty.error_reported() {
                     reported
-                } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
-                    // `<impl Trait as OtherTrait>::Assoc` makes no sense.
-                    struct_span_code_err!(
-                        self.dcx(),
-                        tcx.def_span(alias_ty.def_id),
-                        E0667,
-                        "`impl Trait` is not allowed in path parameters"
-                    )
-                    .emit() // Already reported in an earlier stage.
                 } else {
                     self.maybe_report_similar_assoc_fn(span, qself_ty, qself)?;
 
@@ -1309,7 +1308,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(infcx) => infcx,
             None => {
                 assert!(!self_ty.has_infer());
-                infcx_ = tcx.infer_ctxt().ignoring_regions().build();
+                infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
                 &infcx_
             }
         };
@@ -1501,7 +1500,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             infcx
         } else {
             assert!(!qself_ty.has_infer());
-            infcx_ = tcx.infer_ctxt().build();
+            infcx_ = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             &infcx_
         };
 
@@ -2103,13 +2102,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself));
                 self.lower_path(opt_self_ty, path, hir_ty.hir_id, false)
             }
-            &hir::TyKind::OpaqueDef(opaque_ty, lifetimes) => {
-                let local_def_id = opaque_ty.def_id;
-
+            &hir::TyKind::OpaqueDef(opaque_ty) => {
                 // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
                 // generate the def_id of an associated type for the trait and return as
                 // type a projection.
-                match opaque_ty.origin {
+                let in_trait = match opaque_ty.origin {
                     hir::OpaqueTyOrigin::FnReturn {
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
@@ -2117,11 +2114,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     | hir::OpaqueTyOrigin::AsyncFn {
                         in_trait_or_impl: Some(hir::RpitContext::Trait),
                         ..
-                    } => self.lower_opaque_ty(
-                        tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id(),
-                        lifetimes,
-                        true,
-                    ),
+                    } => true,
                     hir::OpaqueTyOrigin::FnReturn {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
@@ -2130,10 +2123,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                         in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
                         ..
                     }
-                    | hir::OpaqueTyOrigin::TyAlias { .. } => {
-                        self.lower_opaque_ty(local_def_id.to_def_id(), lifetimes, false)
-                    }
-                }
+                    | hir::OpaqueTyOrigin::TyAlias { .. } => false,
+                };
+
+                self.lower_opaque_ty(opaque_ty.def_id, in_trait)
             }
             // If we encounter a type relative path with RTN generics, then it must have
             // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore
@@ -2273,40 +2266,34 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
     }
 
     /// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
-    #[instrument(level = "debug", skip_all, ret)]
-    fn lower_opaque_ty(
-        &self,
-        def_id: DefId,
-        lifetimes: &[hir::GenericArg<'_>],
-        in_trait: bool,
-    ) -> Ty<'tcx> {
-        debug!(?def_id, ?lifetimes);
+    #[instrument(level = "debug", skip(self), ret)]
+    fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
         let tcx = self.tcx();
 
+        let lifetimes = tcx.opaque_captured_lifetimes(def_id);
+        debug!(?lifetimes);
+
+        // If this is an RPITIT and we are using the new RPITIT lowering scheme, we
+        // generate the def_id of an associated type for the trait and return as
+        // type a projection.
+        let def_id = if in_trait {
+            tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id()
+        } else {
+            def_id.to_def_id()
+        };
+
         let generics = tcx.generics_of(def_id);
         debug!(?generics);
 
+        // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count`
+        // since return-position impl trait in trait squashes all of the generics from its source fn
+        // into its own generics, so the opaque's "own" params isn't always just lifetimes.
+        let offset = generics.count() - lifetimes.len();
+
         let args = ty::GenericArgs::for_item(tcx, def_id, |param, _| {
-            // We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count`
-            // since return-position impl trait in trait squashes all of the generics from its source fn
-            // into its own generics, so the opaque's "own" params isn't always just lifetimes.
-            if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len())
-            {
-                // Resolve our own lifetime parameters.
-                let GenericParamDefKind::Lifetime { .. } = param.kind else {
-                    span_bug!(
-                        tcx.def_span(param.def_id),
-                        "only expected lifetime for opaque's own generics, got {:?}",
-                        param
-                    );
-                };
-                let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else {
-                    bug!(
-                        "expected lifetime argument for param {param:?}, found {:?}",
-                        &lifetimes[i]
-                    )
-                };
-                self.lower_lifetime(lifetime, RegionInferReason::Param(&param)).into()
+            if let Some(i) = (param.index as usize).checked_sub(offset) {
+                let (lifetime, _) = lifetimes[i];
+                self.lower_resolved_lifetime(lifetime).into()
             } else {
                 tcx.mk_param_from_def(param)
             }
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 2fa4ca68073..5b0165bf993 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_span::def_id::LocalDefId;
 use rustc_trait_selection::traits::{self, ObligationCtxt};
 use tracing::debug;
@@ -68,7 +68,7 @@ fn diagnostic_hir_wf_check<'tcx>(
 
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-            let infcx = self.tcx.infer_ctxt().build();
+            let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
             let tcx_ty = self.icx.lower_ty(ty);
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index a394fc2fbb1..b0c9aed5d85 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -72,7 +72,9 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::traits::specialization_graph::Node;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
-use rustc_middle::ty::{self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, GenericArg, GenericArgs, GenericArgsRef, TyCtxt, TypeVisitableExt, TypingMode,
+};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
@@ -195,7 +197,7 @@ fn get_impl_args(
     impl1_def_id: LocalDefId,
     impl2_node: Node,
 ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> {
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(infcx);
     let param_env = tcx.param_env(impl1_def_id);
     let impl1_span = tcx.def_span(impl1_def_id);
@@ -409,7 +411,7 @@ fn check_predicates<'tcx>(
 
     // Include the well-formed predicates of the type parameters of the impl.
     for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity().args {
-        let infcx = &tcx.infer_ctxt().build();
+        let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let obligations =
             wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span)
                 .unwrap();
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 3ad35163191..339eddeeade 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -153,12 +153,6 @@ pub fn provide(providers: &mut Providers) {
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let _prof_timer = tcx.sess.timer("type_check_crate");
 
-    // FIXME(effects): remove once effects is implemented in old trait solver
-    // or if the next solver is stabilized.
-    if tcx.features().effects() && !tcx.next_trait_solver_globally() {
-        tcx.dcx().emit_err(errors::EffectsWithoutNextSolver);
-    }
-
     tcx.sess.time("coherence_checking", || {
         tcx.hir().par_for_each_module(|module| {
             let _ = tcx.ensure().check_mod_type_wf(module);
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 61214b99215..2073f2868b4 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -659,8 +659,6 @@ impl<'a> State<'a> {
 
     fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) {
         self.head("opaque");
-        self.print_generic_params(o.generics.params);
-        self.print_where_clause(o.generics);
         self.word("{");
         self.print_bounds("impl", o.bounds);
         self.word("}");
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index e68caa3e2e3..3372cae7a51 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -94,14 +94,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 (None, arm.body.span)
             };
 
-            let (span, code) = match prior_arm {
+            let code = match prior_arm {
                 // The reason for the first arm to fail is not that the match arms diverge,
                 // but rather that there's a prior obligation that doesn't hold.
-                None => {
-                    (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src))
-                }
-                Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => (
-                    expr.span,
+                None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src),
+                Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => {
                     ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
                         arm_block_id,
                         arm_span,
@@ -110,13 +107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         prior_arm_ty,
                         prior_arm_span,
                         scrut_span: scrut.span,
+                        expr_span: expr.span,
                         source: match_src,
                         prior_non_diverging_arms: prior_non_diverging_arms.clone(),
                         tail_defines_return_position_impl_trait,
-                    })),
-                ),
+                    }))
+                }
             };
-            let cause = self.cause(span, code);
+            let cause = self.cause(arm_span, code);
 
             // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
             // We use it this way to be able to expand on the potential error and detect when a
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index e4ca1cee757..c3e095b0554 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -23,7 +23,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         base_ty: Ty<'tcx>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
+        self.try_overloaded_place_op(span, base_ty, None, PlaceOp::Deref)
     }
 
     /// Returns the adjustment steps.
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index ed56bb9c455..9cf1ea3fcb8 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,4 +1,4 @@
-use std::{iter, slice};
+use std::iter;
 
 use rustc_ast::util::parser::PREC_UNAMBIGUOUS;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
@@ -300,7 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ident::with_dummy_span(method_name),
                 trait_def_id,
                 adjusted_ty,
-                opt_input_type.as_ref().map(slice::from_ref),
+                opt_input_type,
             ) {
                 let method = self.register_infer_ok_obligations(ok);
                 let mut autoref = None;
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 92c2a906055..d6e5fab610e 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2027,7 +2027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     }
                                     Err(_) => {
                                         span_bug!(
-                                            cause.span(),
+                                            cause.span,
                                             "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}",
                                             variant.name,
                                             ident.name,
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 96784fcb61b..92b504d10bc 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -533,9 +533,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                 self.register_predicates(obligations);
             }
             Err(terr) => {
-                // FIXME(arbitrary_self_types): We probably should limit the
-                // situations where this can occur by adding additional restrictions
-                // to the feature, like the self type can't reference method args.
                 if self.tcx.features().arbitrary_self_types() {
                     self.err_ctxt()
                         .report_mismatched_types(
@@ -550,7 +547,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
                     // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions
                     // may run before wfcheck if the function is used in const eval.
                     self.dcx().span_delayed_bug(
-                        cause.span(),
+                        cause.span,
                         format!("{self_ty} was a subtype of {method_self_ty} but now is not?"),
                     );
                 }
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index e20a0cb67c3..e0b6ea0ac9d 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -324,35 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         Ok(pick)
     }
 
-    pub(super) fn obligation_for_method(
-        &self,
-        cause: ObligationCause<'tcx>,
-        trait_def_id: DefId,
-        self_ty: Ty<'tcx>,
-        opt_input_types: Option<&[Ty<'tcx>]>,
-    ) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) {
-        // Construct a trait-reference `self_ty : Trait<input_tys>`
-        let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
-            match param.kind {
-                GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {}
-                GenericParamDefKind::Type { .. } => {
-                    if param.index == 0 {
-                        return self_ty.into();
-                    } else if let Some(input_types) = opt_input_types {
-                        return input_types[param.index as usize - 1].into();
-                    }
-                }
-            }
-            self.var_for_def(cause.span, param)
-        });
-
-        let trait_ref = ty::TraitRef::new_from_args(self.tcx, trait_def_id, args);
-
-        // Construct an obligation
-        let poly_trait_ref = ty::Binder::dummy(trait_ref);
-        (traits::Obligation::new(self.tcx, cause, self.param_env, poly_trait_ref), args)
-    }
-
     /// `lookup_method_in_trait` is used for overloaded operators.
     /// It does a very narrow slice of what the normal probe/confirm path does.
     /// In particular, it doesn't really do any probing: it simply constructs
@@ -365,24 +336,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         m_name: Ident,
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
-        opt_input_types: Option<&[Ty<'tcx>]>,
+        opt_rhs_ty: Option<Ty<'tcx>>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        let (obligation, args) =
-            self.obligation_for_method(cause, trait_def_id, self_ty, opt_input_types);
-        self.construct_obligation_for_trait(m_name, trait_def_id, obligation, args)
-    }
+        // Construct a trait-reference `self_ty : Trait<input_tys>`
+        let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| match param.kind {
+            GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => {
+                unreachable!("did not expect operator trait to have lifetime/const")
+            }
+            GenericParamDefKind::Type { .. } => {
+                if param.index == 0 {
+                    self_ty.into()
+                } else if let Some(rhs_ty) = opt_rhs_ty {
+                    assert_eq!(param.index, 1, "did not expect >1 param on operator trait");
+                    rhs_ty.into()
+                } else {
+                    // FIXME: We should stop passing `None` for the failure case
+                    // when probing for call exprs. I.e. `opt_rhs_ty` should always
+                    // be set when it needs to be.
+                    self.var_for_def(cause.span, param)
+                }
+            }
+        });
 
-    // FIXME(#18741): it seems likely that we can consolidate some of this
-    // code with the other method-lookup code. In particular, the second half
-    // of this method is basically the same as confirmation.
-    fn construct_obligation_for_trait(
-        &self,
-        m_name: Ident,
-        trait_def_id: DefId,
-        obligation: traits::PredicateObligation<'tcx>,
-        args: ty::GenericArgsRef<'tcx>,
-    ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
-        debug!(?obligation);
+        let obligation = traits::Obligation::new(
+            self.tcx,
+            cause,
+            self.param_env,
+            ty::TraitRef::new_from_args(self.tcx, trait_def_id, args),
+        );
 
         // Now we want to know if this can be matched
         if !self.predicate_may_hold(&obligation) {
@@ -406,8 +387,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
         let mut obligations = PredicateObligations::new();
 
-        // FIXME(effects): revisit when binops get `#[const_trait]`
-
         // Instantiate late-bound regions and instantiate the trait
         // parameters into the method type to get the actual method type.
         //
@@ -418,12 +397,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let fn_sig =
             self.instantiate_binder_with_fresh_vars(obligation.cause.span, infer::FnCall, fn_sig);
 
-        let InferOk { value, obligations: o } =
+        let InferOk { value: fn_sig, obligations: o } =
             self.at(&obligation.cause, self.param_env).normalize(fn_sig);
-        let fn_sig = {
-            obligations.extend(o);
-            value
-        };
+        obligations.extend(o);
 
         // Register obligations for the parameters. This will include the
         // `Self` parameter, which in turn has a bound of the main trait,
@@ -435,13 +411,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // any late-bound regions appearing in its bounds.
         let bounds = self.tcx.predicates_of(def_id).instantiate(self.tcx, args);
 
-        let InferOk { value, obligations: o } =
+        let InferOk { value: bounds, obligations: o } =
             self.at(&obligation.cause, self.param_env).normalize(bounds);
-        let bounds = {
-            obligations.extend(o);
-            value
-        };
-
+        obligations.extend(o);
         assert!(!bounds.has_escaping_bound_vars());
 
         let predicates_cause = obligation.cause.clone();
@@ -454,7 +426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Also add an obligation for the method type being well-formed.
         let method_ty = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
         debug!(
-            "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
+            "lookup_method_in_trait: matched method method_ty={:?} obligation={:?}",
             method_ty, obligation
         );
         obligations.push(traits::Obligation::new(
@@ -467,7 +439,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ));
 
         let callee = MethodCallee { def_id, args, sig: fn_sig };
-
         debug!("callee = {:?}", callee);
 
         Some(InferOk { obligations, value: callee })
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 1574e9e98d4..57ac7f7d2cd 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -15,7 +15,7 @@ use rustc_span::Span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{Ident, sym};
 use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
+use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt};
 use rustc_type_ir::TyKind::*;
 use tracing::debug;
 use {rustc_ast as ast, rustc_hir as hir};
@@ -895,7 +895,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let opname = Ident::with_dummy_span(opname);
         let (opt_rhs_expr, opt_rhs_ty) = opt_rhs.unzip();
-        let input_types = opt_rhs_ty.as_slice();
         let cause = self.cause(span, ObligationCauseCode::BinOp {
             lhs_hir_id: lhs_expr.hir_id,
             rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id),
@@ -904,13 +903,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             output_ty: expected.only_has_type(self),
         });
 
-        let method = self.lookup_method_in_trait(
-            cause.clone(),
-            opname,
-            trait_did,
-            lhs_ty,
-            Some(input_types),
-        );
+        let method =
+            self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, opt_rhs_ty);
         match method {
             Some(ok) => {
                 let method = self.register_infer_ok_obligations(ok);
@@ -931,9 +925,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None);
                 }
 
-                let (obligation, _) =
-                    self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
-                // FIXME: This should potentially just add the obligation to the `FnCtxt`
+                // Construct an obligation `self_ty : Trait<input_tys>`
+                let args =
+                    ty::GenericArgs::for_item(self.tcx, trait_did, |param, _| match param.kind {
+                        ty::GenericParamDefKind::Lifetime
+                        | ty::GenericParamDefKind::Const { .. } => {
+                            unreachable!("did not expect operand trait to have lifetime/const args")
+                        }
+                        ty::GenericParamDefKind::Type { .. } => {
+                            if param.index == 0 {
+                                lhs_ty.into()
+                            } else {
+                                opt_rhs_ty.expect("expected RHS for binop").into()
+                            }
+                        }
+                    });
+                let obligation = Obligation::new(
+                    self.tcx,
+                    cause,
+                    self.param_env,
+                    ty::TraitRef::new_from_args(self.tcx, trait_did, args),
+                );
                 let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx);
                 ocx.register_obligation(obligation);
                 Err(ocx.select_all_or_error())
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 8604f5f6920..5dd51721022 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If some lookup succeeded, install method in table
             let input_ty = self.next_ty_var(base_expr.span);
             let method =
-                self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
+                self.try_overloaded_place_op(expr.span, self_ty, Some(input_ty), PlaceOp::Index);
 
             if let Some(result) = method {
                 debug!("try_index_step: success, using overloaded indexing");
@@ -189,7 +189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         base_ty: Ty<'tcx>,
-        arg_tys: &[Ty<'tcx>],
+        opt_rhs_ty: Option<Ty<'tcx>>,
         op: PlaceOp,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
@@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Ident::with_dummy_span(imm_op),
             imm_tr,
             base_ty,
-            Some(arg_tys),
+            opt_rhs_ty,
         )
     }
 
@@ -215,7 +215,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         span: Span,
         base_ty: Ty<'tcx>,
-        arg_tys: &[Ty<'tcx>],
+        opt_rhs_ty: Option<Ty<'tcx>>,
         op: PlaceOp,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
@@ -233,7 +233,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Ident::with_dummy_span(mut_op),
             mut_tr,
             base_ty,
-            Some(arg_tys),
+            opt_rhs_ty,
         )
     }
 
@@ -284,7 +284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         && let Some(ok) = self.try_mutable_overloaded_place_op(
                             expr.span,
                             source,
-                            &[],
+                            None,
                             PlaceOp::Deref,
                         )
                     {
@@ -359,8 +359,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Some(self.typeck_results.borrow().node_args(expr.hir_id).type_at(1))
             }
         };
-        let arg_tys = arg_ty.as_slice();
-        let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op);
+        let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_ty, op);
         let method = match method {
             Some(ok) => self.register_infer_ok_obligations(ok),
             // Couldn't find the mutable variant of the place op, keep the
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 18e40cfa428..903be7e732a 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -8,7 +8,7 @@ use rustc_hir::{HirId, HirIdMap};
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use rustc_middle::span_bug;
 use rustc_middle::ty::visit::TypeVisitableExt;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_span::Span;
 use rustc_span::def_id::LocalDefIdMap;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -81,7 +81,8 @@ impl<'tcx> TypeckRootCtxt<'tcx> {
     pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
 
-        let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build();
+        let infcx =
+            tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id));
         let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
 
         TypeckRootCtxt {
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 8c943a961e7..3eda3e9c67e 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -28,7 +28,7 @@
 use relate::lattice::{LatticeOp, LatticeOpKind};
 use rustc_middle::bug;
 use rustc_middle::ty::relate::solver_relating::RelateExt as NextSolverRelate;
-use rustc_middle::ty::{Const, ImplSubject};
+use rustc_middle::ty::{Const, ImplSubject, TypingMode};
 
 use super::*;
 use crate::infer::relate::type_relating::TypeRelating;
@@ -67,30 +67,48 @@ impl<'tcx> InferCtxt<'tcx> {
     /// variables in the same state. This can be used to "branch off" many tests from the same
     /// common state.
     pub fn fork(&self) -> Self {
-        self.fork_with_intercrate(self.intercrate)
+        Self {
+            tcx: self.tcx,
+            typing_mode: self.typing_mode,
+            considering_regions: self.considering_regions,
+            skip_leak_check: self.skip_leak_check,
+            inner: self.inner.clone(),
+            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
+            selection_cache: self.selection_cache.clone(),
+            evaluation_cache: self.evaluation_cache.clone(),
+            reported_trait_errors: self.reported_trait_errors.clone(),
+            reported_signature_mismatch: self.reported_signature_mismatch.clone(),
+            tainted_by_errors: self.tainted_by_errors.clone(),
+            universe: self.universe.clone(),
+            next_trait_solver: self.next_trait_solver,
+            obligation_inspector: self.obligation_inspector.clone(),
+        }
     }
 
     /// Forks the inference context, creating a new inference context with the same inference
     /// variables in the same state, except possibly changing the intercrate mode. This can be
     /// used to "branch off" many tests from the same common state. Used in negative coherence.
-    pub fn fork_with_intercrate(&self, intercrate: bool) -> Self {
-        Self {
+    pub fn fork_with_typing_mode(&self, typing_mode: TypingMode<'tcx>) -> Self {
+        // Unlike `fork`, this invalidates all cache entries as they may depend on the
+        // typing mode.
+        let forked = Self {
             tcx: self.tcx,
-            defining_opaque_types: self.defining_opaque_types,
+            typing_mode,
             considering_regions: self.considering_regions,
             skip_leak_check: self.skip_leak_check,
             inner: self.inner.clone(),
             lexical_region_resolutions: self.lexical_region_resolutions.clone(),
-            selection_cache: self.selection_cache.clone(),
-            evaluation_cache: self.evaluation_cache.clone(),
+            selection_cache: Default::default(),
+            evaluation_cache: Default::default(),
             reported_trait_errors: self.reported_trait_errors.clone(),
             reported_signature_mismatch: self.reported_signature_mismatch.clone(),
             tainted_by_errors: self.tainted_by_errors.clone(),
             universe: self.universe.clone(),
-            intercrate,
             next_trait_solver: self.next_trait_solver,
             obligation_inspector: self.obligation_inspector.clone(),
-        }
+        };
+        forked.inner.borrow_mut().projection_cache().clear();
+        forked
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 90d07964fda..c9d8ebecef0 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -46,7 +46,7 @@ impl<'tcx> InferCtxt<'tcx> {
         V: TypeFoldable<TyCtxt<'tcx>>,
     {
         let (param_env, value) = value.into_parts();
-        let param_env = self.tcx.canonical_param_env_cache.get_or_insert(
+        let canonical_param_env = self.tcx.canonical_param_env_cache.get_or_insert(
             self.tcx,
             param_env,
             query_state,
@@ -64,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> {
         );
 
         let canonical = Canonicalizer::canonicalize_with_base(
-            param_env,
+            canonical_param_env,
             value,
             Some(self),
             self.tcx,
@@ -72,7 +72,7 @@ impl<'tcx> InferCtxt<'tcx> {
             query_state,
         )
         .unchecked_map(|(param_env, value)| param_env.and(value));
-        CanonicalQueryInput { canonical, defining_opaque_types: self.defining_opaque_types() }
+        CanonicalQueryInput { canonical, typing_mode: self.typing_mode(param_env) }
     }
 
     /// Canonicalizes a query *response* `V`. When we canonicalize a
diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs
index 0c151a11ad4..ecda9c6eb00 100644
--- a/compiler/rustc_infer/src/infer/context.rs
+++ b/compiler/rustc_infer/src/infer/context.rs
@@ -1,7 +1,6 @@
 ///! Definition of `InferCtxtLike` from the librarified type layer.
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::traits::solve::SolverMode;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
@@ -21,11 +20,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.next_trait_solver
     }
 
-    fn solver_mode(&self) -> ty::solve::SolverMode {
-        match self.intercrate {
-            true => SolverMode::Coherence,
-            false => SolverMode::Normal,
-        }
+    fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
+    ) -> ty::TypingMode<'tcx> {
+        self.typing_mode(param_env_for_debug_assertion)
     }
 
     fn universe(&self) -> ty::UniverseIndex {
@@ -91,10 +90,6 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
         self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
 
-    fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types()
-    }
-
     fn next_ty_infer(&self) -> Ty<'tcx> {
         self.next_ty_var(DUMMY_SP)
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index be43cba97f0..fc54d69449f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -38,11 +38,12 @@ use rustc_middle::ty::fold::{
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{
     self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef,
-    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid,
+    GenericParamDefKind, InferConst, IntVid, Ty, TyCtxt, TyVid, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
+use rustc_type_ir::solve::Reveal;
 use snapshot::undo_log::InferCtxtUndoLogs;
 use tracing::{debug, instrument};
 use type_variable::TypeVariableOrigin;
@@ -243,8 +244,9 @@ impl<'tcx> InferCtxtInner<'tcx> {
 pub struct InferCtxt<'tcx> {
     pub tcx: TyCtxt<'tcx>,
 
-    /// The `DefIds` of the opaque types that may have their hidden types constrained.
-    defining_opaque_types: &'tcx ty::List<LocalDefId>,
+    /// The mode of this inference context, see the struct documentation
+    /// for more details.
+    typing_mode: TypingMode<'tcx>,
 
     /// Whether this inference context should care about region obligations in
     /// the root universe. Most notably, this is used during hir typeck as region
@@ -296,26 +298,6 @@ pub struct InferCtxt<'tcx> {
     /// bound.
     universe: Cell<ty::UniverseIndex>,
 
-    /// During coherence we have to assume that other crates may add
-    /// additional impls which we currently don't know about.
-    ///
-    /// To deal with this evaluation, we should be conservative
-    /// and consider the possibility of impls from outside this crate.
-    /// This comes up primarily when resolving ambiguity. Imagine
-    /// there is some trait reference `$0: Bar` where `$0` is an
-    /// inference variable. If `intercrate` is true, then we can never
-    /// say for sure that this reference is not implemented, even if
-    /// there are *no impls at all for `Bar`*, because `$0` could be
-    /// bound to some type that in a downstream crate that implements
-    /// `Bar`.
-    ///
-    /// Outside of coherence, we set this to false because we are only
-    /// interested in types that the user could actually have written.
-    /// In other words, we consider `$0: Bar` to be unimplemented if
-    /// there is no type that the user could *actually name* that
-    /// would satisfy it. This avoids crippling inference, basically.
-    pub intercrate: bool,
-
     next_trait_solver: bool,
 
     pub obligation_inspector: Cell<Option<ObligationInspector<'tcx>>>,
@@ -529,11 +511,8 @@ pub struct RegionObligation<'tcx> {
 /// Used to configure inference contexts before their creation.
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    defining_opaque_types: &'tcx ty::List<LocalDefId>,
     considering_regions: bool,
     skip_leak_check: bool,
-    /// Whether we are in coherence mode.
-    intercrate: bool,
     /// Whether we should use the new trait solver in the local inference context,
     /// which affects things like which solver is used in `predicate_may_hold`.
     next_trait_solver: bool,
@@ -544,37 +523,19 @@ impl<'tcx> TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
         InferCtxtBuilder {
             tcx: self,
-            defining_opaque_types: ty::List::empty(),
             considering_regions: true,
             skip_leak_check: false,
-            intercrate: false,
             next_trait_solver: self.next_trait_solver_globally(),
         }
     }
 }
 
 impl<'tcx> InferCtxtBuilder<'tcx> {
-    /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
-    /// you need to call this function. Otherwise the opaque type will be treated opaquely.
-    ///
-    /// It is only meant to be called in two places, for typeck
-    /// (via `Inherited::build`) and for the inference context used
-    /// in mir borrowck.
-    pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self {
-        self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor);
-        self
-    }
-
     pub fn with_next_trait_solver(mut self, next_trait_solver: bool) -> Self {
         self.next_trait_solver = next_trait_solver;
         self
     }
 
-    pub fn intercrate(mut self, intercrate: bool) -> Self {
-        self.intercrate = intercrate;
-        self
-    }
-
     pub fn ignoring_regions(mut self) -> Self {
         self.considering_regions = false;
         self
@@ -600,24 +561,17 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     where
         T: TypeFoldable<TyCtxt<'tcx>>,
     {
-        self.defining_opaque_types = input.defining_opaque_types;
-        let infcx = self.build();
+        let infcx = self.build(input.typing_mode);
         let (value, args) = infcx.instantiate_canonical(span, &input.canonical);
         (infcx, value, args)
     }
 
-    pub fn build(&mut self) -> InferCtxt<'tcx> {
-        let InferCtxtBuilder {
-            tcx,
-            defining_opaque_types,
-            considering_regions,
-            skip_leak_check,
-            intercrate,
-            next_trait_solver,
-        } = *self;
+    pub fn build(&mut self, typing_mode: TypingMode<'tcx>) -> InferCtxt<'tcx> {
+        let InferCtxtBuilder { tcx, considering_regions, skip_leak_check, next_trait_solver } =
+            *self;
         InferCtxt {
             tcx,
-            defining_opaque_types,
+            typing_mode,
             considering_regions,
             skip_leak_check,
             inner: RefCell::new(InferCtxtInner::new()),
@@ -628,7 +582,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             reported_signature_mismatch: Default::default(),
             tainted_by_errors: Cell::new(None),
             universe: Cell::new(ty::UniverseIndex::ROOT),
-            intercrate,
             next_trait_solver,
             obligation_inspector: Cell::new(None),
         }
@@ -659,14 +612,30 @@ impl<'tcx> InferCtxt<'tcx> {
         self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
     }
 
-    pub fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
-        self.defining_opaque_types
-    }
-
     pub fn next_trait_solver(&self) -> bool {
         self.next_trait_solver
     }
 
+    #[inline(always)]
+    pub fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: ty::ParamEnv<'tcx>,
+    ) -> TypingMode<'tcx> {
+        if cfg!(debug_assertions) {
+            match (param_env_for_debug_assertion.reveal(), self.typing_mode) {
+                (Reveal::All, TypingMode::PostAnalysis)
+                | (Reveal::UserFacing, TypingMode::Coherence | TypingMode::Analysis { .. }) => {}
+                (r, t) => unreachable!("TypingMode x Reveal mismatch: {r:?} {t:?}"),
+            }
+        }
+        self.typing_mode
+    }
+
+    #[inline(always)]
+    pub fn typing_mode_unchecked(&self) -> TypingMode<'tcx> {
+        self.typing_mode
+    }
+
     pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
         t.fold_with(&mut self.freshener())
     }
@@ -1029,8 +998,12 @@ impl<'tcx> InferCtxt<'tcx> {
 
     #[inline(always)]
     pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
-        let Some(id) = id.into().as_local() else { return false };
-        self.defining_opaque_types.contains(&id)
+        match self.typing_mode_unchecked() {
+            TypingMode::Analysis { defining_opaque_types } => {
+                id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
+            }
+            TypingMode::Coherence | TypingMode::PostAnalysis => false,
+        }
     }
 
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index 853ae6d2641..498d25aea64 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -2,6 +2,7 @@ use hir::def_id::{DefId, LocalDefId};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::Goal;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -100,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
                 let def_id = def_id.expect_local();
-                if self.intercrate {
+                if let ty::TypingMode::Coherence = self.typing_mode(param_env) {
                     // See comment on `insert_hidden_type` for why this is sufficient in coherence
                     return Some(self.register_hidden_type(
                         OpaqueTypeKey { def_id, args },
@@ -364,7 +365,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     span,
                     concrete_ty,
                     r,
-                    choice_regions.clone(),
+                    Lrc::clone(&choice_regions),
                 )
             },
         });
@@ -519,28 +520,32 @@ impl<'tcx> InferCtxt<'tcx> {
         // value being folded. In simple cases like `-> impl Foo`,
         // these are the same span, but not in cases like `-> (impl
         // Foo, impl Bar)`.
-        if self.intercrate {
-            // During intercrate we do not define opaque types but instead always
-            // force ambiguity unless the hidden type is known to not implement
-            // our trait.
-            goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous))
-        } else {
-            let prev = self
-                .inner
-                .borrow_mut()
-                .opaque_types()
-                .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
-            if let Some(prev) = prev {
-                goals.extend(
-                    self.at(&ObligationCause::dummy_with_span(span), param_env)
-                        .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
-                        .obligations
-                        .into_iter()
-                        // FIXME: Shuttling between obligations and goals is awkward.
-                        .map(Goal::from),
-                );
+        match self.typing_mode(param_env) {
+            ty::TypingMode::Coherence => {
+                // During intercrate we do not define opaque types but instead always
+                // force ambiguity unless the hidden type is known to not implement
+                // our trait.
+                goals.push(Goal::new(self.tcx, param_env, ty::PredicateKind::Ambiguous));
             }
-        };
+            ty::TypingMode::Analysis { .. } => {
+                let prev = self
+                    .inner
+                    .borrow_mut()
+                    .opaque_types()
+                    .register(opaque_type_key, OpaqueHiddenType { ty: hidden_ty, span });
+                if let Some(prev) = prev {
+                    goals.extend(
+                        self.at(&ObligationCause::dummy_with_span(span), param_env)
+                            .eq(DefineOpaqueTypes::Yes, prev, hidden_ty)?
+                            .obligations
+                            .into_iter()
+                            // FIXME: Shuttling between obligations and goals is awkward.
+                            .map(Goal::from),
+                    );
+                }
+            }
+            ty::TypingMode::PostAnalysis => bug!("insert hidden type post-analysis"),
+        }
 
         Ok(())
     }
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index 32817dbcb21..4c80bf4e07e 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -9,6 +9,7 @@ use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::visit::MaxUniverse;
 use rustc_middle::ty::{
     self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt,
+    TypingMode,
 };
 use rustc_span::Span;
 use tracing::{debug, instrument, warn};
@@ -519,7 +520,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
                             //
                             // cc trait-system-refactor-initiative#108
                             if self.infcx.next_trait_solver()
-                                && !self.infcx.intercrate
+                                && !matches!(
+                                    self.infcx.typing_mode_unchecked(),
+                                    TypingMode::Coherence
+                                )
                                 && self.in_alias
                             {
                                 inner.type_variables().equate(vid, new_var_id);
@@ -650,7 +654,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
                             // See the comment for type inference variables
                             // for more details.
                             if self.infcx.next_trait_solver()
-                                && !self.infcx.intercrate
+                                && !matches!(
+                                    self.infcx.typing_mode_unchecked(),
+                                    TypingMode::Coherence
+                                )
                                 && self.in_alias
                             {
                                 variable_table.union(vid, new_var_id);
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 3a1833452d4..b6837ec764f 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -142,7 +142,7 @@ impl Linker {
 
         Ok(Linker {
             dep_graph: tcx.dep_graph.clone(),
-            output_filenames: tcx.output_filenames(()).clone(),
+            output_filenames: Arc::clone(tcx.output_filenames(())),
             crate_hash: if tcx.needs_crate_hash() {
                 Some(tcx.crate_hash(LOCAL_CRATE))
             } else {
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 232d4c18fa4..dd7b40d0a32 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index c4d709aa1f9..3fa43296dfc 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -203,14 +203,14 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i
     .current_use = this identifier can be confused with `{$existing_sym}`
     .other_use = other identifier used here
 
-lint_cstring_ptr = getting the inner pointer of a temporary `CString`
-    .as_ptr_label = this pointer will be invalid
-    .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-    .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-    .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
-
 lint_custom_inner_attribute_unstable = custom inner attributes are unstable
 
+lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped
+    .label_ptr = this pointer will immediately be invalid
+    .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+    .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+    .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 3ee4980a948..77682ea9341 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -4,21 +4,14 @@
 //! AST visitor. Also see `rustc_session::lint::builtin`, which contains the
 //! definitions of lints that are emitted directly inside the main compiler.
 //!
-//! To add a new lint to rustc, declare it here using `declare_lint!()`.
+//! To add a new lint to rustc, declare it here using [`declare_lint!`].
 //! Then add code to emit the new lint in the appropriate circumstances.
-//! You can do that in an existing `LintPass` if it makes sense, or in a
-//! new `LintPass`, or using `Session::add_lint` elsewhere in the
-//! compiler. Only do the latter if the check can't be written cleanly as a
-//! `LintPass` (also, note that such lints will need to be defined in
-//! `rustc_session::lint::builtin`, not here).
 //!
-//! If you define a new `EarlyLintPass`, you will also need to add it to the
-//! `add_early_builtin!` or `add_early_builtin_with_new!` invocation in
-//! `lib.rs`. Use the former for unit-like structs and the latter for structs
-//! with a `pub fn new()`.
+//! If you define a new [`EarlyLintPass`], you will also need to add it to the
+//! [`crate::early_lint_methods!`] invocation in `lib.rs`.
 //!
-//! If you define a new `LateLintPass`, you will also need to add it to the
-//! `late_lint_methods!` invocation in `lib.rs`.
+//! If you define a new [`LateLintPass`], you will also need to add it to the
+//! [`crate::late_lint_methods!`] invocation in `lib.rs`.
 
 use std::fmt::Write;
 
@@ -38,7 +31,7 @@ use rustc_middle::bug;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, Upcast, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, VariantDef};
 use rustc_session::lint::FutureIncompatibilityReason;
 // hardwired lints from rustc_lint_defs
 pub use rustc_session::lint::builtin::*;
@@ -611,7 +604,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
             && cx
                 .tcx
                 .infer_ctxt()
-                .build()
+                .build(cx.typing_mode())
                 .type_implements_trait(iter_trait, [ty], cx.param_env)
                 .must_apply_modulo_regions()
         {
@@ -655,7 +648,9 @@ fn type_implements_negative_copy_modulo_regions<'tcx>(
         predicate: pred.upcast(tcx),
     };
 
-    tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+    tcx.infer_ctxt()
+        .build(TypingMode::non_body_analysis())
+        .predicate_must_hold_modulo_regions(&obligation)
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 39f90a8e9ed..aa7ec2659d0 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Basic types for managing and implementing lints.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
 
 use std::cell::Cell;
 use std::{iter, slice};
@@ -22,15 +11,15 @@ use rustc_data_structures::sync;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
 use rustc_feature::Features;
-use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_infer::traits::Reveal;
 use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
-use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingMode};
 use rustc_session::lint::{
     BuiltinLintDiag, FutureIncompatibleInfo, Level, Lint, LintBuffer, LintExpectationId, LintId,
 };
@@ -38,8 +27,8 @@ use rustc_session::{LintStoreMarker, Session};
 use rustc_span::Span;
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::symbol::{Ident, Symbol, sym};
-use rustc_target::abi;
 use tracing::debug;
+use {rustc_abi as abi, rustc_hir as hir};
 
 use self::TargetLint::*;
 use crate::levels::LintLevelsBuilder;
@@ -52,9 +41,6 @@ type LateLintPassFactory =
     dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
 
 /// Information about the registered lints.
-///
-/// This is basically the subset of `Context` that we can
-/// build early in the compile pipeline.
 pub struct LintStore {
     /// Registered lints.
     lints: Vec<&'static Lint>,
@@ -713,6 +699,15 @@ impl LintContext for EarlyContext<'_> {
 }
 
 impl<'tcx> LateContext<'tcx> {
+    /// The typing mode of the currently visited node. Use this when
+    /// building a new `InferCtxt`.
+    pub fn typing_mode(&self) -> TypingMode<'tcx> {
+        debug_assert_eq!(self.param_env.reveal(), Reveal::UserFacing);
+        // FIXME(#132279): In case we're in a body, we should use a typing
+        // mode which reveals the opaque types defined by that body.
+        TypingMode::non_body_analysis()
+    }
+
     /// Gets the type-checking results for the current body,
     /// or `None` if outside a body.
     pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> {
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
new file mode 100644
index 00000000000..a34c3e26778
--- /dev/null
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -0,0 +1,223 @@
+use rustc_ast::visit::{visit_opt, walk_list};
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
+use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
+use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_session::{declare_lint, impl_lint_pass};
+use rustc_span::Span;
+use rustc_span::symbol::sym;
+
+use crate::lints::DanglingPointersFromTemporaries;
+use crate::{LateContext, LateLintPass};
+
+declare_lint! {
+    /// The `dangling_pointers_from_temporaries` lint detects getting a pointer to data
+    /// of a temporary that will immediately get dropped.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// # unsafe fn use_data(ptr: *const u8) { }
+    /// fn gather_and_use(bytes: impl Iterator<Item = u8>) {
+    ///     let x: *const u8 = bytes.collect::<Vec<u8>>().as_ptr();
+    ///     unsafe { use_data(x) }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Getting a pointer from a temporary value will not prolong its lifetime,
+    /// which means that the value can be dropped and the allocation freed
+    /// while the pointer still exists, making the pointer dangling.
+    /// This is not an error (as far as the type system is concerned)
+    /// but probably is not what the user intended either.
+    ///
+    /// If you need stronger guarantees, consider using references instead,
+    /// as they are statically verified by the borrow-checker to never dangle.
+    pub DANGLING_POINTERS_FROM_TEMPORARIES,
+    Warn,
+    "detects getting a pointer from a temporary"
+}
+
+/// FIXME: false negatives (i.e. the lint is not emitted when it should be)
+/// 1. Method calls that are not checked for:
+///    - [`temporary_unsafe_cell.get()`][`core::cell::UnsafeCell::get()`]
+///    - [`temporary_sync_unsafe_cell.get()`][`core::cell::SyncUnsafeCell::get()`]
+/// 2. Ways to get a temporary that are not recognized:
+///    - `owning_temporary.field`
+///    - `owning_temporary[index]`
+/// 3. No checks for ref-to-ptr conversions:
+///    - `&raw [mut] temporary`
+///    - `&temporary as *(const|mut) _`
+///    - `ptr::from_ref(&temporary)` and friends
+#[derive(Clone, Copy, Default)]
+pub(crate) struct DanglingPointers;
+
+impl_lint_pass!(DanglingPointers => [DANGLING_POINTERS_FROM_TEMPORARIES]);
+
+// This skips over const blocks, but they cannot use or return a dangling pointer anyways.
+impl<'tcx> LateLintPass<'tcx> for DanglingPointers {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        body: &'tcx Body<'tcx>,
+        _: Span,
+        _: LocalDefId,
+    ) {
+        DanglingPointerSearcher { cx, inside_call_args: false }.visit_body(body)
+    }
+}
+
+/// This produces a dangling pointer:
+/// ```ignore (example)
+/// let ptr = CString::new("hello").unwrap().as_ptr();
+/// foo(ptr)
+/// ```
+///
+/// But this does not:
+/// ```ignore (example)
+/// foo(CString::new("hello").unwrap().as_ptr())
+/// ```
+///
+/// But this does:
+/// ```ignore (example)
+/// foo({ let ptr = CString::new("hello").unwrap().as_ptr(); ptr })
+/// ```
+///
+/// So we have to keep track of when we are inside of a function/method call argument.
+struct DanglingPointerSearcher<'lcx, 'tcx> {
+    cx: &'lcx LateContext<'tcx>,
+    /// Keeps track of whether we are inside of function/method call arguments,
+    /// where this lint should not be emitted.
+    ///
+    /// See [the main doc][`Self`] for examples.
+    inside_call_args: bool,
+}
+
+impl Visitor<'_> for DanglingPointerSearcher<'_, '_> {
+    fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
+        if !self.inside_call_args {
+            lint_expr(self.cx, expr)
+        }
+        match expr.kind {
+            ExprKind::Call(lhs, args) | ExprKind::MethodCall(_, lhs, args, _) => {
+                self.visit_expr(lhs);
+                self.with_inside_call_args(true, |this| walk_list!(this, visit_expr, args))
+            }
+            ExprKind::Block(&Block { stmts, expr, .. }, _) => {
+                self.with_inside_call_args(false, |this| walk_list!(this, visit_stmt, stmts));
+                visit_opt!(self, visit_expr, expr)
+            }
+            _ => walk_expr(self, expr),
+        }
+    }
+}
+
+impl DanglingPointerSearcher<'_, '_> {
+    fn with_inside_call_args<R>(
+        &mut self,
+        inside_call_args: bool,
+        callback: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        let old = core::mem::replace(&mut self.inside_call_args, inside_call_args);
+        let result = callback(self);
+        self.inside_call_args = old;
+        result
+    }
+}
+
+fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    if let ExprKind::MethodCall(method, receiver, _args, _span) = expr.kind
+        && matches!(method.ident.name, sym::as_ptr | sym::as_mut_ptr)
+        && is_temporary_rvalue(receiver)
+        && let ty = cx.typeck_results().expr_ty(receiver)
+        && is_interesting(cx.tcx, ty)
+    {
+        // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
+        cx.tcx.emit_node_span_lint(
+            DANGLING_POINTERS_FROM_TEMPORARIES,
+            expr.hir_id,
+            method.ident.span,
+            DanglingPointersFromTemporaries {
+                callee: method.ident.name,
+                ty,
+                ptr_span: method.ident.span,
+                temporary_span: receiver.span,
+            },
+        )
+    }
+}
+
+fn is_temporary_rvalue(expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        // Const is not temporary.
+        ExprKind::ConstBlock(..) | ExprKind::Repeat(..) | ExprKind::Lit(..) => false,
+
+        // This is literally lvalue.
+        ExprKind::Path(..) => false,
+
+        // Calls return rvalues.
+        ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true,
+
+        // Inner blocks are rvalues.
+        ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true,
+
+        // FIXME: these should probably recurse and typecheck along the way.
+        //        Some false negatives are possible for now.
+        ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(..) => false,
+
+        ExprKind::Struct(..) => true,
+
+        // FIXME: this has false negatives, but I do not want to deal with 'static/const promotion just yet.
+        ExprKind::Array(..) => false,
+
+        // These typecheck to `!`
+        ExprKind::Break(..) | ExprKind::Continue(..) | ExprKind::Ret(..) | ExprKind::Become(..) => {
+            false
+        }
+
+        // These typecheck to `()`
+        ExprKind::Assign(..) | ExprKind::AssignOp(..) | ExprKind::Yield(..) => false,
+
+        // Compiler-magic macros
+        ExprKind::AddrOf(..) | ExprKind::OffsetOf(..) | ExprKind::InlineAsm(..) => false,
+
+        // We are not interested in these
+        ExprKind::Cast(..)
+        | ExprKind::Closure(..)
+        | ExprKind::Tup(..)
+        | ExprKind::DropTemps(..)
+        | ExprKind::Let(..) => false,
+
+        // Not applicable
+        ExprKind::Type(..) | ExprKind::Err(..) => false,
+    }
+}
+
+// Array, Vec, String, CString, MaybeUninit, Cell, Box<[_]>, Box<str>, Box<CStr>,
+// or any of the above in arbitrary many nested Box'es.
+fn is_interesting(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+    if ty.is_array() {
+        true
+    } else if let Some(inner) = ty.boxed_ty() {
+        inner.is_slice()
+            || inner.is_str()
+            || inner.ty_adt_def().is_some_and(|def| tcx.is_lang_item(def.did(), LangItem::CStr))
+            || is_interesting(tcx, inner)
+    } else if let Some(def) = ty.ty_adt_def() {
+        for lang_item in [LangItem::String, LangItem::MaybeUninit] {
+            if tcx.is_lang_item(def.did(), lang_item) {
+                return true;
+            }
+        }
+        tcx.get_diagnostic_name(def.did())
+            .is_some_and(|name| matches!(name, sym::cstring_type | sym::Vec | sym::Cell))
+    } else {
+        false
+    }
+}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index e2247d3a1f6..acccff77a10 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -1,18 +1,8 @@
-//! Implementation of lint checking.
+//! Implementation of the early lint pass.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The early lint pass works on AST nodes after macro expansion and name
+//! resolution, just before AST lowering. These lints are for purely
+//! syntactical lints.
 
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, Visitor, walk_list};
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index fcb7a6108c0..cf68e41243f 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -166,7 +166,7 @@ fn suggest_question_mark<'tcx>(
     }
 
     let ty = args.type_at(0);
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     let ocx = ObligationCtxt::new(&infcx);
 
     let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 816882962be..abe4e3e78ee 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -1,3 +1,4 @@
+use rustc_abi::FIRST_VARIANT;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_hir as hir;
@@ -6,7 +7,6 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
 use rustc_session::declare_lint;
 use rustc_span::{Span, Symbol, sym};
-use rustc_target::abi::FIRST_VARIANT;
 use tracing::{debug, instrument};
 
 use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub};
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index bdfcc2c0a10..afcfbebc14b 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -24,7 +24,6 @@ declare_lint! {
     /// ### Example
     ///
     /// ```rust,edition2021
-    /// #![feature(if_let_rescope)]
     /// #![warn(if_let_rescope)]
     /// #![allow(unused_variables)]
     ///
@@ -243,7 +242,7 @@ impl_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if expr.span.edition().at_least_rust_2024() || !cx.tcx.features().if_let_rescope() {
+        if expr.span.edition().at_least_rust_2024() {
             return;
         }
         if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) {
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
index cc40b67ab27..026826021c8 100644
--- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::relate::{
     Relate, RelateResult, TypeRelation, structurally_relate_consts, structurally_relate_tys,
 };
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::FutureIncompatibilityReason;
@@ -184,7 +184,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
         }),
         outlives_env: LazyCell::new(|| {
             let param_env = tcx.param_env(parent_def_id);
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
             let ocx = ObligationCtxt::new(&infcx);
             let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
             let implied_bounds =
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 9b1877599ba..9d35ce19b57 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -1,18 +1,7 @@
-//! Implementation of lint checking.
+//! Implementation of the late lint pass.
 //!
-//! The lint checking is mostly consolidated into one pass which runs
-//! after all other analyses. Throughout compilation, lint warnings
-//! can be added via the `add_lint` method on the Session structure. This
-//! requires a span and an ID of the node that the lint is being added to. The
-//! lint isn't actually emitted at that time because it is unknown what the
-//! actual lint level at that location is.
-//!
-//! To actually emit lint warnings/errors, a separate pass is used.
-//! A context keeps track of the current state of all lint levels.
-//! Upon entering a node of the ast which can modify the lint settings, the
-//! previous lint state is pushed onto a stack and the ast is then recursed
-//! upon. As the ast is traversed, this keeps track of the current lint level
-//! for all lint attributes.
+//! The late lint pass Works on HIR nodes, towards the end of analysis (after
+//! borrow checking, etc.). These lints have full type information available.
 
 use std::any::Any;
 use std::cell::Cell;
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 5389860e23b..86112277504 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -6,20 +6,14 @@
 //! other phases of the compiler, which are generally required to hold in order
 //! to compile the program at all.
 //!
-//! Most lints can be written as [LintPass] instances. These run after
+//! Most lints can be written as [`LintPass`] instances. These run after
 //! all other analyses. The `LintPass`es built into rustc are defined
 //! within [rustc_session::lint::builtin],
 //! which has further comments on how to add such a lint.
 //! rustc can also load external lint plugins, as is done for Clippy.
 //!
-//! Some of rustc's lints are defined elsewhere in the compiler and work by
-//! calling `add_lint()` on the overall `Session` object. This works when
-//! it happens before the main lint pass, which emits the lints stored by
-//! `add_lint()`. To emit lints after the main lint pass (from codegen, for
-//! example) requires more effort. See `emit_lint` and `GatherNodeLevels`
-//! in `context.rs`.
-//!
-//! Some code also exists in [rustc_session::lint], [rustc_middle::lint].
+//! See <https://rustc-dev-guide.rust-lang.org/diagnostics.html> for an
+//! overview of how lints are implemented.
 //!
 //! ## Note
 //!
@@ -46,6 +40,7 @@ mod async_closures;
 mod async_fn_in_trait;
 pub mod builtin;
 mod context;
+mod dangling;
 mod deref_into_dyn_supertrait;
 mod drop_forget_useless;
 mod early;
@@ -65,7 +60,6 @@ mod levels;
 mod lints;
 mod macro_expr_fragment_specifier_2024_migration;
 mod map_unit_fn;
-mod methods;
 mod multiple_supertrait_upcastable;
 mod non_ascii_idents;
 mod non_fmt_panic;
@@ -91,6 +85,7 @@ mod unused;
 use async_closures::AsyncClosureUsage;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
+use dangling::*;
 use deref_into_dyn_supertrait::*;
 use drop_forget_useless::*;
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
@@ -103,7 +98,6 @@ use invalid_from_utf8::*;
 use let_underscore::*;
 use macro_expr_fragment_specifier_2024_migration::*;
 use map_unit_fn::*;
-use methods::*;
 use multiple_supertrait_upcastable::*;
 use non_ascii_idents::*;
 use non_fmt_panic::NonPanicFmt;
@@ -231,7 +225,7 @@ late_lint_methods!(
             UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
             ShadowedIntoIter: ShadowedIntoIter,
             DropTraitConstraints: DropTraitConstraints,
-            TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+            DanglingPointers: DanglingPointers,
             NonPanicFmt: NonPanicFmt,
             NoopMethodCall: NoopMethodCall,
             EnumIntrinsicsNonEnums: EnumIntrinsicsNonEnums,
@@ -356,6 +350,7 @@ fn register_builtins(store: &mut LintStore) {
     store.register_renamed("non_fmt_panic", "non_fmt_panics");
     store.register_renamed("unused_tuple_struct_fields", "dead_code");
     store.register_renamed("static_mut_ref", "static_mut_refs");
+    store.register_renamed("temporary_cstring_as_ptr", "dangling_pointers_from_temporaries");
 
     // These were moved to tool lints, but rustc still sees them when compiling normally, before
     // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 16cfae17d40..000f4b697bd 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1137,16 +1137,19 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> {
     pub name: Symbol,
 }
 
-// methods.rs
+// dangling.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_cstring_ptr)]
+#[diag(lint_dangling_pointers_from_temporaries)]
 #[note]
 #[help]
-pub(crate) struct CStringPtr {
-    #[label(lint_as_ptr_label)]
-    pub as_ptr: Span,
-    #[label(lint_unwrap_label)]
-    pub unwrap: Span,
+// FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts
+pub(crate) struct DanglingPointersFromTemporaries<'tcx> {
+    pub callee: Symbol,
+    pub ty: Ty<'tcx>,
+    #[label(lint_label_ptr)]
+    pub ptr_span: Span,
+    #[label(lint_label_temporary)]
+    pub temporary_span: Span,
 }
 
 // multiple_supertrait_upcastable.rs
diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs
deleted file mode 100644
index df22bf0972d..00000000000
--- a/compiler/rustc_lint/src/methods.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use rustc_hir::{Expr, ExprKind};
-use rustc_middle::ty;
-use rustc_session::{declare_lint, declare_lint_pass};
-use rustc_span::Span;
-use rustc_span::symbol::sym;
-
-use crate::lints::CStringPtr;
-use crate::{LateContext, LateLintPass, LintContext};
-
-declare_lint! {
-    /// The `temporary_cstring_as_ptr` lint detects getting the inner pointer of
-    /// a temporary `CString`.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// # #![allow(unused)]
-    /// # use std::ffi::CString;
-    /// let c_str = CString::new("foo").unwrap().as_ptr();
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The inner pointer of a `CString` lives only as long as the `CString` it
-    /// points to. Getting the inner pointer of a *temporary* `CString` allows the `CString`
-    /// to be dropped at the end of the statement, as it is not being referenced as far as the
-    /// typesystem is concerned. This means outside of the statement the pointer will point to
-    /// freed memory, which causes undefined behavior if the pointer is later dereferenced.
-    pub TEMPORARY_CSTRING_AS_PTR,
-    Warn,
-    "detects getting the inner pointer of a temporary `CString`"
-}
-
-declare_lint_pass!(TemporaryCStringAsPtr => [TEMPORARY_CSTRING_AS_PTR]);
-
-impl<'tcx> LateLintPass<'tcx> for TemporaryCStringAsPtr {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::MethodCall(as_ptr_path, as_ptr_receiver, ..) = expr.kind
-            && as_ptr_path.ident.name == sym::as_ptr
-            && let ExprKind::MethodCall(unwrap_path, unwrap_receiver, ..) = as_ptr_receiver.kind
-            && (unwrap_path.ident.name == sym::unwrap || unwrap_path.ident.name == sym::expect)
-        {
-            lint_cstring_as_ptr(cx, as_ptr_path.ident.span, unwrap_receiver, as_ptr_receiver);
-        }
-    }
-}
-
-fn lint_cstring_as_ptr(
-    cx: &LateContext<'_>,
-    as_ptr_span: Span,
-    source: &rustc_hir::Expr<'_>,
-    unwrap: &rustc_hir::Expr<'_>,
-) {
-    let source_type = cx.typeck_results().expr_ty(source);
-    if let ty::Adt(def, args) = source_type.kind() {
-        if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
-            if let ty::Adt(adt, _) = args.type_at(0).kind() {
-                if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
-                    cx.emit_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, CStringPtr {
-                        as_ptr: as_ptr_span,
-                        unwrap: unwrap.span,
-                    });
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 51877e8a034..cf25ec99e67 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -157,7 +157,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 Some(ty_def) if cx.tcx.is_lang_item(ty_def.did(), LangItem::String),
             );
 
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             let suggest_display = is_str
                 || cx.tcx.get_diagnostic_item(sym::Display).is_some_and(|t| {
                     infcx.type_implements_trait(t, [ty], cx.param_env).may_apply()
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index ffbcf7f808e..5de0d4bc870 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -69,7 +69,7 @@ declare_lint_pass!(OpaqueHiddenInferredBound => [OPAQUE_HIDDEN_INFERRED_BOUND]);
 
 impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx hir::Ty<'tcx>) {
-        let hir::TyKind::OpaqueDef(opaque, _) = &ty.kind else {
+        let hir::TyKind::OpaqueDef(opaque) = &ty.kind else {
             return;
         };
 
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
         }
 
         let def_id = opaque.def_id.to_def_id();
-        let infcx = &cx.tcx.infer_ctxt().build();
+        let infcx = &cx.tcx.infer_ctxt().build(cx.typing_mode());
         // For every projection predicate in the opaque type's explicit bounds,
         // check that the type that we're assigning actually satisfies the bounds
         // of the associated type.
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index d1e850990dc..dca42fea57d 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -1,8 +1,8 @@
 use hir::{ExprKind, Node, is_range_literal};
+use rustc_abi::{Integer, Size};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::{bug, ty};
-use rustc_target::abi::{Integer, Size};
 use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
 
 use crate::LateContext;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 4b303511dbc..3e906f89c15 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1251,12 +1251,12 @@ getFirstDefinitionForLinker(const GlobalValueSummaryList &GVSummaryList) {
 // here is basically the same as before threads are spawned in the `run`
 // function of `lib/LTO/ThinLTOCodeGenerator.cpp`.
 extern "C" LLVMRustThinLTOData *
-LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules,
-                          const char **preserved_symbols, int num_symbols) {
+LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, size_t num_modules,
+                          const char **preserved_symbols, size_t num_symbols) {
   auto Ret = std::make_unique<LLVMRustThinLTOData>();
 
   // Load each module's summary and merge it into one combined index
-  for (int i = 0; i < num_modules; i++) {
+  for (size_t i = 0; i < num_modules; i++) {
     auto module = &modules[i];
     auto buffer = StringRef(module->data, module->len);
     auto mem_buffer = MemoryBufferRef(buffer, module->identifier);
@@ -1275,7 +1275,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, int num_modules,
 
   // Convert the preserved symbols set from string to GUID, this is then needed
   // for internalization.
-  for (int i = 0; i < num_symbols; i++) {
+  for (size_t i = 0; i < num_symbols; i++) {
     auto GUID = GlobalValue::getGUID(preserved_symbols[i]);
     Ret->GUIDPreservedSymbols.insert(GUID);
   }
@@ -1559,8 +1559,10 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
 extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
                                                             size_t len,
                                                             const char *name,
+                                                            size_t name_len,
                                                             size_t *out_len) {
   *out_len = 0;
+  auto Name = StringRef(name, name_len);
   auto Data = StringRef(data, len);
   auto Buffer = MemoryBufferRef(Data, ""); // The id is unused.
   file_magic Type = identify_magic(Buffer.getBuffer());
@@ -1571,8 +1573,8 @@ extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
     return nullptr;
   }
   for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
-    Expected<StringRef> Name = Sec.getName();
-    if (Name && *Name == name) {
+    Expected<StringRef> SecName = Sec.getName();
+    if (SecName && *SecName == Name) {
       Expected<StringRef> SectionOrError = Sec.getContents();
       if (!SectionOrError) {
         LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index cb75888abd7..645b4082be5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -853,25 +853,63 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
 
 extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
 
-extern "C" void LLVMRustAddModuleFlagU32(LLVMModuleRef M,
-                                         Module::ModFlagBehavior MergeBehavior,
-                                         const char *Name, uint32_t Value) {
-  unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
+// FFI equivalent of LLVM's `llvm::Module::ModFlagBehavior`.
+// Must match the layout of
+// `rustc_codegen_llvm::llvm::ffi::ModuleFlagMergeBehavior`.
+//
+// There is a stable LLVM-C version of this enum (`LLVMModuleFlagBehavior`),
+// but as of LLVM 19 it does not support all of the enum values in the unstable
+// C++ API.
+enum class LLVMRustModuleFlagMergeBehavior {
+  Error = 1,
+  Warning = 2,
+  Require = 3,
+  Override = 4,
+  Append = 5,
+  AppendUnique = 6,
+  Max = 7,
+  Min = 8,
+};
+
+static Module::ModFlagBehavior
+fromRust(LLVMRustModuleFlagMergeBehavior Behavior) {
+  switch (Behavior) {
+  case LLVMRustModuleFlagMergeBehavior::Error:
+    return Module::ModFlagBehavior::Error;
+  case LLVMRustModuleFlagMergeBehavior::Warning:
+    return Module::ModFlagBehavior::Warning;
+  case LLVMRustModuleFlagMergeBehavior::Require:
+    return Module::ModFlagBehavior::Require;
+  case LLVMRustModuleFlagMergeBehavior::Override:
+    return Module::ModFlagBehavior::Override;
+  case LLVMRustModuleFlagMergeBehavior::Append:
+    return Module::ModFlagBehavior::Append;
+  case LLVMRustModuleFlagMergeBehavior::AppendUnique:
+    return Module::ModFlagBehavior::AppendUnique;
+  case LLVMRustModuleFlagMergeBehavior::Max:
+    return Module::ModFlagBehavior::Max;
+  case LLVMRustModuleFlagMergeBehavior::Min:
+    return Module::ModFlagBehavior::Min;
+  }
+  report_fatal_error("bad LLVMRustModuleFlagMergeBehavior");
+}
+
+extern "C" void
+LLVMRustAddModuleFlagU32(LLVMModuleRef M,
+                         LLVMRustModuleFlagMergeBehavior MergeBehavior,
+                         const char *Name, size_t NameLen, uint32_t Value) {
+  unwrap(M)->addModuleFlag(fromRust(MergeBehavior), StringRef(Name, NameLen),
+                           Value);
 }
 
 extern "C" void LLVMRustAddModuleFlagString(
-    LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name,
-    const char *Value, size_t ValueLen) {
+    LLVMModuleRef M, LLVMRustModuleFlagMergeBehavior MergeBehavior,
+    const char *Name, size_t NameLen, const char *Value, size_t ValueLen) {
   unwrap(M)->addModuleFlag(
-      MergeBehavior, Name,
+      fromRust(MergeBehavior), StringRef(Name, NameLen),
       MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen)));
 }
 
-extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name,
-                                      size_t Len) {
-  return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr;
-}
-
 extern "C" void LLVMRustGlobalAddMetadata(LLVMValueRef Global, unsigned Kind,
                                           LLVMMetadataRef MD) {
   unwrap<GlobalObject>(Global)->addMetadata(Kind, *unwrap<MDNode>(MD));
@@ -1231,7 +1269,7 @@ extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
   return dwarf::DW_OP_plus_uconst;
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpLLVMFragment() {
   return dwarf::DW_OP_LLVM_fragment;
 }
 
@@ -1499,38 +1537,6 @@ LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef, RustStringRef MessageOut,
   return true;
 }
 
-extern "C" OperandBundleDef *LLVMRustBuildOperandBundleDef(const char *Name,
-                                                           LLVMValueRef *Inputs,
-                                                           unsigned NumInputs) {
-  return new OperandBundleDef(Name,
-                              ArrayRef<Value *>(unwrap(Inputs), NumInputs));
-}
-
-extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
-  delete Bundle;
-}
-
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
-extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty,
-                                          LLVMValueRef Fn, LLVMValueRef *Args,
-                                          unsigned NumArgs,
-                                          OperandBundleDef **OpBundlesIndirect,
-                                          unsigned NumOpBundles) {
-  Value *Callee = unwrap(Fn);
-  FunctionType *FTy = unwrap<FunctionType>(Ty);
-
-  // FIXME: Is there a way around this?
-  SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
-  }
-
-  return wrap(unwrap(B)->CreateCall(FTy, Callee,
-                                    ArrayRef<Value *>(unwrap(Args), NumArgs),
-                                    ArrayRef<OperandBundleDef>(OpBundles)));
-}
-
 extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
                                             unsigned DstAlign, LLVMValueRef Src,
                                             unsigned SrcAlign,
@@ -1558,37 +1564,18 @@ extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B, LLVMValueRef Dst,
                                       MaybeAlign(DstAlign), IsVolatile));
 }
 
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
-extern "C" LLVMValueRef
-LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
-                    LLVMValueRef *Args, unsigned NumArgs,
-                    LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
-                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
-                    const char *Name) {
-  Value *Callee = unwrap(Fn);
-  FunctionType *FTy = unwrap<FunctionType>(Ty);
-
-  // FIXME: Is there a way around this?
-  SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
-  }
-
-  return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
-                                      ArrayRef<Value *>(unwrap(Args), NumArgs),
-                                      ArrayRef<OperandBundleDef>(OpBundles),
-                                      Name));
-}
+// Polyfill for `LLVMBuildCallBr`, which was added in LLVM 19.
+// <https://github.com/llvm/llvm-project/commit/584253c4e2f788f870488fc32193b52d67ddaccc>
+// FIXME: Remove when Rust's minimum supported LLVM version reaches 19.
+#if LLVM_VERSION_LT(19, 0)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OperandBundleDef, LLVMOperandBundleRef)
 
-// OpBundlesIndirect is an array of pointers (*not* a pointer to an array).
 extern "C" LLVMValueRef
-LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
-                    LLVMBasicBlockRef DefaultDest,
-                    LLVMBasicBlockRef *IndirectDests, unsigned NumIndirectDests,
-                    LLVMValueRef *Args, unsigned NumArgs,
-                    OperandBundleDef **OpBundlesIndirect, unsigned NumOpBundles,
-                    const char *Name) {
+LLVMBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
+                LLVMBasicBlockRef DefaultDest, LLVMBasicBlockRef *IndirectDests,
+                unsigned NumIndirectDests, LLVMValueRef *Args, unsigned NumArgs,
+                LLVMOperandBundleRef *Bundles, unsigned NumBundles,
+                const char *Name) {
   Value *Callee = unwrap(Fn);
   FunctionType *FTy = unwrap<FunctionType>(Ty);
 
@@ -1601,9 +1588,9 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
 
   // FIXME: Is there a way around this?
   SmallVector<OperandBundleDef> OpBundles;
-  OpBundles.reserve(NumOpBundles);
-  for (unsigned i = 0; i < NumOpBundles; ++i) {
-    OpBundles.push_back(*OpBundlesIndirect[i]);
+  OpBundles.reserve(NumBundles);
+  for (unsigned i = 0; i < NumBundles; ++i) {
+    OpBundles.push_back(*unwrap(Bundles[i]));
   }
 
   return wrap(
@@ -1612,6 +1599,7 @@ LLVMRustBuildCallBr(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
                               ArrayRef<Value *>(unwrap(Args), NumArgs),
                               ArrayRef<OperandBundleDef>(OpBundles), Name));
 }
+#endif
 
 extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
                                                LLVMBasicBlockRef BB) {
@@ -1619,86 +1607,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
   unwrap(B)->SetInsertPoint(unwrap(BB), Point);
 }
 
-enum class LLVMRustLinkage {
-  ExternalLinkage = 0,
-  AvailableExternallyLinkage = 1,
-  LinkOnceAnyLinkage = 2,
-  LinkOnceODRLinkage = 3,
-  WeakAnyLinkage = 4,
-  WeakODRLinkage = 5,
-  AppendingLinkage = 6,
-  InternalLinkage = 7,
-  PrivateLinkage = 8,
-  ExternalWeakLinkage = 9,
-  CommonLinkage = 10,
-};
-
-static LLVMRustLinkage toRust(LLVMLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMExternalLinkage:
-    return LLVMRustLinkage::ExternalLinkage;
-  case LLVMAvailableExternallyLinkage:
-    return LLVMRustLinkage::AvailableExternallyLinkage;
-  case LLVMLinkOnceAnyLinkage:
-    return LLVMRustLinkage::LinkOnceAnyLinkage;
-  case LLVMLinkOnceODRLinkage:
-    return LLVMRustLinkage::LinkOnceODRLinkage;
-  case LLVMWeakAnyLinkage:
-    return LLVMRustLinkage::WeakAnyLinkage;
-  case LLVMWeakODRLinkage:
-    return LLVMRustLinkage::WeakODRLinkage;
-  case LLVMAppendingLinkage:
-    return LLVMRustLinkage::AppendingLinkage;
-  case LLVMInternalLinkage:
-    return LLVMRustLinkage::InternalLinkage;
-  case LLVMPrivateLinkage:
-    return LLVMRustLinkage::PrivateLinkage;
-  case LLVMExternalWeakLinkage:
-    return LLVMRustLinkage::ExternalWeakLinkage;
-  case LLVMCommonLinkage:
-    return LLVMRustLinkage::CommonLinkage;
-  default:
-    report_fatal_error("Invalid LLVMRustLinkage value!");
-  }
-}
-
-static LLVMLinkage fromRust(LLVMRustLinkage Linkage) {
-  switch (Linkage) {
-  case LLVMRustLinkage::ExternalLinkage:
-    return LLVMExternalLinkage;
-  case LLVMRustLinkage::AvailableExternallyLinkage:
-    return LLVMAvailableExternallyLinkage;
-  case LLVMRustLinkage::LinkOnceAnyLinkage:
-    return LLVMLinkOnceAnyLinkage;
-  case LLVMRustLinkage::LinkOnceODRLinkage:
-    return LLVMLinkOnceODRLinkage;
-  case LLVMRustLinkage::WeakAnyLinkage:
-    return LLVMWeakAnyLinkage;
-  case LLVMRustLinkage::WeakODRLinkage:
-    return LLVMWeakODRLinkage;
-  case LLVMRustLinkage::AppendingLinkage:
-    return LLVMAppendingLinkage;
-  case LLVMRustLinkage::InternalLinkage:
-    return LLVMInternalLinkage;
-  case LLVMRustLinkage::PrivateLinkage:
-    return LLVMPrivateLinkage;
-  case LLVMRustLinkage::ExternalWeakLinkage:
-    return LLVMExternalWeakLinkage;
-  case LLVMRustLinkage::CommonLinkage:
-    return LLVMCommonLinkage;
-  }
-  report_fatal_error("Invalid LLVMRustLinkage value!");
-}
-
-extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
-  return toRust(LLVMGetLinkage(V));
-}
-
-extern "C" void LLVMRustSetLinkage(LLVMValueRef V,
-                                   LLVMRustLinkage RustLinkage) {
-  LLVMSetLinkage(V, fromRust(RustLinkage));
-}
-
 extern "C" bool LLVMRustConstIntGetZExtValue(LLVMValueRef CV, uint64_t *value) {
   auto C = unwrap<llvm::ConstantInt>(CV);
   if (C->getBitWidth() > 64)
@@ -1726,45 +1634,6 @@ extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext,
   return true;
 }
 
-enum class LLVMRustVisibility {
-  Default = 0,
-  Hidden = 1,
-  Protected = 2,
-};
-
-static LLVMRustVisibility toRust(LLVMVisibility Vis) {
-  switch (Vis) {
-  case LLVMDefaultVisibility:
-    return LLVMRustVisibility::Default;
-  case LLVMHiddenVisibility:
-    return LLVMRustVisibility::Hidden;
-  case LLVMProtectedVisibility:
-    return LLVMRustVisibility::Protected;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-static LLVMVisibility fromRust(LLVMRustVisibility Vis) {
-  switch (Vis) {
-  case LLVMRustVisibility::Default:
-    return LLVMDefaultVisibility;
-  case LLVMRustVisibility::Hidden:
-    return LLVMHiddenVisibility;
-  case LLVMRustVisibility::Protected:
-    return LLVMProtectedVisibility;
-  }
-  report_fatal_error("Invalid LLVMRustVisibility value!");
-}
-
-extern "C" LLVMRustVisibility LLVMRustGetVisibility(LLVMValueRef V) {
-  return toRust(LLVMGetVisibility(V));
-}
-
-extern "C" void LLVMRustSetVisibility(LLVMValueRef V,
-                                      LLVMRustVisibility RustVisibility) {
-  LLVMSetVisibility(V, fromRust(RustVisibility));
-}
-
 extern "C" void LLVMRustSetDSOLocal(LLVMValueRef Global, bool is_dso_local) {
   unwrap<GlobalValue>(Global)->setDSOLocal(is_dso_local);
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 72f1e599247..1055f27c1e4 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -253,7 +253,10 @@ impl DiagnosticDeriveVariantBuilder {
         let mut field_binding = binding_info.binding.clone();
         field_binding.set_span(field.ty.span());
 
-        let ident = field.ident.as_ref().unwrap();
+        let Some(ident) = field.ident.as_ref() else {
+            span_err(field.span().unwrap(), "tuple structs are not supported").emit();
+            return TokenStream::new();
+        };
         let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
 
         quote! {
diff --git a/compiler/rustc_macros/src/diagnostics/error.rs b/compiler/rustc_macros/src/diagnostics/error.rs
index 9cdb9fbab12..a78cf2b63d0 100644
--- a/compiler/rustc_macros/src/diagnostics/error.rs
+++ b/compiler/rustc_macros/src/diagnostics/error.rs
@@ -56,7 +56,7 @@ fn path_to_string(path: &syn::Path) -> String {
 /// Returns an error diagnostic on span `span` with msg `msg`.
 #[must_use]
 pub(crate) fn span_err<T: Into<String>>(span: impl MultiSpan, msg: T) -> Diagnostic {
-    Diagnostic::spanned(span, Level::Error, msg)
+    Diagnostic::spanned(span, Level::Error, format!("derive(Diagnostic): {}", msg.into()))
 }
 
 /// Emit a diagnostic on span `$span` with msg `$msg` (optionally performing additional decoration
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 5946b11828e..612a36ba9aa 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -243,7 +243,7 @@ impl<T> SetOnce<T> for SpannedOption<T> {
                 *self = Some((value, span));
             }
             Some((_, prev_span)) => {
-                span_err(span, "specified multiple times")
+                span_err(span, "attribute specified multiple times")
                     .span_note(*prev_span, "previously specified here")
                     .emit();
             }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index f46c795b956..0df674eb4c9 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -20,6 +20,7 @@ mod lift;
 mod query;
 mod serialize;
 mod symbols;
+mod try_from;
 mod type_foldable;
 mod type_visitable;
 
@@ -165,3 +166,12 @@ decl_derive!(
         suggestion_part,
         applicability)] => diagnostics::subdiagnostic_derive
 );
+
+decl_derive! {
+    [TryFromU32] =>
+    /// Derives `TryFrom<u32>` for the annotated `enum`, which must have no fields.
+    /// Each variant maps to the value it would produce under an `as u32` cast.
+    ///
+    /// The error type is `u32`.
+    try_from::try_from_u32
+}
diff --git a/compiler/rustc_macros/src/try_from.rs b/compiler/rustc_macros/src/try_from.rs
new file mode 100644
index 00000000000..9338c1c2b33
--- /dev/null
+++ b/compiler/rustc_macros/src/try_from.rs
@@ -0,0 +1,55 @@
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned};
+use syn::Data;
+use syn::spanned::Spanned;
+use synstructure::Structure;
+
+pub(crate) fn try_from_u32(s: Structure<'_>) -> TokenStream {
+    let span_error = |span, message: &str| {
+        quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
+    };
+
+    // Must be applied to an enum type.
+    if let Some(span) = match &s.ast().data {
+        Data::Enum(_) => None,
+        Data::Struct(s) => Some(s.struct_token.span()),
+        Data::Union(u) => Some(u.union_token.span()),
+    } {
+        return span_error(span, "type is not an enum (TryFromU32)");
+    }
+
+    // The enum's variants must not have fields.
+    let variant_field_errors = s
+        .variants()
+        .iter()
+        .filter_map(|v| v.ast().fields.iter().map(|f| f.span()).next())
+        .map(|span| span_error(span, "enum variant cannot have fields (TryFromU32)"))
+        .collect::<TokenStream>();
+    if !variant_field_errors.is_empty() {
+        return variant_field_errors;
+    }
+
+    let ctor = s
+        .variants()
+        .iter()
+        .map(|v| v.construct(|_, _| -> TokenStream { unreachable!() }))
+        .collect::<Vec<_>>();
+    // FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
+    #[allow(keyword_idents_2024)]
+    s.gen_impl(quote! {
+        // The surrounding code might have shadowed these identifiers.
+        use ::core::convert::TryFrom;
+        use ::core::primitive::u32;
+        use ::core::result::Result::{self, Ok, Err};
+
+        gen impl TryFrom<u32> for @Self {
+            type Error = u32;
+
+            #[allow(deprecated)] // Don't warn about deprecated variants.
+            fn try_from(value: u32) -> Result<Self, Self::Error> {
+                #( if value == const { #ctor as u32 } { return Ok(#ctor) } )*
+                Err(value)
+            }
+        }
+    })
+}
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 79d3482472a..3b0151b1f94 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2021"
 bitflags = "2.4.1"
 libloading = "0.8.0"
 odht = { version = "0.3.1", features = ["nightly"] }
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 8adec7554a8..16623915c40 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -28,7 +28,7 @@ use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
-use rustc_span::symbol::{Symbol, sym};
+use rustc_span::symbol::{Ident, Symbol, sym};
 use rustc_span::{DUMMY_SP, Span};
 use rustc_target::spec::{PanicStrategy, Target, TargetTriple};
 use tracing::{debug, info, trace};
@@ -97,7 +97,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 }
 
 pub enum LoadedMacro {
-    MacroDef(ast::Item, Edition),
+    MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition },
     ProcMacro(SyntaxExtension),
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 71c7231a788..926eb4f6210 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -1,7 +1,6 @@
 use std::any::Any;
 use std::mem;
 
-use rustc_ast as ast;
 use rustc_attr::Deprecation;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -592,27 +591,16 @@ impl CStore {
 
         let data = self.get_crate_data(id.krate);
         if data.root.is_proc_macro_crate() {
-            return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx));
-        }
-
-        let span = data.get_span(id.index, sess);
-
-        LoadedMacro::MacroDef(
-            ast::Item {
+            LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx))
+        } else {
+            LoadedMacro::MacroDef {
+                def: data.get_macro(id.index, sess),
                 ident: data.item_ident(id.index, sess),
-                id: ast::DUMMY_NODE_ID,
-                span,
                 attrs: data.get_item_attrs(id.index, sess).collect(),
-                kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)),
-                vis: ast::Visibility {
-                    span: span.shrink_to_lo(),
-                    kind: ast::VisibilityKind::Inherited,
-                    tokens: None,
-                },
-                tokens: None,
-            },
-            data.root.edition,
-        )
+                span: data.get_span(id.index, sess),
+                edition: data.root.edition,
+            }
+        }
     }
 
     pub fn def_span_untracked(&self, def_id: DefId, sess: &Session) -> Span {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 47f7a8b7c20..b5ac302c597 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -278,7 +278,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
             let source_map = s.tcx.sess.source_map();
             let source_file_index = source_map.lookup_source_file_idx(self.lo);
             s.source_file_cache =
-                (source_map.files()[source_file_index].clone(), source_file_index);
+                (Lrc::clone(&source_map.files()[source_file_index]), source_file_index);
         }
         let (ref source_file, source_file_index) = s.source_file_cache;
         debug_assert!(source_file.contains(self.lo));
@@ -2275,7 +2275,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
     encoder.emit_raw_bytes(&0u64.to_le_bytes());
 
     let source_map_files = tcx.sess.source_map().files();
-    let source_file_cache = (source_map_files[0].clone(), 0);
+    let source_file_cache = (Lrc::clone(&source_map_files[0]), 0);
     let required_source_files = Some(FxIndexSet::default());
     drop(source_map_files);
 
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a00ca27aacc..f1844045677 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -6,6 +6,7 @@ use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
 use encoder::EncodeContext;
 pub use encoder::{EncodedMetadata, encode_metadata, rendered_const};
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
@@ -37,7 +38,6 @@ use rustc_span::edition::Edition;
 use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
-use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 use table::TableBuilder;
 use {rustc_ast as ast, rustc_attr as attr, rustc_hir as hir};
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 52fe9956b47..7e77923fcdf 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -8,7 +8,7 @@
 macro_rules! arena_types {
     ($macro:path) => (
         $macro!([
-            [] layout: rustc_target::abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>,
+            [] layout: rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx>,
             [] fn_abi: rustc_target::abi::call::FnAbi<'tcx, rustc_middle::ty::Ty<'tcx>>,
             // AdtDef are interned and compared by address
             [decode] adt_def: rustc_middle::ty::AdtDefData,
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
index 615a7402139..c241c06fce4 100644
--- a/compiler/rustc_middle/src/middle/debugger_visualizer.rs
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -32,7 +32,7 @@ impl DebuggerVisualizerFile {
 
     pub fn path_erased(&self) -> Self {
         DebuggerVisualizerFile {
-            src: self.src.clone(),
+            src: Lrc::clone(&self.src),
             visualizer_type: self.visualizer_type,
             path: None,
         }
diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
index 13e35cd0909..111ac990bc7 100644
--- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
+++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs
@@ -3,7 +3,7 @@
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::ItemLocalId;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
 use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable};
 
 use crate::ty;
@@ -54,4 +54,6 @@ pub struct ResolveBoundVars {
     pub defs: SortedMap<ItemLocalId, ResolvedArg>,
 
     pub late_bound_vars: SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>>,
+
+    pub opaque_captured_lifetimes: LocalDefIdMap<Vec<(ResolvedArg, LocalDefId)>>,
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d7a60a843b7..d7f58963101 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1781,6 +1781,23 @@ rustc_queries! {
         -> &'tcx SortedMap<ItemLocalId, Vec<ty::BoundVariableKind>> {
         desc { |tcx| "looking up late bound vars inside `{}`", tcx.def_path_str(owner_id) }
     }
+    /// For an opaque type, return the list of (captured lifetime, inner generic param).
+    /// ```ignore (illustrative)
+    /// fn foo<'a: 'a, 'b, T>(&'b u8) -> impl Into<Self> + 'b { ... }
+    /// ```
+    ///
+    /// We would return `[('a, '_a), ('b, '_b)]`, with `'a` early-bound and `'b` late-bound.
+    ///
+    /// After hir_ty_lowering, we get:
+    /// ```ignore (pseudo-code)
+    /// opaque foo::<'a>::opaque<'_a, '_b>: Into<Foo<'_a>> + '_b;
+    ///                          ^^^^^^^^ inner generic params
+    /// fn foo<'a>: for<'b> fn(&'b u8) -> foo::<'a>::opaque::<'a, 'b>
+    ///                                                       ^^^^^^ captured lifetimes
+    /// ```
+    query opaque_captured_lifetimes(def_id: LocalDefId) -> &'tcx [(ResolvedArg, LocalDefId)] {
+        desc { |tcx| "listing captured lifetimes for opaque `{}`", tcx.def_path_str(def_id) }
+    }
 
     /// Computes the visibility of the provided `def_id`.
     ///
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 35a16684615..8b77a4a81ca 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -472,32 +472,27 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
         let CacheDecoder { tcx, file_index_to_file, file_index_to_stable_id, source_map, .. } =
             *self;
 
-        file_index_to_file
-            .borrow_mut()
-            .entry(index)
-            .or_insert_with(|| {
-                let source_file_id = &file_index_to_stable_id[&index];
-                let source_file_cnum =
-                    tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id);
-
-                // If this `SourceFile` is from a foreign crate, then make sure
-                // that we've imported all of the source files from that crate.
-                // This has usually already been done during macro invocation.
-                // However, when encoding query results like `TypeckResults`,
-                // we might encode an `AdtDef` for a foreign type (because it
-                // was referenced in the body of the function). There is no guarantee
-                // that we will load the source files from that crate during macro
-                // expansion, so we use `import_source_files` to ensure that the foreign
-                // source files are actually imported before we call `source_file_by_stable_id`.
-                if source_file_cnum != LOCAL_CRATE {
-                    self.tcx.import_source_files(source_file_cnum);
-                }
+        Lrc::clone(file_index_to_file.borrow_mut().entry(index).or_insert_with(|| {
+            let source_file_id = &file_index_to_stable_id[&index];
+            let source_file_cnum = tcx.stable_crate_id_to_crate_num(source_file_id.stable_crate_id);
+
+            // If this `SourceFile` is from a foreign crate, then make sure
+            // that we've imported all of the source files from that crate.
+            // This has usually already been done during macro invocation.
+            // However, when encoding query results like `TypeckResults`,
+            // we might encode an `AdtDef` for a foreign type (because it
+            // was referenced in the body of the function). There is no guarantee
+            // that we will load the source files from that crate during macro
+            // expansion, so we use `import_source_files` to ensure that the foreign
+            // source files are actually imported before we call `source_file_by_stable_id`.
+            if source_file_cnum != LOCAL_CRATE {
+                self.tcx.import_source_files(source_file_cnum);
+            }
 
-                source_map
-                    .source_file_by_stable_id(source_file_id.stable_source_file_id)
-                    .expect("failed to lookup `SourceFile` in new context")
-            })
-            .clone()
+            source_map
+                .source_file_by_stable_id(source_file_id.stable_source_file_id)
+                .expect("failed to lookup `SourceFile` in new context")
+        }))
     }
 }
 
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 564d274bc8b..57da5b39ba7 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -323,7 +323,7 @@ macro_rules! define_callbacks {
                 // Increase this limit if necessary, but do try to keep the size low if possible
                 #[cfg(target_pointer_width = "64")]
                 const _: () = {
-                    if mem::size_of::<Key<'static>>() > 72 {
+                    if mem::size_of::<Key<'static>>() > 80 {
                         panic!("{}", concat!(
                             "the query `",
                             stringify!($name),
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 8ee8b4c4823..40e5ec45959 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -92,16 +92,6 @@ impl<'tcx> ObligationCause<'tcx> {
         ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() }
     }
 
-    pub fn span(&self) -> Span {
-        match *self.code() {
-            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                arm_span,
-                ..
-            }) => arm_span,
-            _ => self.span,
-        }
-    }
-
     #[inline]
     pub fn code(&self) -> &ObligationCauseCode<'tcx> {
         &self.code
@@ -517,10 +507,17 @@ pub struct MatchExpressionArmCause<'tcx> {
     pub prior_arm_block_id: Option<HirId>,
     pub prior_arm_ty: Ty<'tcx>,
     pub prior_arm_span: Span,
+    /// Span of the scrutinee of the match (the matched value).
     pub scrut_span: Span,
+    /// Source of the match, i.e. `match` or a desugaring.
     pub source: hir::MatchSource,
+    /// Span of the *whole* match expr.
+    pub expr_span: Span,
+    /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`).
+    ///
+    /// These are used for pointing out errors that may affect several arms.
     pub prior_non_diverging_arms: Vec<Span>,
-    // Is the expectation of this match expression an RPIT?
+    /// Is the expectation of this match expression an RPIT?
     pub tail_defines_return_position_impl_trait: Option<LocalDefId>,
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a6a0a6dc222..9616a533ab6 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -12,7 +12,7 @@ use std::marker::PhantomData;
 use std::ops::{Bound, Deref};
 use std::{fmt, iter, mem};
 
-use rustc_abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
+use rustc_abi::{FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
 use rustc_ast::{self as ast, attr};
 use rustc_data_structures::defer;
 use rustc_data_structures::fingerprint::Fingerprint;
@@ -54,7 +54,6 @@ use rustc_type_ir::TyKind::*;
 use rustc_type_ir::fold::TypeFoldable;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 pub use rustc_type_ir::lift::Lift;
-use rustc_type_ir::solve::SolverMode;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph};
 use tracing::{debug, trace};
 
@@ -170,15 +169,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         tracked.get(self)
     }
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R {
-        match mode {
-            SolverMode::Normal => f(&mut *self.new_solver_evaluation_cache.lock()),
-            SolverMode::Coherence => f(&mut *self.new_solver_coherence_evaluation_cache.lock()),
-        }
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
+        f(&mut *self.new_solver_evaluation_cache.lock())
     }
 
     fn evaluation_is_concurrent(&self) -> bool {
@@ -629,6 +621,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     ) -> ty::Binder<'tcx, T> {
         self.anonymize_bound_vars(binder)
     }
+
+    fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes {
+        self.opaque_types_defined_by(defining_anchor)
+    }
 }
 
 macro_rules! bidirectional_lang_item_map {
@@ -766,7 +762,7 @@ pub struct CtxtInterners<'tcx> {
     pat: InternedSet<'tcx, PatternKind<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
-    layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
+    layout: InternedSet<'tcx, LayoutData<FieldIdx, VariantIdx>>,
     adt_def: InternedSet<'tcx, AdtDefData>,
     external_constraints: InternedSet<'tcx, ExternalConstraintsData<TyCtxt<'tcx>>>,
     predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<TyCtxt<'tcx>>>,
@@ -1334,7 +1330,6 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Caches the results of goal evaluation in the new solver.
     pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
-    pub new_solver_coherence_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
 
     pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
 
@@ -1561,7 +1556,6 @@ impl<'tcx> TyCtxt<'tcx> {
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
             new_solver_evaluation_cache: Default::default(),
-            new_solver_coherence_evaluation_cache: Default::default(),
             canonical_param_env_cache: Default::default(),
             data_layout,
             alloc_map: Lock::new(interpret::AllocMap::new()),
@@ -2469,7 +2463,7 @@ direct_interners! {
     region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
     pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>,
     const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
-    layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
+    layout: pub mk_layout(LayoutData<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
     adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
     external_constraints: pub mk_external_constraints(ExternalConstraintsData<TyCtxt<'tcx>>):
         ExternalConstraints -> ExternalConstraints<'tcx>,
@@ -3066,7 +3060,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         loop {
             let parent = self.local_parent(opaque_lifetime_param_def_id);
-            let hir::OpaqueTy { lifetime_mapping, .. } = self.hir().expect_opaque_ty(parent);
+            let lifetime_mapping = self.opaque_captured_lifetimes(parent);
 
             let Some((lifetime, _)) = lifetime_mapping
                 .iter()
@@ -3075,8 +3069,8 @@ impl<'tcx> TyCtxt<'tcx> {
                 bug!("duplicated lifetime param should be present");
             };
 
-            match self.named_bound_var(lifetime.hir_id) {
-                Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => {
+            match *lifetime {
+                resolve_bound_vars::ResolvedArg::EarlyBound(ebv) => {
                     let new_parent = self.local_parent(ebv);
 
                     // If we map to another opaque, then it should be a parent
@@ -3095,7 +3089,7 @@ impl<'tcx> TyCtxt<'tcx> {
                         name: self.item_name(ebv.to_def_id()),
                     });
                 }
-                Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => {
+                resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv) => {
                     let new_parent = self.local_parent(lbv);
                     return ty::Region::new_late_param(
                         self,
@@ -3106,13 +3100,13 @@ impl<'tcx> TyCtxt<'tcx> {
                         ),
                     );
                 }
-                Some(resolve_bound_vars::ResolvedArg::Error(guar)) => {
+                resolve_bound_vars::ResolvedArg::Error(guar) => {
                     return ty::Region::new_error(self, guar);
                 }
                 _ => {
                     return ty::Region::new_error_with_message(
                         self,
-                        lifetime.ident.span,
+                        self.def_span(opaque_lifetime_param_def_id),
                         "cannot resolve lifetime",
                     );
                 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 7e65df6b27c..2c7a3ffd04c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,7 @@ use std::{cmp, fmt};
 
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
-    Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutS,
+    Abi, AddressSpace, Align, FieldsShape, HasDataLayout, Integer, LayoutCalculator, LayoutData,
     PointeeInfo, PointerKind, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, Variants,
 };
 use rustc_error_messages::DiagMessage;
@@ -346,7 +346,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
         // First try computing a static layout.
         let err = match tcx.layout_of(param_env.and(ty)) {
             Ok(layout) => {
-                if layout.abi.is_sized() {
+                if layout.is_sized() {
                     return Ok(SizeSkeleton::Known(layout.size, Some(layout.align.abi)));
                 } else {
                     // Just to be safe, don't claim a known layout for unsized types.
@@ -751,7 +751,7 @@ where
                     ty::Adt(def, _) => def.variant(variant_index).fields.len(),
                     _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
                 };
-                tcx.mk_layout(LayoutS {
+                tcx.mk_layout(LayoutData {
                     variants: Variants::Single { index: variant_index },
                     fields: match NonZero::new(fields) {
                         Some(fields) => FieldsShape::Union(fields),
@@ -788,7 +788,7 @@ where
             let tcx = cx.tcx();
             let tag_layout = |tag: Scalar| -> TyAndLayout<'tcx> {
                 TyAndLayout {
-                    layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+                    layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
                     ty: tag.primitive().to_ty(tcx),
                 }
             };
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b92fc864b49..bd32e5837b3 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -100,7 +100,7 @@ pub use self::rvalue_scopes::RvalueScopes;
 pub use self::sty::{
     AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig,
     CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst,
-    ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs,
+    ParamTy, PolyFnSig, TyKind, TypeAndMut, TypingMode, UpvarArgs,
 };
 pub use self::trait_def::TraitDef;
 pub use self::typeck_results::{
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index d8362ccc0a9..f54afdbc929 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -40,6 +40,7 @@ pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
 pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
 pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
 pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>;
+pub type TypingMode<'tcx> = ir::TypingMode<TyCtxt<'tcx>>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -1353,6 +1354,7 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
+    #[tracing::instrument(level = "trace", skip(tcx))]
     pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
         match self.kind() {
             FnDef(def_id, args) => tcx.fn_sig(*def_id).instantiate(tcx, args),
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 8c20d2e0d3a..e15ea4d8d8b 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -16,7 +16,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
-use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_span::{Span, Symbol};
@@ -500,7 +500,9 @@ fn construct_fn<'tcx>(
         );
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    // FIXME(#132279): This should be able to reveal opaque
+    // types defined during HIR typeck.
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let mut builder = Builder::new(
         thir,
         infcx,
@@ -578,7 +580,9 @@ fn construct_const<'a, 'tcx>(
         _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
     };
 
-    let infcx = tcx.infer_ctxt().build();
+    // FIXME(#132279): We likely want to be able to use the hidden types of
+    // opaques used by this function here.
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let mut builder =
         Builder::new(thir, infcx, def, hir_id, span, 0, const_ty, const_ty_span, None);
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index e2823456477..d20e5fcf4ec 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -784,7 +784,7 @@ impl<'tcx> Cx<'tcx> {
                 if_then_scope: region::Scope {
                     id: then.hir_id.local_id,
                     data: {
-                        if expr.span.at_least_rust_2024() && tcx.features().if_let_rescope() {
+                        if expr.span.at_least_rust_2024() {
                             region::ScopeData::IfThenRescope
                         } else {
                             region::ScopeData::IfThen
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 8498df59ce6..f222a869c03 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -79,6 +79,8 @@ enum LetSource {
     IfLetGuard,
     LetElse,
     WhileLet,
+    Else,
+    ElseIfLet,
 }
 
 struct MatchVisitor<'p, 'tcx> {
@@ -129,15 +131,20 @@ impl<'p, 'tcx> Visitor<'p, 'tcx> for MatchVisitor<'p, 'tcx> {
                 // Give a specific `let_source` for the condition.
                 let let_source = match ex.span.desugaring_kind() {
                     Some(DesugaringKind::WhileLoop) => LetSource::WhileLet,
-                    _ => LetSource::IfLet,
+                    _ => match self.let_source {
+                        LetSource::Else => LetSource::ElseIfLet,
+                        _ => LetSource::IfLet,
+                    },
                 };
                 self.with_let_source(let_source, |this| this.visit_expr(&self.thir[cond]));
                 self.with_let_source(LetSource::None, |this| {
                     this.visit_expr(&this.thir[then]);
-                    if let Some(else_) = else_opt {
-                        this.visit_expr(&this.thir[else_]);
-                    }
                 });
+                if let Some(else_) = else_opt {
+                    self.with_let_source(LetSource::Else, |this| {
+                        this.visit_expr(&this.thir[else_])
+                    });
+                }
                 return;
             }
             ExprKind::Match { scrutinee, scrutinee_hir_id: _, box ref arms, match_source } => {
@@ -573,9 +580,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
             // and we shouldn't lint.
             // For let guards inside a match, prefixes might use bindings of the match pattern,
             // so can't always be moved out.
+            // For `else if let`, an extra indentation level would be required to move the bindings.
             // FIXME: Add checking whether the bindings are actually used in the prefix,
             // and lint if they are not.
-            if !matches!(self.let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
+            if !matches!(
+                self.let_source,
+                LetSource::WhileLet | LetSource::IfLetGuard | LetSource::ElseIfLet
+            ) {
                 // Emit the lint
                 let prefix = &chain_refutabilities[..until];
                 let span_start = prefix[0].unwrap().0;
@@ -906,8 +917,8 @@ fn report_irrefutable_let_patterns(
     }
 
     match source {
-        LetSource::None | LetSource::PlainLet => bug!(),
-        LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
+        LetSource::None | LetSource::PlainLet | LetSource::Else => bug!(),
+        LetSource::IfLet | LetSource::ElseIfLet => emit_diag!(IrrefutableLetPatternsIfLet),
         LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
         LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
         LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 0dfa9168f7c..c89f526aa17 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -7,7 +7,7 @@ use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
 use rustc_span::Span;
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::ObligationCause;
@@ -36,7 +36,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         id: hir::HirId,
         span: Span,
     ) -> Box<Pat<'tcx>> {
-        let infcx = self.tcx.infer_ctxt().build();
+        // FIXME(#132279): We likely want to be able to reveal the hidden types
+        // of opaques defined in this function here.
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut convert = ConstToPat::new(self, id, span, infcx);
         convert.to_pat(c, ty)
     }
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 7199db677c4..62a69b3464f 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 # tidy-alphabetical-start
 polonius-engine = "0.13.0"
 regex = "1"
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
index bb53eaf6cbd..e5cddd0e5e4 100644
--- a/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
+++ b/compiler/rustc_mir_dataflow/src/drop_flag_effects.rs
@@ -1,5 +1,5 @@
+use rustc_abi::VariantIdx;
 use rustc_middle::mir::{self, Body, Location, Terminator, TerminatorKind};
-use rustc_target::abi::VariantIdx;
 use tracing::debug;
 
 use super::move_paths::{InitKind, LookupResult, MoveData, MovePathIndex};
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index 7f2a07e2f5e..9a1f000d39d 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,5 +1,6 @@
 use std::{fmt, iter};
 
+use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_hir::lang_items::LangItem;
 use rustc_index::Idx;
 use rustc_middle::mir::patch::MirPatch;
@@ -10,7 +11,6 @@ use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt};
 use rustc_span::DUMMY_SP;
 use rustc_span::source_map::Spanned;
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use tracing::{debug, instrument};
 
 /// The value of an inserted drop flag.
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 96a70f4fa5b..bac75b972f9 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -32,8 +32,11 @@ pub(crate) struct Formatter<'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    body: &'mir Body<'tcx>,
-    results: RefCell<Option<Results<'tcx, A>>>,
+    // The `RefCell` is used because `<Formatter as Labeller>::node_label`
+    // takes `&self`, but it needs to modify the cursor. This is also the
+    // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has
+    // the operations that involve the mutation, i.e. within the `borrow_mut`.
+    cursor: RefCell<ResultsCursor<'mir, 'tcx, A>>,
     style: OutputStyle,
     reachable: BitSet<BasicBlock>,
 }
@@ -48,11 +51,15 @@ where
         style: OutputStyle,
     ) -> Self {
         let reachable = mir::traversal::reachable_as_bitset(body);
-        Formatter { body, results: Some(results).into(), style, reachable }
+        Formatter { cursor: results.into_results_cursor(body).into(), style, reachable }
+    }
+
+    fn body(&self) -> &'mir Body<'tcx> {
+        self.cursor.borrow().body()
     }
 
     pub(crate) fn into_results(self) -> Results<'tcx, A> {
-        self.results.into_inner().unwrap()
+        self.cursor.into_inner().into_results()
     }
 }
 
@@ -81,7 +88,7 @@ where
     type Edge = CfgEdge;
 
     fn graph_id(&self) -> dot::Id<'_> {
-        let name = graphviz_safe_def_name(self.body.source.def_id());
+        let name = graphviz_safe_def_name(self.body().source.def_id());
         dot::Id::new(format!("graph_for_def_id_{name}")).unwrap()
     }
 
@@ -90,20 +97,11 @@ where
     }
 
     fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
-        let mut label = Vec::new();
-        self.results.replace_with(|results| {
-            // `Formatter::result` is a `RefCell<Option<_>>` so we can replace
-            // the value with `None`, move it into the results cursor, move it
-            // back out, and return it to the refcell wrapped in `Some`.
-            let mut fmt = BlockFormatter {
-                results: results.take().unwrap().into_results_cursor(self.body),
-                style: self.style,
-                bg: Background::Light,
-            };
+        let mut cursor = self.cursor.borrow_mut();
+        let mut fmt =
+            BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light };
+        let label = fmt.write_node_label(*block).unwrap();
 
-            fmt.write_node_label(&mut label, *block).unwrap();
-            Some(fmt.results.into_results())
-        });
         dot::LabelText::html(String::from_utf8(label).unwrap())
     }
 
@@ -112,12 +110,12 @@ where
     }
 
     fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> {
-        let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index];
+        let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index];
         dot::LabelText::label(label.clone())
     }
 }
 
-impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A>
+impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
@@ -125,7 +123,7 @@ where
     type Edge = CfgEdge;
 
     fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
-        self.body
+        self.body()
             .basic_blocks
             .indices()
             .filter(|&idx| self.reachable.contains(idx))
@@ -134,10 +132,10 @@ where
     }
 
     fn edges(&self) -> dot::Edges<'_, Self::Edge> {
-        self.body
-            .basic_blocks
+        let body = self.body();
+        body.basic_blocks
             .indices()
-            .flat_map(|bb| dataflow_successors(self.body, bb))
+            .flat_map(|bb| dataflow_successors(body, bb))
             .collect::<Vec<_>>()
             .into()
     }
@@ -147,20 +145,20 @@ where
     }
 
     fn target(&self, edge: &Self::Edge) -> Self::Node {
-        self.body[edge.source].terminator().successors().nth(edge.index).unwrap()
+        self.body()[edge.source].terminator().successors().nth(edge.index).unwrap()
     }
 }
 
-struct BlockFormatter<'mir, 'tcx, A>
+struct BlockFormatter<'a, 'mir, 'tcx, A>
 where
     A: Analysis<'tcx>,
 {
-    results: ResultsCursor<'mir, 'tcx, A>,
+    cursor: &'a mut ResultsCursor<'mir, 'tcx, A>,
     bg: Background,
     style: OutputStyle,
 }
 
-impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A>
+impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A>
 where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
@@ -173,7 +171,9 @@ where
         bg
     }
 
-    fn write_node_label(&mut self, w: &mut impl io::Write, block: BasicBlock) -> io::Result<()> {
+    fn write_node_label(&mut self, block: BasicBlock) -> io::Result<Vec<u8>> {
+        use std::io::Write;
+
         //   Sample output:
         //   +-+-----------------------------------------------+
         // A |                      bb4                        |
@@ -200,6 +200,9 @@ where
         // attributes. Make sure to test the output before trying to remove the redundancy.
         // Notably, `align` was found to have no effect when applied only to <table>.
 
+        let mut v = vec![];
+        let w = &mut v;
+
         let table_fmt = concat!(
             " border=\"1\"",
             " cellborder=\"1\"",
@@ -219,8 +222,8 @@ where
 
         // C: State at start of block
         self.bg = Background::Light;
-        self.results.seek_to_block_start(block);
-        let block_start_state = self.results.get().clone();
+        self.cursor.seek_to_block_start(block);
+        let block_start_state = self.cursor.get().clone();
         self.write_row_with_full_state(w, "", "(on start)")?;
 
         // D + E: Statement and terminator transfer functions
@@ -228,12 +231,12 @@ where
 
         // F: State at end of block
 
-        let terminator = self.results.body()[block].terminator();
+        let terminator = self.cursor.body()[block].terminator();
 
         // Write the full dataflow state immediately after the terminator if it differs from the
         // state at block entry.
-        self.results.seek_to_block_end(block);
-        if self.results.get() != &block_start_state || A::Direction::IS_BACKWARD {
+        self.cursor.seek_to_block_end(block);
+        if self.cursor.get() != &block_start_state || A::Direction::IS_BACKWARD {
             let after_terminator_name = match terminator.kind {
                 mir::TerminatorKind::Call { target: Some(_), .. } => "(on unwind)",
                 _ => "(on end)",
@@ -250,8 +253,8 @@ where
         match terminator.kind {
             mir::TerminatorKind::Call { destination, .. } => {
                 self.write_row(w, "", "(on successful return)", |this, w, fmt| {
-                    let state_on_unwind = this.results.get().clone();
-                    this.results.apply_custom_effect(|analysis, state| {
+                    let state_on_unwind = this.cursor.get().clone();
+                    this.cursor.apply_custom_effect(|analysis, state| {
                         analysis.apply_call_return_effect(
                             state,
                             block,
@@ -265,9 +268,9 @@ where
                         colspan = this.style.num_state_columns(),
                         fmt = fmt,
                         diff = diff_pretty(
-                            this.results.get(),
+                            this.cursor.get(),
                             &state_on_unwind,
-                            this.results.analysis()
+                            this.cursor.analysis()
                         ),
                     )
                 })?;
@@ -275,8 +278,8 @@ where
 
             mir::TerminatorKind::Yield { resume, resume_arg, .. } => {
                 self.write_row(w, "", "(on yield resume)", |this, w, fmt| {
-                    let state_on_coroutine_drop = this.results.get().clone();
-                    this.results.apply_custom_effect(|analysis, state| {
+                    let state_on_coroutine_drop = this.cursor.get().clone();
+                    this.cursor.apply_custom_effect(|analysis, state| {
                         analysis.apply_call_return_effect(
                             state,
                             resume,
@@ -290,9 +293,9 @@ where
                         colspan = this.style.num_state_columns(),
                         fmt = fmt,
                         diff = diff_pretty(
-                            this.results.get(),
+                            this.cursor.get(),
                             &state_on_coroutine_drop,
-                            this.results.analysis()
+                            this.cursor.analysis()
                         ),
                     )
                 })?;
@@ -302,8 +305,8 @@ where
                 if !targets.is_empty() =>
             {
                 self.write_row(w, "", "(on successful return)", |this, w, fmt| {
-                    let state_on_unwind = this.results.get().clone();
-                    this.results.apply_custom_effect(|analysis, state| {
+                    let state_on_unwind = this.cursor.get().clone();
+                    this.cursor.apply_custom_effect(|analysis, state| {
                         analysis.apply_call_return_effect(
                             state,
                             block,
@@ -317,9 +320,9 @@ where
                         colspan = this.style.num_state_columns(),
                         fmt = fmt,
                         diff = diff_pretty(
-                            this.results.get(),
+                            this.cursor.get(),
                             &state_on_unwind,
-                            this.results.analysis()
+                            this.cursor.analysis()
                         ),
                     )
                 })?;
@@ -328,7 +331,9 @@ where
             _ => {}
         };
 
-        write!(w, "</table>")
+        write!(w, "</table>")?;
+
+        Ok(v)
     }
 
     fn write_block_header_simple(
@@ -407,9 +412,9 @@ where
         block: BasicBlock,
     ) -> io::Result<()> {
         let diffs = StateDiffCollector::run(
-            self.results.body(),
+            self.cursor.body(),
             block,
-            self.results.mut_results(),
+            self.cursor.mut_results(),
             self.style,
         );
 
@@ -420,7 +425,7 @@ where
             if A::Direction::IS_FORWARD { it.next().unwrap() } else { it.next_back().unwrap() }
         };
 
-        for (i, statement) in self.results.body()[block].statements.iter().enumerate() {
+        for (i, statement) in self.cursor.body()[block].statements.iter().enumerate() {
             let statement_str = format!("{statement:?}");
             let index_str = format!("{i}");
 
@@ -442,7 +447,7 @@ where
         assert!(diffs_after.is_empty());
         assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty));
 
-        let terminator = self.results.body()[block].terminator();
+        let terminator = self.cursor.body()[block].terminator();
         let mut terminator_str = String::new();
         terminator.kind.fmt_head(&mut terminator_str).unwrap();
 
@@ -492,8 +497,8 @@ where
         mir: &str,
     ) -> io::Result<()> {
         self.write_row(w, i, mir, |this, w, fmt| {
-            let state = this.results.get();
-            let analysis = this.results.analysis();
+            let state = this.cursor.get();
+            let analysis = this.cursor.analysis();
 
             // FIXME: The full state vector can be quite long. It would be nice to split on commas
             // and use some text wrapping algorithm.
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index 959f1ea5340..8f81da8bb04 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -7,18 +7,17 @@
 //!
 //! The `impls` module contains several examples of dataflow analyses.
 //!
-//! Create an `Engine` for your analysis using the `into_engine` method on the `Analysis` trait,
-//! then call `iterate_to_fixpoint`. From there, you can use a `ResultsCursor` to inspect the
-//! fixpoint solution to your dataflow problem, or implement the `ResultsVisitor` interface and use
-//! `visit_results`. The following example uses the `ResultsCursor` approach.
+//! Then call `iterate_to_fixpoint` on your type that impls `Analysis` to get a `Results`. From
+//! there, you can use a `ResultsCursor` to inspect the fixpoint solution to your dataflow problem,
+//! or implement the `ResultsVisitor` interface and use `visit_results`. The following example uses
+//! the `ResultsCursor` approach.
 //!
 //! ```ignore (cross-crate-imports)
-//! use rustc_const_eval::dataflow::Analysis; // Makes `into_engine` available.
+//! use rustc_const_eval::dataflow::Analysis; // Makes `iterate_to_fixpoint` available.
 //!
 //! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
 //!     let analysis = MyAnalysis::new()
-//!         .into_engine(tcx, body)
-//!         .iterate_to_fixpoint()
+//!         .iterate_to_fixpoint(tcx, body, None)
 //!         .into_results_cursor(body);
 //!
 //!     // Print the dataflow state *after* each statement in the start block.
@@ -34,23 +33,29 @@
 
 use std::cmp::Ordering;
 
-use rustc_index::Idx;
+use rustc_data_structures::work_queue::WorkQueue;
 use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
-use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges};
+use rustc_index::{Idx, IndexVec};
+use rustc_middle::bug;
+use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal};
 use rustc_middle::ty::TyCtxt;
+use tracing::error;
+
+use self::results::write_graphviz_results;
+use super::fmt::DebugWithContext;
 
 mod cursor;
 mod direction;
-mod engine;
 pub mod fmt;
 pub mod graphviz;
 pub mod lattice;
+mod results;
 mod visitor;
 
 pub use self::cursor::ResultsCursor;
 pub use self::direction::{Backward, Direction, Forward};
-pub use self::engine::{Engine, Results};
 pub use self::lattice::{JoinSemiLattice, MaybeReachable};
+pub use self::results::Results;
 pub use self::visitor::{ResultsVisitable, ResultsVisitor, visit_results};
 
 /// Analysis domains are all bitsets of various kinds. This trait holds
@@ -223,26 +228,92 @@ pub trait Analysis<'tcx> {
 
     /* Extension methods */
 
-    /// Creates an `Engine` to find the fixpoint for this dataflow problem.
+    /// Finds the fixpoint for this dataflow problem.
     ///
     /// You shouldn't need to override this. Its purpose is to enable method chaining like so:
     ///
     /// ```ignore (cross-crate-imports)
     /// let results = MyAnalysis::new(tcx, body)
-    ///     .into_engine(tcx, body, def_id)
-    ///     .iterate_to_fixpoint()
+    ///     .iterate_to_fixpoint(tcx, body, None)
     ///     .into_results_cursor(body);
     /// ```
-    #[inline]
-    fn into_engine<'mir>(
-        self,
+    /// You can optionally add a `pass_name` to the graphviz output for this particular run of a
+    /// dataflow analysis. Some analyses are run multiple times in the compilation pipeline.
+    /// Without a `pass_name` to differentiates them, only the results for the latest run will be
+    /// saved.
+    fn iterate_to_fixpoint<'mir>(
+        mut self,
         tcx: TyCtxt<'tcx>,
         body: &'mir mir::Body<'tcx>,
-    ) -> Engine<'mir, 'tcx, Self>
+        pass_name: Option<&'static str>,
+    ) -> Results<'tcx, Self>
     where
         Self: Sized,
+        Self::Domain: DebugWithContext<Self>,
     {
-        Engine::new(tcx, body, self)
+        let mut entry_sets =
+            IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len());
+        self.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
+
+        if Self::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != self.bottom_value(body) {
+            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
+        }
+
+        let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
+
+        if Self::Direction::IS_FORWARD {
+            for (bb, _) in traversal::reverse_postorder(body) {
+                dirty_queue.insert(bb);
+            }
+        } else {
+            // Reverse post-order on the reverse CFG may generate a better iteration order for
+            // backward dataflow analyses, but probably not enough to matter.
+            for (bb, _) in traversal::postorder(body) {
+                dirty_queue.insert(bb);
+            }
+        }
+
+        // `state` is not actually used between iterations;
+        // this is just an optimization to avoid reallocating
+        // every iteration.
+        let mut state = self.bottom_value(body);
+        while let Some(bb) = dirty_queue.pop() {
+            let bb_data = &body[bb];
+
+            // Set the state to the entry state of the block.
+            // This is equivalent to `state = entry_sets[bb].clone()`,
+            // but it saves an allocation, thus improving compile times.
+            state.clone_from(&entry_sets[bb]);
+
+            // Apply the block transfer function, using the cached one if it exists.
+            let edges = Self::Direction::apply_effects_in_block(&mut self, &mut state, bb, bb_data);
+
+            Self::Direction::join_state_into_successors_of(
+                &mut self,
+                body,
+                &mut state,
+                bb,
+                edges,
+                |target: BasicBlock, state: &Self::Domain| {
+                    let set_changed = entry_sets[target].join(state);
+                    if set_changed {
+                        dirty_queue.insert(target);
+                    }
+                },
+            );
+        }
+
+        let results = Results { analysis: self, entry_sets };
+
+        if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
+            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
+            if let Err(e) = res {
+                error!("Failed to write graphviz dataflow results: {}", e);
+            }
+            results
+        } else {
+            results
+        }
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index cbd1083d037..366fcbf33ba 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -1,23 +1,19 @@
-//! A solver for dataflow problems.
+//! Dataflow analysis results.
 
 use std::ffi::OsString;
 use std::path::PathBuf;
 
-use rustc_data_structures::work_queue::WorkQueue;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
-use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, create_dump_file, dump_enabled, traversal};
 use rustc_middle::ty::TyCtxt;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_span::symbol::{Symbol, sym};
-use tracing::{debug, error};
+use tracing::debug;
 use {rustc_ast as ast, rustc_graphviz as dot};
 
 use super::fmt::DebugWithContext;
-use super::{
-    Analysis, Direction, JoinSemiLattice, ResultsCursor, ResultsVisitor, graphviz, visit_results,
-};
+use super::{Analysis, ResultsCursor, ResultsVisitor, graphviz, visit_results};
 use crate::errors::{
     DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter,
 };
@@ -65,124 +61,17 @@ where
         body: &'mir mir::Body<'tcx>,
         vis: &mut impl ResultsVisitor<'mir, 'tcx, Self, Domain = A::Domain>,
     ) {
-        let blocks = mir::traversal::reachable(body);
+        let blocks = traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
 }
 
-/// A solver for dataflow problems.
-pub struct Engine<'mir, 'tcx, A>
-where
-    A: Analysis<'tcx>,
-{
-    tcx: TyCtxt<'tcx>,
-    body: &'mir mir::Body<'tcx>,
-    entry_sets: IndexVec<BasicBlock, A::Domain>,
-    pass_name: Option<&'static str>,
-    analysis: A,
-}
-
-impl<'mir, 'tcx, A, D> Engine<'mir, 'tcx, A>
-where
-    A: Analysis<'tcx, Domain = D>,
-    D: Clone + JoinSemiLattice,
-{
-    /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer
-    /// function.
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, analysis: A) -> Self {
-        let mut entry_sets =
-            IndexVec::from_fn_n(|_| analysis.bottom_value(body), body.basic_blocks.len());
-        analysis.initialize_start_block(body, &mut entry_sets[mir::START_BLOCK]);
-
-        if A::Direction::IS_BACKWARD && entry_sets[mir::START_BLOCK] != analysis.bottom_value(body)
-        {
-            bug!("`initialize_start_block` is not yet supported for backward dataflow analyses");
-        }
-
-        Engine { analysis, tcx, body, pass_name: None, entry_sets }
-    }
-
-    /// Adds an identifier to the graphviz output for this particular run of a dataflow analysis.
-    ///
-    /// Some analyses are run multiple times in the compilation pipeline. Give them a `pass_name`
-    /// to differentiate them. Otherwise, only the results for the latest run will be saved.
-    pub fn pass_name(mut self, name: &'static str) -> Self {
-        self.pass_name = Some(name);
-        self
-    }
-
-    /// Computes the fixpoint for this dataflow problem and returns it.
-    pub fn iterate_to_fixpoint(self) -> Results<'tcx, A>
-    where
-        A::Domain: DebugWithContext<A>,
-    {
-        let Engine { mut analysis, body, mut entry_sets, tcx, pass_name } = self;
-
-        let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks.len());
-
-        if A::Direction::IS_FORWARD {
-            for (bb, _) in traversal::reverse_postorder(body) {
-                dirty_queue.insert(bb);
-            }
-        } else {
-            // Reverse post-order on the reverse CFG may generate a better iteration order for
-            // backward dataflow analyses, but probably not enough to matter.
-            for (bb, _) in traversal::postorder(body) {
-                dirty_queue.insert(bb);
-            }
-        }
-
-        // `state` is not actually used between iterations;
-        // this is just an optimization to avoid reallocating
-        // every iteration.
-        let mut state = analysis.bottom_value(body);
-        while let Some(bb) = dirty_queue.pop() {
-            let bb_data = &body[bb];
-
-            // Set the state to the entry state of the block.
-            // This is equivalent to `state = entry_sets[bb].clone()`,
-            // but it saves an allocation, thus improving compile times.
-            state.clone_from(&entry_sets[bb]);
-
-            // Apply the block transfer function, using the cached one if it exists.
-            let edges =
-                A::Direction::apply_effects_in_block(&mut analysis, &mut state, bb, bb_data);
-
-            A::Direction::join_state_into_successors_of(
-                &mut analysis,
-                body,
-                &mut state,
-                bb,
-                edges,
-                |target: BasicBlock, state: &A::Domain| {
-                    let set_changed = entry_sets[target].join(state);
-                    if set_changed {
-                        dirty_queue.insert(target);
-                    }
-                },
-            );
-        }
-
-        let results = Results { analysis, entry_sets };
-
-        if tcx.sess.opts.unstable_opts.dump_mir_dataflow {
-            let (res, results) = write_graphviz_results(tcx, body, results, pass_name);
-            if let Err(e) = res {
-                error!("Failed to write graphviz dataflow results: {}", e);
-            }
-            results
-        } else {
-            results
-        }
-    }
-}
-
 // Graphviz
 
 /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via
 /// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are
 /// the same.
-fn write_graphviz_results<'tcx, A>(
+pub(super) fn write_graphviz_results<'tcx, A>(
     tcx: TyCtxt<'tcx>,
     body: &mir::Body<'tcx>,
     results: Results<'tcx, A>,
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index b284f0308f9..b404e3bfb72 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -18,9 +18,9 @@ pub use self::drop_flag_effects::{
     move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
 };
 pub use self::framework::{
-    Analysis, Backward, Direction, Engine, Forward, GenKill, JoinSemiLattice, MaybeReachable,
-    Results, ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz,
-    lattice, visit_results,
+    Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results,
+    ResultsCursor, ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects, fmt, graphviz, lattice,
+    visit_results,
 };
 use self::move_paths::MoveData;
 
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 5727517bd61..99d0ccde105 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -43,31 +43,28 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let move_data = MoveData::gather_moves(body, tcx, |_| true);
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+        let flow_inits =
+            MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
         let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+            .iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-        let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint();
+        let flow_def_inits =
+            DefinitelyInitializedPlaces::new(body, &move_data).iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
     }
 
     if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
-        let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
+        let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None);
 
         sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
     }
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index d0f62bd82d1..f7d4a082779 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -36,6 +36,7 @@ use std::assert_matches::assert_matches;
 use std::fmt::{Debug, Formatter};
 use std::ops::Range;
 
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry};
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -46,7 +47,6 @@ use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_target::abi::{FieldIdx, VariantIdx};
 use tracing::debug;
 
 use crate::fmt::DebugWithContext;
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 07ca51a67ae..4b648d21084 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 # tidy-alphabetical-start
 either = "1"
 itertools = "0.12"
+rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index cd291058977..6d5665b4331 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -64,7 +64,7 @@ use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{
-    self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt,
+    self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::Analysis;
@@ -666,14 +666,13 @@ fn locals_live_across_suspend_points<'tcx>(
     // Calculate when MIR locals have live storage. This gives us an upper bound of their
     // lifetimes.
     let mut storage_live = MaybeStorageLive::new(std::borrow::Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // Calculate the MIR locals which have been previously
     // borrowed (even if they are still active).
     let borrowed_locals_results =
-        MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint();
+        MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine"));
 
     let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body);
 
@@ -681,16 +680,12 @@ fn locals_live_across_suspend_points<'tcx>(
     // for.
     let mut requires_storage_cursor =
         MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body))
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(tcx, body, None)
             .into_results_cursor(body);
 
     // Calculate the liveness of MIR locals ignoring borrows.
-    let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body)
-        .pass_name("coroutine")
-        .iterate_to_fixpoint()
-        .into_results_cursor(body);
+    let mut liveness =
+        MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")).into_results_cursor(body);
 
     let mut storage_liveness_map = IndexVec::from_elem(None, &body.basic_blocks);
     let mut live_locals_at_suspension_points = Vec::new();
@@ -1501,7 +1496,11 @@ fn check_field_tys_sized<'tcx>(
         return;
     }
 
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    // FIXME(#132279): @lcnr believes that we may want to support coroutines
+    // whose `Sized`-ness relies on the hidden types of opaques defined by the
+    // parent function. In this case we'd have to be able to reveal only these
+    // opaques here.
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
     let param_env = tcx.param_env(def_id);
 
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 9a533ea024d..cf9f6981c5a 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -280,13 +280,12 @@ impl<'a> CountersBuilder<'a> {
         //
         // The traversal tries to ensure that, when a loop is encountered, all
         // nodes within the loop are visited before visiting any nodes outside
-        // the loop. It also keeps track of which loop(s) the traversal is
-        // currently inside.
+        // the loop.
         let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph);
         while let Some(bcb) = traversal.next() {
             let _span = debug_span!("traversal", ?bcb).entered();
             if self.bcb_needs_counter.contains(bcb) {
-                self.make_node_counter_and_out_edge_counters(&traversal, bcb);
+                self.make_node_counter_and_out_edge_counters(bcb);
             }
         }
 
@@ -299,12 +298,8 @@ impl<'a> CountersBuilder<'a> {
 
     /// Make sure the given node has a node counter, and then make sure each of
     /// its out-edges has an edge counter (if appropriate).
-    #[instrument(level = "debug", skip(self, traversal))]
-    fn make_node_counter_and_out_edge_counters(
-        &mut self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
-        from_bcb: BasicCoverageBlock,
-    ) {
+    #[instrument(level = "debug", skip(self))]
+    fn make_node_counter_and_out_edge_counters(&mut self, from_bcb: BasicCoverageBlock) {
         // First, ensure that this node has a counter of some kind.
         // We might also use that counter to compute one of the out-edge counters.
         let node_counter = self.get_or_make_node_counter(from_bcb);
@@ -337,8 +332,7 @@ impl<'a> CountersBuilder<'a> {
 
         // If there are out-edges without counters, choose one to be given an expression
         // (computed from this node and the other out-edges) instead of a physical counter.
-        let Some(target_bcb) =
-            self.choose_out_edge_for_expression(traversal, &candidate_successors)
+        let Some(target_bcb) = self.choose_out_edge_for_expression(from_bcb, &candidate_successors)
         else {
             return;
         };
@@ -462,12 +456,12 @@ impl<'a> CountersBuilder<'a> {
     /// choose one to be given a counter expression instead of a physical counter.
     fn choose_out_edge_for_expression(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
+        from_bcb: BasicCoverageBlock,
         candidate_successors: &[BasicCoverageBlock],
     ) -> Option<BasicCoverageBlock> {
         // Try to find a candidate that leads back to the top of a loop,
         // because reloop edges tend to be executed more times than loop-exit edges.
-        if let Some(reloop_target) = self.find_good_reloop_edge(traversal, &candidate_successors) {
+        if let Some(reloop_target) = self.find_good_reloop_edge(from_bcb, &candidate_successors) {
             debug!("Selecting reloop target {reloop_target:?} to get an expression");
             return Some(reloop_target);
         }
@@ -486,7 +480,7 @@ impl<'a> CountersBuilder<'a> {
     /// for them to be able to avoid a physical counter increment.
     fn find_good_reloop_edge(
         &self,
-        traversal: &TraverseCoverageGraphWithLoops<'_>,
+        from_bcb: BasicCoverageBlock,
         candidate_successors: &[BasicCoverageBlock],
     ) -> Option<BasicCoverageBlock> {
         // If there are no candidates, avoid iterating over the loop stack.
@@ -495,14 +489,15 @@ impl<'a> CountersBuilder<'a> {
         }
 
         // Consider each loop on the current traversal context stack, top-down.
-        for reloop_bcbs in traversal.reloop_bcbs_per_loop() {
+        for loop_header_node in self.graph.loop_headers_containing(from_bcb) {
             // Try to find a candidate edge that doesn't exit this loop.
             for &target_bcb in candidate_successors {
                 // An edge is a reloop edge if its target dominates any BCB that has
                 // an edge back to the loop header. (Otherwise it's an exit edge.)
-                let is_reloop_edge = reloop_bcbs
-                    .iter()
-                    .any(|&reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb));
+                let is_reloop_edge = self
+                    .graph
+                    .reloop_predecessors(loop_header_node)
+                    .any(|reloop_bcb| self.graph.dominates(target_bcb, reloop_bcb));
                 if is_reloop_edge {
                     // We found a good out-edge to be given an expression.
                     return Some(target_bcb);
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 930fa129ef2..168262bf01c 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,10 +1,11 @@
 use std::cmp::Ordering;
 use std::collections::VecDeque;
+use std::iter;
 use std::ops::{Index, IndexMut};
 
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::graph::dominators::{self, Dominators};
+use rustc_data_structures::graph::dominators::Dominators;
 use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
@@ -20,11 +21,17 @@ pub(crate) struct CoverageGraph {
     bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
     pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
     pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
+
     dominators: Option<Dominators<BasicCoverageBlock>>,
     /// Allows nodes to be compared in some total order such that _if_
     /// `a` dominates `b`, then `a < b`. If neither node dominates the other,
     /// their relative order is consistent but arbitrary.
     dominator_order_rank: IndexVec<BasicCoverageBlock, u32>,
+    /// A loop header is a node that dominates one or more of its predecessors.
+    is_loop_header: BitSet<BasicCoverageBlock>,
+    /// For each node, the loop header node of its nearest enclosing loop.
+    /// This forms a linked list that can be traversed to find all enclosing loops.
+    enclosing_loop_header: IndexVec<BasicCoverageBlock, Option<BasicCoverageBlock>>,
 }
 
 impl CoverageGraph {
@@ -66,17 +73,38 @@ impl CoverageGraph {
             predecessors,
             dominators: None,
             dominator_order_rank: IndexVec::from_elem_n(0, num_nodes),
+            is_loop_header: BitSet::new_empty(num_nodes),
+            enclosing_loop_header: IndexVec::from_elem_n(None, num_nodes),
         };
         assert_eq!(num_nodes, this.num_nodes());
 
-        this.dominators = Some(dominators::dominators(&this));
+        // Set the dominators first, because later init steps rely on them.
+        this.dominators = Some(graph::dominators::dominators(&this));
 
-        // The dominator rank of each node is just its index in a reverse-postorder traversal.
-        let reverse_post_order = graph::iterate::reverse_post_order(&this, this.start_node());
+        // Iterate over all nodes, such that dominating nodes are visited before
+        // the nodes they dominate. Either preorder or reverse postorder is fine.
+        let dominator_order = graph::iterate::reverse_post_order(&this, this.start_node());
         // The coverage graph is created by traversal, so all nodes are reachable.
-        assert_eq!(reverse_post_order.len(), this.num_nodes());
-        for (rank, bcb) in (0u32..).zip(reverse_post_order) {
+        assert_eq!(dominator_order.len(), this.num_nodes());
+        for (rank, bcb) in (0u32..).zip(dominator_order) {
+            // The dominator rank of each node is its index in a dominator-order traversal.
             this.dominator_order_rank[bcb] = rank;
+
+            // A node is a loop header if it dominates any of its predecessors.
+            if this.reloop_predecessors(bcb).next().is_some() {
+                this.is_loop_header.insert(bcb);
+            }
+
+            // If the immediate dominator is a loop header, that's our enclosing loop.
+            // Otherwise, inherit the immediate dominator's enclosing loop.
+            // (Dominator order ensures that we already processed the dominator.)
+            if let Some(dom) = this.dominators().immediate_dominator(bcb) {
+                this.enclosing_loop_header[bcb] = this
+                    .is_loop_header
+                    .contains(dom)
+                    .then_some(dom)
+                    .or_else(|| this.enclosing_loop_header[dom]);
+            }
         }
 
         // The coverage graph's entry-point node (bcb0) always starts with bb0,
@@ -173,8 +201,13 @@ impl CoverageGraph {
     }
 
     #[inline(always)]
+    fn dominators(&self) -> &Dominators<BasicCoverageBlock> {
+        self.dominators.as_ref().unwrap()
+    }
+
+    #[inline(always)]
     pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool {
-        self.dominators.as_ref().unwrap().dominates(dom, node)
+        self.dominators().dominates(dom, node)
     }
 
     #[inline(always)]
@@ -214,6 +247,36 @@ impl CoverageGraph {
             None
         }
     }
+
+    /// For each loop that contains the given node, yields the "loop header"
+    /// node representing that loop, from innermost to outermost. If the given
+    /// node is itself a loop header, it is yielded first.
+    pub(crate) fn loop_headers_containing(
+        &self,
+        bcb: BasicCoverageBlock,
+    ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+        let self_if_loop_header = self.is_loop_header.contains(bcb).then_some(bcb).into_iter();
+
+        let mut curr = Some(bcb);
+        let strictly_enclosing = iter::from_fn(move || {
+            let enclosing = self.enclosing_loop_header[curr?];
+            curr = enclosing;
+            enclosing
+        });
+
+        self_if_loop_header.chain(strictly_enclosing)
+    }
+
+    /// For the given node, yields the subset of its predecessor nodes that
+    /// it dominates. If that subset is non-empty, the node is a "loop header",
+    /// and each of those predecessors represents an in-edge that jumps back to
+    /// the top of its loop.
+    pub(crate) fn reloop_predecessors(
+        &self,
+        to_bcb: BasicCoverageBlock,
+    ) -> impl Iterator<Item = BasicCoverageBlock> + Captures<'_> {
+        self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred))
+    }
 }
 
 impl Index<BasicCoverageBlock> for CoverageGraph {
@@ -439,15 +502,12 @@ struct TraversalContext {
 pub(crate) struct TraverseCoverageGraphWithLoops<'a> {
     basic_coverage_blocks: &'a CoverageGraph,
 
-    backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
     context_stack: Vec<TraversalContext>,
     visited: BitSet<BasicCoverageBlock>,
 }
 
 impl<'a> TraverseCoverageGraphWithLoops<'a> {
     pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self {
-        let backedges = find_loop_backedges(basic_coverage_blocks);
-
         let worklist = VecDeque::from([basic_coverage_blocks.start_node()]);
         let context_stack = vec![TraversalContext { loop_header: None, worklist }];
 
@@ -456,17 +516,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
         // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
         // exhausted.
         let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        Self { basic_coverage_blocks, backedges, context_stack, visited }
-    }
-
-    /// For each loop on the loop context stack (top-down), yields a list of BCBs
-    /// within that loop that have an outgoing edge back to the loop header.
-    pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator<Item = &[BasicCoverageBlock]> {
-        self.context_stack
-            .iter()
-            .rev()
-            .filter_map(|context| context.loop_header)
-            .map(|header_bcb| self.backedges[header_bcb].as_slice())
+        Self { basic_coverage_blocks, context_stack, visited }
     }
 
     pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> {
@@ -488,7 +538,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
             }
             debug!("Visiting {bcb:?}");
 
-            if self.backedges[bcb].len() > 0 {
+            if self.basic_coverage_blocks.is_loop_header.contains(bcb) {
                 debug!("{bcb:?} is a loop header! Start a new TraversalContext...");
                 self.context_stack
                     .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() });
@@ -566,29 +616,6 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
     }
 }
 
-fn find_loop_backedges(
-    basic_coverage_blocks: &CoverageGraph,
-) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> {
-    let num_bcbs = basic_coverage_blocks.num_nodes();
-    let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs);
-
-    // Identify loops by their backedges.
-    for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
-        for &successor in &basic_coverage_blocks.successors[bcb] {
-            if basic_coverage_blocks.dominates(successor, bcb) {
-                let loop_header = successor;
-                let backedge_from_bcb = bcb;
-                debug!(
-                    "Found BCB backedge: {:?} -> loop_header: {:?}",
-                    backedge_from_bcb, loop_header
-                );
-                backedges[loop_header].push(backedge_from_bcb);
-            }
-        }
-    }
-    backedges
-}
-
 fn short_circuit_preorder<'a, 'tcx, F, Iter>(
     body: &'a mir::Body<'tcx>,
     filtered_successors: F,
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 002216f50f2..07263460733 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -59,7 +59,7 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
         // Perform the actual dataflow analysis.
         let analysis = ConstAnalysis::new(tcx, body, map);
         let mut results = debug_span!("analyze")
-            .in_scope(|| analysis.wrap().into_engine(tcx, body).iterate_to_fixpoint());
+            .in_scope(|| analysis.wrap().iterate_to_fixpoint(tcx, body, None));
 
         // Collect results and patch the body afterwards.
         let mut visitor = Collector::new(tcx, &body.local_decls);
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index edffe6ce78f..2898f82e25c 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -37,8 +37,7 @@ fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     always_live.union(&borrowed_locals);
 
     let mut live = MaybeTransitiveLiveLocals::new(&always_live)
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // For blocks with a call terminator, if an argument copy can be turned into a move,
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index ad83c0295ba..beeab0d4a66 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -169,10 +169,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
 
         let borrowed = rustc_mir_dataflow::impls::borrowed_locals(body);
 
-        let live = MaybeLiveLocals
-            .into_engine(tcx, body)
-            .pass_name("MaybeLiveLocals-DestinationPropagation")
-            .iterate_to_fixpoint();
+        let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp"));
         let points = DenseLocationMap::new(body);
         let mut live = save_as_intervals(&points, body, live);
 
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 30e1ac05e03..58e1db19438 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -64,18 +64,14 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
 
             let mut inits = MaybeInitializedPlaces::new(tcx, body, &env.move_data)
                 .skipping_unreachable_unwind()
-                .into_engine(tcx, body)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
                 .into_results_cursor(body);
             let dead_unwinds = compute_dead_unwinds(body, &mut inits);
 
             let uninits = MaybeUninitializedPlaces::new(tcx, body, &env.move_data)
                 .mark_inactive_variants_as_uninit()
                 .skipping_unreachable_unwind(dead_unwinds)
-                .into_engine(tcx, body)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
+                .iterate_to_fixpoint(tcx, body, Some("elaborate_drops"))
                 .into_results_cursor(body);
 
             let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs
index 23733994a8b..d8ff1cfc90b 100644
--- a/compiler/rustc_mir_transform/src/lint.rs
+++ b/compiler/rustc_mir_transform/src/lint.rs
@@ -17,13 +17,11 @@ pub(super) fn lint_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: String
     let always_live_locals = &always_storage_live_locals(body);
 
     let maybe_storage_live = MaybeStorageLive::new(Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     let maybe_storage_dead = MaybeStorageDead::new(Cow::Borrowed(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     let mut lint = Lint {
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 53e53d9d5ba..b11b503e8d4 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -126,8 +126,7 @@ fn compute_replacement<'tcx>(
     // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is
     // definitely live.
     let mut maybe_dead = MaybeStorageDead::new(Cow::Owned(always_live_locals))
-        .into_engine(tcx, body)
-        .iterate_to_fixpoint()
+        .iterate_to_fixpoint(tcx, body, None)
         .into_results_cursor(body);
 
     // Map for each local to the pointee.
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 09969a4c7cc..55dd96100b0 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -22,9 +22,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
         let move_data = MoveData::gather_moves(body, tcx, |ty| ty.needs_drop(tcx, param_env));
 
         let mut maybe_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-            .into_engine(tcx, body)
-            .pass_name("remove_uninit_drops")
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(tcx, body, Some("remove_uninit_drops"))
             .into_results_cursor(body);
 
         let mut to_remove = vec![];
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 5612e779d6b..3011af4d9d7 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -1,5 +1,6 @@
 //! A pass that eliminates branches on uninhabited or unreachable enum variants.
 
+use rustc_abi::Variants;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::mir::patch::MirPatch;
@@ -9,7 +10,6 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_target::abi::{Abi, Variants};
 use tracing::trace;
 
 pub(super) struct UnreachableEnumBranching;
@@ -65,7 +65,7 @@ fn variant_discriminants<'tcx>(
         Variants::Multiple { variants, .. } => variants
             .iter_enumerated()
             .filter_map(|(idx, layout)| {
-                (layout.abi != Abi::Uninhabited)
+                (!layout.is_uninhabited())
                     .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
             })
             .collect(),
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 25e68f44456..77356723c46 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -12,7 +12,7 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{
     self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
-    Variance,
+    TypingMode, Variance,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{FIRST_VARIANT, Size};
@@ -606,7 +606,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
-        let infcx = self.tcx.infer_ctxt().build();
+        let infcx = self.tcx.infer_ctxt().build(TypingMode::from_param_env(self.param_env));
         let ocx = ObligationCtxt::new(&infcx);
         ocx.register_obligation(Obligation::new(
             self.tcx,
diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs
index 4da1e7fa711..f7fbfed5b8e 100644
--- a/compiler/rustc_next_trait_solver/src/delegate.rs
+++ b/compiler/rustc_next_trait_solver/src/delegate.rs
@@ -1,7 +1,7 @@
 use std::ops::Deref;
 
 use rustc_type_ir::fold::TypeFoldable;
-use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode};
+use rustc_type_ir::solve::{Certainty, Goal, NoSolution};
 use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
 
 pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Sized {
@@ -15,7 +15,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
 
     fn build_with_canonical<V>(
         cx: Self::Interner,
-        solver_mode: SolverMode,
         canonical: &ty::CanonicalQueryInput<Self::Interner, V>,
     ) -> (Self, V, ty::CanonicalVarValues<Self::Interner>)
     where
@@ -93,7 +92,6 @@ pub trait SolverDelegate: Deref<Target = <Self as SolverDelegate>::Infcx> + Size
 
     fn fetch_eligible_assoc_item(
         &self,
-        param_env: <Self::Interner as Interner>::ParamEnv,
         goal_trait_ref: ty::TraitRef<Self::Interner>,
         trait_assoc_def_id: <Self::Interner as Interner>::DefId,
         impl_def_id: <Self::Interner as Interner>::DefId,
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 f6a5f20a639..ebf7372926f 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -8,14 +8,14 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::solve::inspect;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, Upcast as _, elaborate};
+use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate};
 use tracing::{debug, instrument};
 
 use crate::delegate::SolverDelegate;
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, CanonicalResponse, Certainty, EvalCtxt, Goal, GoalSource,
-    MaybeCause, NoSolution, QueryResult, SolverMode,
+    MaybeCause, NoSolution, QueryResult,
 };
 
 /// A candidate is a possible way to prove a goal.
@@ -328,11 +328,12 @@ where
 
         let mut candidates = vec![];
 
-        if self.solver_mode() == SolverMode::Coherence {
+        if let TypingMode::Coherence = self.typing_mode(goal.param_env) {
             if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
                 return vec![candidate];
             }
         }
+
         self.assemble_impl_candidates(goal, &mut candidates);
 
         self.assemble_builtin_impl_candidates(goal, &mut candidates);
@@ -343,8 +344,11 @@ where
 
         self.assemble_param_env_candidates(goal, &mut candidates);
 
-        if self.solver_mode() == SolverMode::Normal {
-            self.discard_impls_shadowed_by_env(goal, &mut candidates);
+        match self.typing_mode(goal.param_env) {
+            TypingMode::Coherence => {}
+            TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
+                self.discard_impls_shadowed_by_env(goal, &mut candidates);
+            }
         }
 
         candidates
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index e2fd0dd2a25..2f50070d438 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -55,6 +55,7 @@ where
         &self,
         goal: Goal<I, T>,
     ) -> (Vec<I::GenericArg>, CanonicalInput<I, T>) {
+        let param_env_for_debug_assertion = goal.param_env;
         let opaque_types = self.delegate.clone_opaque_types_for_query_response();
         let (goal, opaque_types) =
             (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate));
@@ -73,7 +74,7 @@ where
         );
         let query_input = ty::CanonicalQueryInput {
             canonical,
-            defining_opaque_types: self.delegate.defining_opaque_types(),
+            typing_mode: self.typing_mode(param_env_for_debug_assertion),
         };
         (orig_values, query_input)
     }
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 7608253882a..8685896715e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -10,7 +10,7 @@ use rustc_type_ir::inherent::*;
 use rustc_type_ir::relate::Relate;
 use rustc_type_ir::relate::solver_relating::RelateExt;
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner};
+use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use tracing::{instrument, trace};
 
@@ -21,7 +21,6 @@ use crate::solve::search_graph::SearchGraph;
 use crate::solve::{
     CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource,
     HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult,
-    SolverMode,
 };
 
 pub(super) mod canonical;
@@ -215,8 +214,8 @@ where
     D: SolverDelegate<Interner = I>,
     I: Interner,
 {
-    pub(super) fn solver_mode(&self) -> SolverMode {
-        self.search_graph.solver_mode()
+    pub(super) fn typing_mode(&self, param_env_for_debug_assertion: I::ParamEnv) -> TypingMode<I> {
+        self.delegate.typing_mode(param_env_for_debug_assertion)
     }
 
     pub(super) fn set_is_normalizes_to_goal(&mut self) {
@@ -232,7 +231,7 @@ where
         generate_proof_tree: GenerateProofTree,
         f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
     ) -> (R, Option<inspect::GoalEvaluation<I>>) {
-        let mut search_graph = SearchGraph::new(delegate.solver_mode(), root_depth);
+        let mut search_graph = SearchGraph::new(root_depth);
 
         let mut ecx = EvalCtxt {
             delegate,
@@ -279,7 +278,7 @@ where
         f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal<I, I::Predicate>) -> R,
     ) -> R {
         let (ref delegate, input, var_values) =
-            SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input);
+            SolverDelegate::build_with_canonical(cx, &canonical_input);
 
         let mut ecx = EvalCtxt {
             delegate,
@@ -942,21 +941,11 @@ where
 
     pub(super) fn fetch_eligible_assoc_item(
         &self,
-        param_env: I::ParamEnv,
         goal_trait_ref: ty::TraitRef<I>,
         trait_assoc_def_id: I::DefId,
         impl_def_id: I::DefId,
     ) -> Result<Option<I::DefId>, NoSolution> {
-        self.delegate.fetch_eligible_assoc_item(
-            param_env,
-            goal_trait_ref,
-            trait_assoc_def_id,
-            impl_def_id,
-        )
-    }
-
-    pub(super) fn can_define_opaque_ty(&self, def_id: I::LocalDefId) -> bool {
-        self.delegate.defining_opaque_types().contains(&def_id)
+        self.delegate.fetch_eligible_assoc_item(goal_trait_ref, trait_assoc_def_id, impl_def_id)
     }
 
     pub(super) fn insert_hidden_type(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 7287cdf74bf..129744b4db7 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -6,7 +6,7 @@ mod weak_types;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::{self as ty, Interner, NormalizesTo, Upcast as _};
+use rustc_type_ir::{self as ty, Interner, NormalizesTo, TypingMode, Upcast as _};
 use tracing::instrument;
 
 use crate::delegate::SolverDelegate;
@@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate};
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, QueryResult, Reveal,
+    NoSolution, QueryResult,
 };
 
 impl<D, I> EvalCtxt<'_, D>
@@ -71,21 +71,21 @@ where
                 Ok(())
             }
             ty::AliasTermKind::OpaqueTy => {
-                match param_env.reveal() {
-                    // In user-facing mode, paques are only rigid if we may not define it.
-                    Reveal::UserFacing => {
+                match self.typing_mode(param_env) {
+                    // Opaques are never rigid outside of analysis mode.
+                    TypingMode::Coherence | TypingMode::PostAnalysis => Err(NoSolution),
+                    // During analysis, opaques are only rigid if we may not define it.
+                    TypingMode::Analysis { defining_opaque_types } => {
                         if rigid_alias
                             .def_id
                             .as_local()
-                            .is_some_and(|def_id| self.can_define_opaque_ty(def_id))
+                            .is_some_and(|def_id| defining_opaque_types.contains(&def_id))
                         {
                             Err(NoSolution)
                         } else {
                             Ok(())
                         }
                     }
-                    // Opaques are never rigid in reveal-all mode.
-                    Reveal::All => Err(NoSolution),
                 }
             }
             // FIXME(generic_const_exprs): we would need to support generic consts here
@@ -252,7 +252,6 @@ where
             // return ambiguity this would otherwise be incomplete, resulting in
             // unsoundness during coherence (#105782).
             let Some(target_item_def_id) = ecx.fetch_eligible_assoc_item(
-                goal.param_env,
                 goal_trait_ref,
                 goal.predicate.def_id(),
                 impl_def_id,
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index f8d51f304f3..d1d701695ab 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -4,12 +4,10 @@
 
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_type_ir::inherent::*;
-use rustc_type_ir::{self as ty, Interner};
+use rustc_type_ir::{self as ty, Interner, TypingMode};
 
 use crate::delegate::SolverDelegate;
-use crate::solve::{
-    Certainty, EvalCtxt, Goal, NoSolution, QueryResult, Reveal, SolverMode, inspect,
-};
+use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect};
 
 impl<D, I> EvalCtxt<'_, D>
 where
@@ -24,17 +22,27 @@ where
         let opaque_ty = goal.predicate.alias;
         let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const");
 
-        match (goal.param_env.reveal(), self.solver_mode()) {
-            (Reveal::UserFacing, SolverMode::Normal) => {
-                let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else {
+        match self.typing_mode(goal.param_env) {
+            TypingMode::Coherence => {
+                // An impossible opaque type bound is the only way this goal will fail
+                // e.g. assigning `impl Copy := NotCopy`
+                self.add_item_bounds_for_hidden_type(
+                    opaque_ty.def_id,
+                    opaque_ty.args,
+                    goal.param_env,
+                    expected,
+                );
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+            }
+            TypingMode::Analysis { defining_opaque_types } => {
+                let Some(def_id) = opaque_ty.def_id.as_local() else {
                     return Err(NoSolution);
                 };
-                // FIXME: at some point we should call queries without defining
-                // new opaque types but having the existing opaque type definitions.
-                // This will require moving this below "Prefer opaques registered already".
-                if !self.can_define_opaque_ty(opaque_ty_def_id) {
+
+                if !defining_opaque_types.contains(&def_id) {
                     return Err(NoSolution);
                 }
+
                 // FIXME: This may have issues when the args contain aliases...
                 match uses_unique_placeholders_ignoring_regions(self.cx(), opaque_ty.args) {
                     Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
@@ -48,8 +56,7 @@ where
                     Ok(()) => {}
                 }
                 // Prefer opaques registered already.
-                let opaque_type_key =
-                    ty::OpaqueTypeKey { def_id: opaque_ty_def_id, args: opaque_ty.args };
+                let opaque_type_key = ty::OpaqueTypeKey { def_id, args: opaque_ty.args };
                 // FIXME: This also unifies the previous hidden type with the expected.
                 //
                 // If that fails, we insert `expected` as a new hidden type instead of
@@ -69,7 +76,7 @@ where
                             }
                             ecx.eq(goal.param_env, candidate_ty, expected)?;
                             ecx.add_item_bounds_for_hidden_type(
-                                candidate_key.def_id.into(),
+                                def_id.into(),
                                 candidate_key.args,
                                 goal.param_env,
                                 candidate_ty,
@@ -82,25 +89,14 @@ where
                 // FIXME: should we use `inject_hidden_type_unchecked` here?
                 self.insert_hidden_type(opaque_type_key, goal.param_env, expected)?;
                 self.add_item_bounds_for_hidden_type(
-                    opaque_ty.def_id,
+                    def_id.into(),
                     opaque_ty.args,
                     goal.param_env,
                     expected,
                 );
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
-            (Reveal::UserFacing, SolverMode::Coherence) => {
-                // An impossible opaque type bound is the only way this goal will fail
-                // e.g. assigning `impl Copy := NotCopy`
-                self.add_item_bounds_for_hidden_type(
-                    opaque_ty.def_id,
-                    opaque_ty.args,
-                    goal.param_env,
-                    expected,
-                );
-                self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-            }
-            (Reveal::All, _) => {
+            TypingMode::PostAnalysis => {
                 // FIXME: Add an assertion that opaque type storage is empty.
                 let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args);
                 self.eq(goal.param_env, expected, actual)?;
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 08cc89d950e..e23e475a2a6 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -6,7 +6,7 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
 use rustc_type_ir::visit::TypeVisitableExt as _;
-use rustc_type_ir::{self as ty, Interner, TraitPredicate, Upcast as _, elaborate};
+use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate};
 use tracing::{instrument, trace};
 
 use crate::delegate::SolverDelegate;
@@ -15,7 +15,7 @@ use crate::solve::assembly::{self, Candidate};
 use crate::solve::inspect::ProbeKind;
 use crate::solve::{
     BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
-    NoSolution, QueryResult, Reveal, SolverMode,
+    NoSolution, QueryResult,
 };
 
 impl<D, I> assembly::GoalKind<D> for TraitPredicate<I>
@@ -67,9 +67,9 @@ where
         let maximal_certainty = match (impl_polarity, goal.predicate.polarity) {
             // In intercrate mode, this is ambiguous. But outside of intercrate,
             // it's not a real impl.
-            (ty::ImplPolarity::Reservation, _) => match ecx.solver_mode() {
-                SolverMode::Coherence => Certainty::AMBIGUOUS,
-                SolverMode::Normal => return Err(NoSolution),
+            (ty::ImplPolarity::Reservation, _) => match ecx.typing_mode(goal.param_env) {
+                TypingMode::Coherence => Certainty::AMBIGUOUS,
+                TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Err(NoSolution),
             },
 
             // Impl matches polarity
@@ -167,30 +167,26 @@ where
             return result;
         }
 
-        // Don't call `type_of` on a local TAIT that's in the defining scope,
-        // since that may require calling `typeck` on the same item we're
+        // We only look into opaque types during analysis for opaque types
+        // outside of their defining scope. Doing so for opaques in the
+        // defining scope may require calling `typeck` on the same item we're
         // currently type checking, which will result in a fatal cycle that
         // ideally we want to avoid, since we can make progress on this goal
         // via an alias bound or a locally-inferred hidden type instead.
-        //
-        // Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since
-        // we already normalize the self type in
-        // `assemble_candidates_after_normalizing_self_ty`, and we'd
-        // just be registering an identical candidate here.
-        //
-        // We always return `Err(NoSolution)` here in `SolverMode::Coherence`
-        // since we'll always register an ambiguous candidate in
-        // `assemble_candidates_after_normalizing_self_ty` due to normalizing
-        // the TAIT.
         if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
-            if matches!(goal.param_env.reveal(), Reveal::All)
-                || matches!(ecx.solver_mode(), SolverMode::Coherence)
-                || opaque_ty
-                    .def_id
-                    .as_local()
-                    .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
-            {
-                return Err(NoSolution);
+            match ecx.typing_mode(goal.param_env) {
+                TypingMode::Coherence | TypingMode::PostAnalysis => {
+                    unreachable!("rigid opaque outside of analysis: {goal:?}");
+                }
+                TypingMode::Analysis { defining_opaque_types } => {
+                    if opaque_ty
+                        .def_id
+                        .as_local()
+                        .is_some_and(|def_id| defining_opaque_types.contains(&def_id))
+                    {
+                        return Err(NoSolution);
+                    }
+                }
             }
         }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a9384501547..a1fe5508970 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -14,6 +14,7 @@ use rustc_ast::{
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PErr, PResult, Subdiagnostic,
     Suggestions, pluralize,
@@ -2437,7 +2438,7 @@ impl<'a> Parser<'a> {
         let mut labels = vec![];
         while let TokenKind::Interpolated(nt) = &tok.kind {
             let tokens = nt.tokens();
-            labels.push(nt.clone());
+            labels.push(Lrc::clone(nt));
             if let Some(tokens) = tokens
                 && let tokens = tokens.to_attr_token_stream()
                 && let tokens = tokens.0.deref()
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 77ad4fdeeb1..50a8b6542df 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -424,7 +424,7 @@ impl TokenDescription {
     }
 }
 
-pub(super) fn token_descr(token: &Token) -> String {
+pub fn token_descr(token: &Token) -> String {
     let name = pprust::token_to_string(token).to_string();
 
     let kind = match (TokenDescription::from_token(token), &token.kind) {
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index b45a8dae277..ed5991459ac 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_attr = { path = "../rustc_attr" }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index f8ef423a9b0..e5e70ba2033 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -622,6 +622,10 @@ passes_remove_fields =
 passes_repr_align_function =
     `repr(align)` attributes on functions are unstable
 
+passes_repr_align_greater_than_target_max =
+    alignment must not be greater than `isize::MAX` bytes
+    .note = `isize::MAX` is {$size} for the current target
+
 passes_repr_conflicting =
     conflicting representation hints
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index ed0d7ed8acc..0a2926c0404 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -25,7 +25,7 @@ use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
@@ -34,6 +34,7 @@ use rustc_session::lint::builtin::{
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{Symbol, kw, sym};
 use rustc_span::{BytePos, DUMMY_SP, Span};
+use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
@@ -262,7 +263,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | sym::cfg_attr
                     // need to be fixed
                     | sym::cfi_encoding // FIXME(cfi_encoding)
-                    | sym::pointee // FIXME(derive_smart_pointer)
+                    | sym::pointee // FIXME(derive_coerce_pointee)
                     | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
                     | sym::used // handled elsewhere to restrict to static items
                     | sym::repr // handled elsewhere to restrict to type decls items
@@ -1785,7 +1786,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | Target::Union
                         | Target::Enum
                         | Target::Fn
-                        | Target::Method(_) => continue,
+                        | Target::Method(_) => {}
                         _ => {
                             self.dcx().emit_err(
                                 errors::AttrApplication::StructEnumFunctionMethodUnion {
@@ -1795,6 +1796,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             );
                         }
                     }
+
+                    self.check_align_value(hint);
                 }
                 sym::packed => {
                     if target != Target::Struct && target != Target::Union {
@@ -1892,6 +1895,45 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
+    fn check_align_value(&self, item: &MetaItemInner) {
+        match item.singleton_lit_list() {
+            Some((
+                _,
+                MetaItemLit {
+                    kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), ..
+                },
+            )) => {
+                let val = literal.get() as u64;
+                if val > 2_u64.pow(29) {
+                    // for values greater than 2^29, a different error will be emitted, make sure that happens
+                    self.dcx().span_delayed_bug(
+                        item.span(),
+                        "alignment greater than 2^29 should be errored on elsewhere",
+                    );
+                } else {
+                    // only do this check when <= 2^29 to prevent duplicate errors:
+                    // alignment greater than 2^29 not supported
+                    // alignment is too large for the current target
+
+                    let max =
+                        Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
+                    if val > max {
+                        self.dcx().emit_err(errors::InvalidReprAlignForTarget {
+                            span: item.span(),
+                            size: max,
+                        });
+                    }
+                }
+            }
+
+            // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None
+            // but an error will have already been emitted, so this code should just skip such attributes
+            Some((_, _)) | None => {
+                self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))");
+            }
+        }
+    }
+
     fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
         let mut used_linker_span = None;
         let mut used_compiler_span = None;
@@ -2225,7 +2267,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let def_id = hir_id.expect_owner().def_id;
         let param_env = ty::ParamEnv::empty();
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
 
         let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index af17fbf7e4d..b1db66fa52d 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -7,6 +7,7 @@ use std::mem;
 
 use hir::ItemKind;
 use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
+use rustc_abi::FieldIdx;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::MultiSpan;
 use rustc_hir as hir;
@@ -22,7 +23,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_session::lint::builtin::DEAD_CODE;
 use rustc_span::symbol::{Symbol, sym};
-use rustc_target::abi::FieldIdx;
 
 use crate::errors::{
     ChangeFields, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo, UselessAssignment,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b5f1eac1cba..8bd767c1243 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -567,6 +567,15 @@ pub(crate) struct ReprConflicting {
     pub hint_spans: Vec<Span>,
 }
 
+#[derive(Diagnostic)]
+#[diag(passes_repr_align_greater_than_target_max, code = E0589)]
+#[note]
+pub(crate) struct InvalidReprAlignForTarget {
+    #[primary_span]
+    pub span: Span,
+    pub size: u64,
+}
+
 #[derive(LintDiagnostic)]
 #[diag(passes_repr_conflicting, code = E0566)]
 pub(crate) struct ReprConflictingLint;
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 93729a7f6df..921a915d05b 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -1,13 +1,14 @@
+use rustc_abi::{HasDataLayout, TargetDataLayout};
 use rustc_ast::Attribute;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::infer::canonical::ir::TypingMode;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers};
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
-use rustc_target::abi::{HasDataLayout, TargetDataLayout};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits;
@@ -54,7 +55,7 @@ pub fn ensure_wf<'tcx>(
         param_env,
         pred,
     );
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
     ocx.register_obligation(obligation);
     let errors = ocx.select_all_or_error();
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 466ea32735b..f69cc74fba2 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -189,9 +189,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             && let Some(fn_sig) = fn_sig
             && const_stab.is_const_stable()
             && !stab.is_some_and(|(s, _)| s.is_stable())
-            // FIXME: we skip this check targets until
-            // <https://github.com/rust-lang/stdarch/pull/1654> propagates.
-            && false
         {
             self.tcx
                 .dcx()
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index 34fb1bdf6fa..f98e4243375 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -6,6 +6,8 @@ edition = "2021"
 [dependencies]
 # tidy-alphabetical-start
 rustc-hash = "2.0.0"
+
+rustc_abi = { path = "../rustc_abi", optional = true }
 rustc_apfloat = "0.2.0"
 rustc_arena = { path = "../rustc_arena", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures", optional = true }
@@ -29,6 +31,7 @@ tracing-tree = "0.3.0"
 [features]
 default = ["rustc"]
 rustc = [
+    "dep:rustc_abi",
     "dep:rustc_arena",
     "dep:rustc_data_structures",
     "dep:rustc_errors",
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 0e132b27fb4..9ea5023064c 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -1,6 +1,7 @@
 use std::fmt;
 use std::iter::once;
 
+use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
 use rustc_arena::DroplessArena;
 use rustc_hir::HirId;
 use rustc_hir::def_id::DefId;
@@ -15,7 +16,6 @@ use rustc_middle::ty::{
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
 
 use crate::constructor::Constructor::*;
 use crate::constructor::{
diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs
index 17e389df17e..7649f72f868 100644
--- a/compiler/rustc_pattern_analysis/src/rustc/print.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs
@@ -11,10 +11,10 @@
 
 use std::fmt;
 
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_middle::bug;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_span::sym;
-use rustc_target::abi::{FieldIdx, VariantIdx};
 
 #[derive(Clone, Debug)]
 pub(crate) struct FieldPat {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index cd7725d2d70..5e30f17d626 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -134,7 +134,7 @@ impl<D: Deps> DepGraph<D> {
             encoder,
             record_graph,
             record_stats,
-            prev_graph.clone(),
+            Arc::clone(&prev_graph),
         );
 
         let colors = DepNodeColorMap::new(prev_graph_node_count);
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index ca3efc11201..5af41b9e687 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -237,7 +237,7 @@ impl QueryLatch {
             // the `wait` call below, by 1) the `set` method or 2) by deadlock detection.
             // Both of these will remove it from the `waiters` list before resuming
             // this thread.
-            info.waiters.push(waiter.clone());
+            info.waiters.push(Arc::clone(waiter));
 
             // If this detects a deadlock and the deadlock handler wants to resume this thread
             // we have to be in the `wait` call. This is ensured by the deadlock handler
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 031ffaed808..bdf940a04b5 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -177,7 +177,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx);
         let macro_data = match loaded_macro {
-            LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition),
+            LoadedMacro::MacroDef { def, ident, attrs, span, edition } => {
+                self.compile_macro(&def, ident, &attrs, span, ast::DUMMY_NODE_ID, edition)
+            }
             LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)),
         };
 
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 0047f2c4b51..a825458dc89 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -199,8 +199,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
             },
             ItemKind::Const(..) => DefKind::Const,
             ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
-            ItemKind::MacroDef(..) => {
-                let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition());
+            ItemKind::MacroDef(def) => {
+                let edition = self.resolver.tcx.sess.edition();
+                let macro_data =
+                    self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition);
                 let macro_kind = macro_data.ext.macro_kind();
                 opt_macro_data = Some(macro_data);
                 DefKind::Macro(macro_kind)
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index adb0ba7c820..f4a85c358e3 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -841,10 +841,9 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
                 visit::walk_ty(self, ty)
             }
-            TyKind::ImplTrait(node_id, _) => {
+            TyKind::ImplTrait(..) => {
                 let candidates = self.lifetime_elision_candidates.take();
                 visit::walk_ty(self, ty);
-                self.record_lifetime_params_for_impl_trait(*node_id);
                 self.lifetime_elision_candidates = candidates;
             }
             TyKind::TraitObject(bounds, ..) => {
@@ -977,14 +976,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                             sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
                             &sig.decl.output,
                         );
-
-                        if let Some((coro_node_id, _)) = sig
-                            .header
-                            .coroutine_kind
-                            .map(|coroutine_kind| coroutine_kind.return_id())
-                        {
-                            this.record_lifetime_params_for_impl_trait(coro_node_id);
-                        }
                     },
                 );
                 return;
@@ -1026,10 +1017,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                                         .map(|Param { pat, ty, .. }| (Some(&**pat), &**ty)),
                                     &declaration.output,
                                 );
-
-                                if let Some((async_node_id, _)) = coro_node_id {
-                                    this.record_lifetime_params_for_impl_trait(async_node_id);
-                                }
                             },
                         );
 
@@ -1220,7 +1207,6 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
                 }
             },
             AssocItemConstraintKind::Bound { ref bounds } => {
-                self.record_lifetime_params_for_impl_trait(constraint.id);
                 walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
             }
         }
@@ -4795,30 +4781,6 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         )
     }
 
-    /// Construct the list of in-scope lifetime parameters for impl trait lowering.
-    /// We include all lifetime parameters, either named or "Fresh".
-    /// The order of those parameters does not matter, as long as it is
-    /// deterministic.
-    fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) {
-        let mut extra_lifetime_params = vec![];
-
-        for rib in self.lifetime_ribs.iter().rev() {
-            extra_lifetime_params
-                .extend(rib.bindings.iter().map(|(&ident, &(node_id, res))| (ident, node_id, res)));
-            match rib.kind {
-                LifetimeRibKind::Item => break,
-                LifetimeRibKind::AnonymousCreateParameter { binder, .. } => {
-                    if let Some(earlier_fresh) = self.r.extra_lifetime_params_map.get(&binder) {
-                        extra_lifetime_params.extend(earlier_fresh);
-                    }
-                }
-                _ => {}
-            }
-        }
-
-        self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
-    }
-
     fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> {
         // FIXME: This caching may be incorrect in case of multiple `macro_rules`
         // items with the same name in the same module.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 35d491cfc18..9abb3180388 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1694,9 +1694,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
     fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
         match macro_kind {
-            MacroKind::Bang => self.dummy_ext_bang.clone(),
-            MacroKind::Derive => self.dummy_ext_derive.clone(),
-            MacroKind::Attr => self.non_macro_attr.ext.clone(),
+            MacroKind::Bang => Lrc::clone(&self.dummy_ext_bang),
+            MacroKind::Derive => Lrc::clone(&self.dummy_ext_derive),
+            MacroKind::Attr => Lrc::clone(&self.non_macro_attr.ext),
         }
     }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index a9ebffea8a1..0b4d0e04c29 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -826,7 +826,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
                 _ => None,
             },
-            None => self.get_macro(res).map(|macro_data| macro_data.ext.clone()),
+            None => self.get_macro(res).map(|macro_data| Lrc::clone(&macro_data.ext)),
         };
         Ok((ext, res))
     }
@@ -1122,9 +1122,25 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     /// Compile the macro into a `SyntaxExtension` and its rule spans.
     ///
     /// Possibly replace its expander to a pre-defined one for built-in macros.
-    pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData {
-        let (mut ext, mut rule_spans) =
-            compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
+    pub(crate) fn compile_macro(
+        &mut self,
+        macro_def: &ast::MacroDef,
+        ident: Ident,
+        attrs: &[ast::Attribute],
+        span: Span,
+        node_id: NodeId,
+        edition: Edition,
+    ) -> MacroData {
+        let (mut ext, mut rule_spans) = compile_declarative_macro(
+            self.tcx.sess,
+            self.tcx.features(),
+            macro_def,
+            ident,
+            attrs,
+            span,
+            node_id,
+            edition,
+        );
 
         if let Some(builtin_name) = ext.builtin_name {
             // The macro was marked with `#[rustc_builtin_macro]`.
@@ -1132,28 +1148,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 // The macro is a built-in, replace its expander function
                 // while still taking everything else from the source code.
                 // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
-                match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
+                match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(span)) {
                     BuiltinMacroState::NotYetSeen(builtin_ext) => {
                         ext.kind = builtin_ext;
                         rule_spans = Vec::new();
                     }
-                    BuiltinMacroState::AlreadySeen(span) => {
-                        self.dcx().emit_err(errors::AttemptToDefineBuiltinMacroTwice {
-                            span: item.span,
-                            note_span: span,
-                        });
+                    BuiltinMacroState::AlreadySeen(note_span) => {
+                        self.dcx()
+                            .emit_err(errors::AttemptToDefineBuiltinMacroTwice { span, note_span });
                     }
                 }
             } else {
-                self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName {
-                    span: item.span,
-                    ident: item.ident,
-                });
+                self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
             }
         }
 
-        let ItemKind::MacroDef(def) = &item.kind else { unreachable!() };
-        MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules }
+        MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: macro_def.macro_rules }
     }
 
     fn path_accessible(
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 75cc8f18a54..e9983699609 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -7,6 +7,7 @@ edition = "2021"
 # tidy-alphabetical-start
 bitflags = "2.4.1"
 getopts = "0.2"
+rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 7a32c0c2655..f3c21992784 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -1,10 +1,10 @@
 use std::cmp;
 
+use rustc_abi::{Align, Size};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lock;
 use rustc_span::Symbol;
 use rustc_span::def_id::DefId;
-use rustc_target::abi::{Align, Size};
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct VariantInfo {
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index ccc01728958..31ef2bda4f1 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -23,12 +23,12 @@
 use std::hash::Hash;
 use std::iter;
 
+use rustc_abi::Align;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS;
 use rustc_span::symbol::{Symbol, sym};
-use rustc_target::abi::Align;
 use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, TARGETS, Target, TargetTriple};
 
 use crate::Session;
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 4aae2649843..b3e3381d986 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -84,7 +84,7 @@ fn current_dll_path() -> Result<PathBuf, String> {
         loop {
             if libc::loadquery(
                 libc::L_GETINFO,
-                buffer.as_mut_ptr() as *mut i8,
+                buffer.as_mut_ptr() as *mut u8,
                 (std::mem::size_of::<libc::ld_info>() * buffer.len()) as u32,
             ) >= 0
             {
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 3d44810e7dd..f20ae85b8e8 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -241,7 +241,7 @@ impl ParseSess {
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let emitter = Box::new(
             HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle)
-                .sm(Some(sm.clone())),
+                .sm(Some(Lrc::clone(&sm))),
         );
         let dcx = DiagCtxt::new(emitter);
         ParseSess::with_dcx(dcx, sm)
@@ -278,7 +278,7 @@ impl ParseSess {
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let emitter = Box::new(HumanEmitter::new(
             stderr_destination(ColorConfig::Auto),
-            fallback_bundle.clone(),
+            Lrc::clone(&fallback_bundle),
         ));
         let fatal_dcx = DiagCtxt::new(emitter);
         let dcx = DiagCtxt::new(Box::new(SilentEmitter {
@@ -297,7 +297,7 @@ impl ParseSess {
     }
 
     pub fn clone_source_map(&self) -> Lrc<SourceMap> {
-        self.source_map.clone()
+        Lrc::clone(&self.source_map)
     }
 
     pub fn buffer_lint(
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1963cf4eb7c..45434534c75 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1036,7 +1036,8 @@ pub fn build_session(
         sopts.unstable_opts.translate_directionality_markers,
     );
     let source_map = rustc_span::source_map::get_source_map().unwrap();
-    let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
+    let emitter =
+        default_emitter(&sopts, registry, Lrc::clone(&source_map), bundle, fallback_bundle);
 
     let mut dcx =
         DiagCtxt::new(emitter).with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings));
@@ -1079,7 +1080,7 @@ pub fn build_session(
     let target_tlib_path = if host_triple == target_triple {
         // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary
         // rescanning of the target lib path and an unnecessary allocation.
-        host_tlib_path.clone()
+        Lrc::clone(&host_tlib_path)
     } else {
         Lrc::new(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
     };
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 55b47817f9a..a326e8583ea 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -170,7 +170,7 @@ impl<'tcx> Tables<'tcx> {
         stable_mir::mir::mono::StaticDef(self.create_def_id(did))
     }
 
-    pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
+    pub(crate) fn layout_id(&mut self, layout: rustc_abi::Layout<'tcx>) -> Layout {
         self.layouts.create_or_fetch(layout)
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 0d8740ae31f..5c09879f60e 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,3 +1,4 @@
+use rustc_abi::{Align, Size};
 use rustc_middle::mir::ConstValue;
 use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range};
 use stable_mir::Error;
@@ -7,7 +8,7 @@ use stable_mir::ty::{Allocation, ProvenanceMap};
 use crate::rustc_smir::{Stable, Tables};
 
 /// Creates new empty `Allocation` from given `Align`.
-fn new_empty_allocation(align: rustc_target::abi::Align) -> Allocation {
+fn new_empty_allocation(align: Align) -> Allocation {
     Allocation {
         bytes: Vec::new(),
         provenance: ProvenanceMap { ptrs: Vec::new() },
@@ -45,7 +46,7 @@ pub(crate) fn try_new_allocation<'tcx>(
                 .align;
             let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
             allocation
-                .write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
+                .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
                 .map_err(|e| e.stable(tables))?;
             allocation.stable(tables)
         }
@@ -59,7 +60,7 @@ pub(crate) fn try_new_allocation<'tcx>(
         }
         ConstValue::Slice { data, meta } => {
             let alloc_id = tables.tcx.reserve_and_set_memory_alloc(data);
-            let ptr = Pointer::new(alloc_id.into(), rustc_target::abi::Size::ZERO);
+            let ptr = Pointer::new(alloc_id.into(), Size::ZERO);
             let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
             let scalar_meta =
                 rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
@@ -72,7 +73,7 @@ pub(crate) fn try_new_allocation<'tcx>(
             allocation
                 .write_scalar(
                     &tables.tcx,
-                    alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
+                    alloc_range(Size::ZERO, tables.tcx.data_layout.pointer_size),
                     scalar_ptr,
                 )
                 .map_err(|e| e.stable(tables))?;
@@ -112,10 +113,7 @@ pub(super) fn allocation_filter<'tcx>(
         .map(Some)
         .collect();
     for (i, b) in bytes.iter_mut().enumerate() {
-        if !alloc
-            .init_mask()
-            .get(rustc_target::abi::Size::from_bytes(i + alloc_range.start.bytes_usize()))
-        {
+        if !alloc.init_mask().get(Size::from_bytes(i + alloc_range.start.bytes_usize())) {
             *b = None;
         }
     }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 06f01aebf9b..410bf0f40f4 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -1,9 +1,9 @@
-//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
+//! Conversion of internal Rust compiler `rustc_target` and `rustc_abi` items to stable ones.
 
 #![allow(rustc::usage_of_qualified_ty)]
 
 use rustc_middle::ty;
-use rustc_target::abi::call::Conv;
+use rustc_target::callconv::{self, Conv};
 use stable_mir::abi::{
     AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
     LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
@@ -15,7 +15,7 @@ use stable_mir::ty::{Align, IndexedVal, VariantIdx};
 
 use crate::rustc_smir::{Stable, Tables};
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
+impl<'tcx> Stable<'tcx> for rustc_abi::VariantIdx {
     type T = VariantIdx;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
         VariantIdx::to_val(self.as_usize())
@@ -33,7 +33,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for rustc_abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
     type T = TyAndLayout;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -41,7 +41,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::Layout<'tcx> {
     type T = Layout;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -49,9 +49,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
     }
 }
 
-impl<'tcx> Stable<'tcx>
-    for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
-{
+impl<'tcx> Stable<'tcx> for rustc_abi::LayoutData<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
     type T = LayoutShape;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -65,7 +63,7 @@ impl<'tcx> Stable<'tcx>
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for callconv::FnAbi<'tcx, ty::Ty<'tcx>> {
     type T = FnAbi;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -81,7 +79,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
+impl<'tcx> Stable<'tcx> for callconv::ArgAbi<'tcx, ty::Ty<'tcx>> {
     type T = ArgAbi;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -93,7 +91,7 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>>
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
+impl<'tcx> Stable<'tcx> for callconv::Conv {
     type T = CallConvention;
 
     fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
@@ -122,31 +120,29 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
+impl<'tcx> Stable<'tcx> for callconv::PassMode {
     type T = PassMode;
 
     fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
         match self {
-            rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
-            rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
-            rustc_target::abi::call::PassMode::Pair(first, second) => {
+            callconv::PassMode::Ignore => PassMode::Ignore,
+            callconv::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
+            callconv::PassMode::Pair(first, second) => {
                 PassMode::Pair(opaque(first), opaque(second))
             }
-            rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
+            callconv::PassMode::Cast { pad_i32, cast } => {
                 PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
             }
-            rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
-                PassMode::Indirect {
-                    attrs: opaque(attrs),
-                    meta_attrs: opaque(meta_attrs),
-                    on_stack: *on_stack,
-                }
-            }
+            callconv::PassMode::Indirect { attrs, meta_attrs, on_stack } => PassMode::Indirect {
+                attrs: opaque(attrs),
+                meta_attrs: opaque(meta_attrs),
+                on_stack: *on_stack,
+            },
         }
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_abi::FieldIdx> {
     type T = FieldsShape;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -163,9 +159,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx>
     }
 }
 
-impl<'tcx> Stable<'tcx>
-    for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
-{
+impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::VariantIdx> {
     type T = VariantsShape;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
@@ -185,7 +179,7 @@ impl<'tcx> Stable<'tcx>
     }
 }
 
-impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
+impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_abi::VariantIdx> {
     type T = TagEncoding;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index dbae4b7e719..820d8a6be25 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -691,11 +691,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation {
     type T = stable_mir::ty::Allocation;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        alloc::allocation_filter(
-            self,
-            alloc_range(rustc_target::abi::Size::ZERO, self.size()),
-            tables,
-        )
+        alloc::allocation_filter(self, alloc_range(rustc_abi::Size::ZERO, self.size()), tables)
     }
 }
 
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 9b27b94fb5a..9032156b257 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -36,7 +36,7 @@ pub struct Tables<'tcx> {
     pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
     pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>,
     pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>,
-    pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
+    pub(crate) layouts: IndexMap<rustc_abi::Layout<'tcx>, Layout>,
 }
 
 impl<'tcx> Tables<'tcx> {
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 26aa782e5d7..9f977b98b82 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -63,7 +63,7 @@ pub struct CachingSourceMapView<'sm> {
 impl<'sm> CachingSourceMapView<'sm> {
     pub fn new(source_map: &'sm SourceMap) -> CachingSourceMapView<'sm> {
         let files = source_map.files();
-        let first_file = files[0].clone();
+        let first_file = Lrc::clone(&files[0]);
         let entry = CacheEntry {
             time_stamp: 0,
             line_number: 0,
@@ -92,7 +92,7 @@ impl<'sm> CachingSourceMapView<'sm> {
             cache_entry.touch(self.time_stamp);
 
             let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
-            return Some((cache_entry.file.clone(), cache_entry.line_number, col));
+            return Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col));
         }
 
         // No cache hit ...
@@ -109,7 +109,7 @@ impl<'sm> CachingSourceMapView<'sm> {
         cache_entry.update(new_file_and_idx, pos, self.time_stamp);
 
         let col = RelativeBytePos(pos.to_u32() - cache_entry.line.start.to_u32());
-        Some((cache_entry.file.clone(), cache_entry.line_number, col))
+        Some((Lrc::clone(&cache_entry.file), cache_entry.line_number, col))
     }
 
     pub fn span_data_to_lines_and_cols(
@@ -133,7 +133,7 @@ impl<'sm> CachingSourceMapView<'sm> {
                 }
 
                 (
-                    lo.file.clone(),
+                    Lrc::clone(&lo.file),
                     lo.line_number,
                     span_data.lo - lo.line.start,
                     hi.line_number,
@@ -181,7 +181,7 @@ impl<'sm> CachingSourceMapView<'sm> {
                 lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
 
                 if !lo.line.contains(&span_data.hi) {
-                    let new_file_and_idx = Some((lo.file.clone(), lo.file_index));
+                    let new_file_and_idx = Some((Lrc::clone(&lo.file), lo.file_index));
                     let next_oldest = self.oldest_cache_entry_index_avoid(oldest);
                     let hi = &mut self.line_cache[next_oldest];
                     hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
@@ -227,7 +227,7 @@ impl<'sm> CachingSourceMapView<'sm> {
         assert_eq!(lo.file_index, hi.file_index);
 
         Some((
-            lo.file.clone(),
+            Lrc::clone(&lo.file),
             lo.line_number,
             span_data.lo - lo.line.start,
             hi.line_number,
@@ -277,7 +277,7 @@ impl<'sm> CachingSourceMapView<'sm> {
             let file = &self.source_map.files()[file_idx];
 
             if file_contains(file, pos) {
-                return Some((file.clone(), file_idx));
+                return Some((Lrc::clone(file), file_idx));
             }
         }
 
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 8a023305937..f36bb38623e 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -286,8 +286,8 @@ impl SourceMap {
         });
 
         let file = Lrc::new(file);
-        files.source_files.push(file.clone());
-        files.stable_id_to_source_file.insert(file_id, file.clone());
+        files.source_files.push(Lrc::clone(&file));
+        files.stable_id_to_source_file.insert(file_id, Lrc::clone(&file));
 
         Ok(file)
     }
@@ -386,7 +386,7 @@ impl SourceMap {
     /// Return the SourceFile that contains the given `BytePos`
     pub fn lookup_source_file(&self, pos: BytePos) -> Lrc<SourceFile> {
         let idx = self.lookup_source_file_idx(pos);
-        (*self.files.borrow().source_files)[idx].clone()
+        Lrc::clone(&(*self.files.borrow().source_files)[idx])
     }
 
     /// Looks up source information about a `BytePos`.
@@ -468,7 +468,7 @@ impl SourceMap {
         if lo != hi {
             return true;
         }
-        let f = (*self.files.borrow().source_files)[lo].clone();
+        let f = Lrc::clone(&(*self.files.borrow().source_files)[lo]);
         let lo = f.relative_position(sp.lo());
         let hi = f.relative_position(sp.hi());
         f.lookup_line(lo) != f.lookup_line(hi)
@@ -994,7 +994,7 @@ impl SourceMap {
         let filename = self.path_mapping().map_filename_prefix(filename).0;
         for sf in self.files.borrow().source_files.iter() {
             if filename == sf.name {
-                return Some(sf.clone());
+                return Some(Lrc::clone(&sf));
             }
         }
         None
@@ -1003,7 +1003,7 @@ impl SourceMap {
     /// For a global `BytePos`, computes the local offset within the containing `SourceFile`.
     pub fn lookup_byte_offset(&self, bpos: BytePos) -> SourceFileAndBytePos {
         let idx = self.lookup_source_file_idx(bpos);
-        let sf = (*self.files.borrow().source_files)[idx].clone();
+        let sf = Lrc::clone(&(*self.files.borrow().source_files)[idx]);
         let offset = bpos - sf.start_pos;
         SourceFileAndBytePos { sf, pos: offset }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 134a1a1db30..890c4fdafef 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -171,9 +171,11 @@ symbols! {
         CallOnceFuture,
         CallRefFuture,
         Capture,
+        Cell,
         Center,
         Cleanup,
         Clone,
+        CoercePointee,
         CoerceUnsized,
         Command,
         ConstParamTy,
@@ -307,7 +309,6 @@ symbols! {
         Sized,
         SliceIndex,
         SliceIter,
-        SmartPointer,
         Some,
         SpanCtxt,
         String,
@@ -409,6 +410,7 @@ symbols! {
         arm,
         arm_target_feature,
         array,
+        as_mut_ptr,
         as_ptr,
         as_ref,
         as_str,
@@ -732,6 +734,7 @@ symbols! {
         deref_pure,
         deref_target,
         derive,
+        derive_coerce_pointee,
         derive_const,
         derive_default_enum,
         derive_smart_pointer,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 65aa9e40c8b..644e710d1db 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -7,6 +7,8 @@ edition = "2021"
 # tidy-alphabetical-start
 punycode = "0.4.0"
 rustc-demangle = "0.1.21"
+
+rustc_abi = { path = "../rustc_abi" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index d092fa8f082..868345c7594 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -2,6 +2,7 @@ use std::fmt::Write;
 use std::iter;
 use std::ops::Range;
 
+use rustc_abi::Integer;
 use rustc_data_structures::base_n::ToBaseN;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::intern::Interned;
@@ -17,7 +18,6 @@ use rustc_middle::ty::{
     TyCtxt, TypeVisitable, TypeVisitableExt, UintTy,
 };
 use rustc_span::symbol::kw;
-use rustc_target::abi::Integer;
 use rustc_target::spec::abi::Abi;
 
 pub(super) fn mangle<'tcx>(
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 910cafbdf3b..3df8f0590a3 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -167,6 +167,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("pacg", Stable, &[]),
     // FEAT_PAN
     ("pan", Stable, &[]),
+    // FEAT_PAuth_LR
+    ("pauth-lr", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_PMUv3
     ("pmuv3", Stable, &[]),
     // FEAT_RNG
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index b9a569d25e3..574cf1e88b1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -392,7 +392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         Some(ty) if expected == ty => {
                             let source_map = self.tcx.sess.source_map();
                             err.span_suggestion(
-                                source_map.end_point(cause.span()),
+                                source_map.end_point(cause.span),
                                 "try removing this `?`",
                                 "",
                                 Applicability::MachineApplicable,
@@ -412,6 +412,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 source,
                 ref prior_non_diverging_arms,
                 scrut_span,
+                expr_span,
                 ..
             }) => match source {
                 hir::MatchSource::TryDesugar(scrut_hir_id) => {
@@ -430,7 +431,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             Some(ty) if expected == ty => {
                                 let source_map = self.tcx.sess.source_map();
                                 err.span_suggestion(
-                                    source_map.end_point(cause.span()),
+                                    source_map.end_point(cause.span),
                                     "try removing this `?`",
                                     "",
                                     Applicability::MachineApplicable,
@@ -460,12 +461,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             format!("this and all prior arms are found to be of type `{t}`"),
                         );
                     }
-                    let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
+                    let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) {
                         // Cover just `match` and the scrutinee expression, not
                         // the entire match body, to reduce diagram noise.
-                        cause.span.shrink_to_lo().to(scrut_span)
+                        expr_span.shrink_to_lo().to(scrut_span)
                     } else {
-                        cause.span
+                        expr_span
                     };
                     let msg = "`match` arms have incompatible types";
                     err.span_label(outer, msg);
@@ -1148,7 +1149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         terr: TypeError<'tcx>,
         prefer_label: bool,
     ) {
-        let span = cause.span();
+        let span = cause.span;
 
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
@@ -1642,7 +1643,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         terr: TypeError<'tcx>,
     ) -> Vec<TypeErrorAdditionalDiags> {
         let mut suggestions = Vec::new();
-        let span = trace.cause.span();
+        let span = trace.cause.span;
         let values = self.resolve_vars_if_possible(trace.values);
         if let Some((expected, found)) = values.ty() {
             match (expected.kind(), found.kind()) {
@@ -1792,7 +1793,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> Diag<'a> {
         debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr);
 
-        let span = trace.cause.span();
+        let span = trace.cause.span;
         let failure_code = trace.cause.as_failure_code_diag(
             terr,
             span,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
index 14c2bf19a9c..4398af76ab2 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs
@@ -237,7 +237,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
         expected_args: GenericArgsRef<'tcx>,
         actual_args: GenericArgsRef<'tcx>,
     ) -> Diag<'tcx> {
-        let span = cause.span();
+        let span = cause.span;
 
         let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
             if let ObligationCauseCode::WhereClause(def_id, span)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 8541621b23b..2b19db2c14e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -284,7 +284,7 @@ pub fn suggest_new_region_bound(
         }
         match fn_return.kind {
             // FIXME(precise_captures): Suggest adding to `use<...>` list instead.
-            TyKind::OpaqueDef(opaque, _) => {
+            TyKind::OpaqueDef(opaque) => {
                 // Get the identity type for this RPIT
                 let did = opaque.def_id.to_def_id();
                 let ty = Ty::new_opaque(tcx, did, ty::GenericArgs::identity_for_item(tcx, did));
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 833358b2e14..438639e72f9 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -862,22 +862,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     self.add_lt_suggs.push(lt.suggestion(self.new_lt));
                 }
             }
-
-            fn visit_ty(&mut self, ty: &'hir hir::Ty<'hir>) {
-                let hir::TyKind::OpaqueDef(opaque_ty, _) = ty.kind else {
-                    return hir::intravisit::walk_ty(self, ty);
-                };
-                if let Some(&(_, b)) =
-                    opaque_ty.lifetime_mapping.iter().find(|&(a, _)| a.res == self.needle)
-                {
-                    let prev_needle =
-                        std::mem::replace(&mut self.needle, hir::LifetimeName::Param(b));
-                    for bound in opaque_ty.bounds {
-                        self.visit_param_bound(bound);
-                    }
-                    self.needle = prev_needle;
-                }
-            }
         }
 
         let (lifetime_def_id, lifetime_scope) =
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index b7e2ed391cd..6014ed555b6 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1835,6 +1835,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     if impl_trait_ref.references_error() {
                         return false;
                     }
+                    let self_ty = impl_trait_ref.self_ty().to_string();
                     err.highlighted_help(vec![
                         StringPart::normal(format!(
                             "the trait `{}` ",
@@ -1842,16 +1843,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         )),
                         StringPart::highlighted("is"),
                         StringPart::normal(" implemented for `"),
-                        StringPart::highlighted(impl_trait_ref.self_ty().to_string()),
+                        if let [TypeError::Sorts(_)] = &terrs[..] {
+                            StringPart::normal(self_ty)
+                        } else {
+                            StringPart::highlighted(self_ty)
+                        },
                         StringPart::normal("`"),
                     ]);
 
                     if let [TypeError::Sorts(exp_found)] = &terrs[..] {
                         let exp_found = self.resolve_vars_if_possible(*exp_found);
-                        err.help(format!(
-                            "for that trait implementation, expected `{}`, found `{}`",
-                            exp_found.expected, exp_found.found
-                        ));
+                        err.highlighted_help(vec![
+                            StringPart::normal("for that trait implementation, "),
+                            StringPart::normal("expected `"),
+                            StringPart::highlighted(exp_found.expected.to_string()),
+                            StringPart::normal("`, found `"),
+                            StringPart::highlighted(exp_found.found.to_string()),
+                            StringPart::normal("`"),
+                        ]);
                     }
 
                     true
@@ -2160,6 +2169,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // First, attempt to add note to this error with an async-await-specific
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
+            let mut long_ty_file = None;
             self.note_obligation_cause_code(
                 obligation.cause.body_id,
                 err,
@@ -2168,7 +2178,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 obligation.cause.code(),
                 &mut vec![],
                 &mut Default::default(),
+                &mut long_ty_file,
             );
+            if let Some(file) = long_ty_file {
+                err.note(format!(
+                    "the full name for the type has been written to '{}'",
+                    file.display(),
+                ));
+                err.note("consider using `--verbose` to print the full type name to the console");
+            }
             self.suggest_unsized_bound_if_applicable(err, obligation);
             if let Some(span) = err.span.primary_span()
                 && let Some(mut diag) =
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index ca23f776581..b108a9352a5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -305,6 +305,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 if let ObligationCauseCode::WhereClause(..)
                 | ObligationCauseCode::WhereClauseInExpr(..) = code
                 {
+                    let mut long_ty_file = None;
                     self.note_obligation_cause_code(
                         error.obligation.cause.body_id,
                         &mut diag,
@@ -313,7 +314,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         code,
                         &mut vec![],
                         &mut Default::default(),
+                        &mut long_ty_file,
                     );
+                    if let Some(file) = long_ty_file {
+                        diag.note(format!(
+                            "the full name for the type has been written to '{}'",
+                            file.display(),
+                        ));
+                        diag.note(
+                            "consider using `--verbose` to print the full type name to the console",
+                        );
+                    }
                 }
                 diag.emit()
             }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
index f4c5733d4a6..c47c2169691 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs
@@ -144,6 +144,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             obligation.cause.span,
             suggest_increasing_limit,
             |err| {
+                let mut long_ty_file = None;
                 self.note_obligation_cause_code(
                     obligation.cause.body_id,
                     err,
@@ -152,7 +153,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     obligation.cause.code(),
                     &mut vec![],
                     &mut Default::default(),
+                    &mut long_ty_file,
                 );
+                if let Some(file) = long_ty_file {
+                    err.note(format!(
+                        "the full name for the type has been written to '{}'",
+                        file.display(),
+                    ));
+                    err.note(
+                        "consider using `--verbose` to print the full type name to the console",
+                    );
+                }
             },
         );
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 1fe93cb017a..19f5d609272 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3,6 +3,7 @@
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
+use std::path::PathBuf;
 
 use itertools::{EitherOrBoth, Itertools};
 use rustc_data_structures::fx::FxHashSet;
@@ -360,7 +361,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 })
                 | hir::Node::TraitItem(hir::TraitItem { generics, .. })
                 | hir::Node::ImplItem(hir::ImplItem { generics, .. })
-                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
                     if param_ty =>
                 {
                     // We skip the 0'th arg (self) because we do not want
@@ -423,10 +423,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         | hir::ItemKind::Const(_, generics, _)
                         | hir::ItemKind::TraitAlias(generics, _),
                     ..
-                })
-                | hir::Node::OpaqueTy(hir::OpaqueTy { generics, .. })
-                    if !param_ty =>
-                {
+                }) if !param_ty => {
                     // Missing generic type parameter bound.
                     if suggest_arbitrary_trait_bound(
                         self.tcx,
@@ -2703,6 +2700,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         // Add a note for the item obligation that remains - normally a note pointing to the
         // bound that introduced the obligation (e.g. `T: Send`).
         debug!(?next_code);
+        let mut long_ty_file = None;
         self.note_obligation_cause_code(
             obligation.cause.body_id,
             err,
@@ -2711,6 +2709,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             next_code.unwrap(),
             &mut Vec::new(),
             &mut Default::default(),
+            &mut long_ty_file,
         );
     }
 
@@ -2723,11 +2722,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
+        long_ty_file: &mut Option<PathBuf>,
     ) where
         T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     {
-        let mut long_ty_file = None;
-
         let tcx = self.tcx;
         let predicate = predicate.upcast(tcx);
         let suggest_remove_deref = |err: &mut Diag<'_, G>, expr: &hir::Expr<'_>| {
@@ -2957,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::Coercion { source, target } => {
                 let source =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file);
+                    tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file);
                 let target =
-                    tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut long_ty_file);
+                    tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file);
                 err.note(with_forced_trimmed_paths!(format!(
                     "required for the cast from `{source}` to `{target}`",
                 )));
@@ -3249,7 +3247,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 };
 
                 if !is_upvar_tys_infer_tuple {
-                    let ty_str = tcx.short_ty_string(ty, &mut long_ty_file);
+                    let ty_str = tcx.short_ty_string(ty, long_ty_file);
                     let msg = format!("required because it appears within the type `{ty_str}`");
                     match ty.kind() {
                         ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) {
@@ -3327,6 +3325,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             &data.parent_code,
                             obligated_types,
                             seen_requirements,
+                            long_ty_file,
                         )
                     });
                 } else {
@@ -3339,6 +3338,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
+                            long_ty_file,
                         )
                     });
                 }
@@ -3347,8 +3347,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let mut parent_trait_pred =
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
-                let self_ty_str = tcx
-                    .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut long_ty_file);
+                let self_ty_str =
+                    tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
                 let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
                 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
@@ -3444,10 +3444,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         count,
                         pluralize!(count)
                     ));
-                    let self_ty = tcx.short_ty_string(
-                        parent_trait_pred.skip_binder().self_ty(),
-                        &mut long_ty_file,
-                    );
+                    let self_ty = tcx
+                        .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file);
                     err.note(format!(
                         "required for `{self_ty}` to implement `{}`",
                         parent_trait_pred.print_modifiers_and_trait_path()
@@ -3463,6 +3461,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3479,6 +3478,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3493,6 +3493,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         nested,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
                 let mut multispan = MultiSpan::from(span);
@@ -3523,6 +3524,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         parent_code,
                         obligated_types,
                         seen_requirements,
+                        long_ty_file,
                     )
                 });
             }
@@ -3562,7 +3564,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::OpaqueReturnType(expr_info) => {
                 if let Some((expr_ty, hir_id)) = expr_info {
-                    let expr_ty = self.tcx.short_ty_string(expr_ty, &mut long_ty_file);
+                    let expr_ty = self.tcx.short_ty_string(expr_ty, long_ty_file);
                     let expr = self.infcx.tcx.hir().expect_expr(hir_id);
                     err.span_label(
                         expr.span,
@@ -3574,14 +3576,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
             }
         }
-
-        if let Some(file) = long_ty_file {
-            err.note(format!(
-                "the full name for the type has been written to '{}'",
-                file.display(),
-            ));
-            err.note("consider using `--verbose` to print the full type name to the console");
-        }
     }
 
     #[instrument(
@@ -5107,24 +5101,13 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
             _ => None,
         };
 
-        let pred = obligation.predicate;
-        let (_, base) = obligation.cause.code().peel_derives_with_predicate();
-        let post = if let ty::PredicateKind::Clause(clause) = pred.kind().skip_binder()
-            && let ty::ClauseKind::Trait(pred) = clause
-            && let Some(base) = base
-            && base.skip_binder() != pred
-        {
-            format!(", which is required by `{base}`")
-        } else {
-            String::new()
-        };
         let desc = match ty_desc {
             Some(desc) => format!(" {desc}"),
             None => String::new(),
         };
         if let ty::PredicatePolarity::Positive = trait_predicate.polarity() {
             format!(
-                "{pre_message}the trait `{}` is not implemented for{desc} `{}`{post}",
+                "{pre_message}the trait `{}` is not implemented for{desc} `{}`",
                 trait_predicate.print_modifiers_and_trait_path(),
                 tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None),
             )
@@ -5132,7 +5115,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>(
             // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is
             // not implemented for `T`".
             // FIXME: add note explaining explicit negative trait bounds.
-            format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied{post}")
+            format!("{pre_message}the trait bound `{trait_predicate}` is not satisfied")
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 5793ac2fc31..c53689b211d 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -7,13 +7,13 @@ use rustc_infer::infer::canonical::{
     Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
 };
 use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::solve::Goal;
-use rustc_infer::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
-use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode};
-use tracing::trace;
+use rustc_type_ir::TypingMode;
+use rustc_type_ir::solve::{Certainty, NoSolution};
 
 use crate::traits::specialization_graph;
 
@@ -47,7 +47,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     fn build_with_canonical<V>(
         interner: TyCtxt<'tcx>,
-        solver_mode: SolverMode,
         canonical: &CanonicalQueryInput<'tcx, V>,
     ) -> (Self, V, CanonicalVarValues<'tcx>)
     where
@@ -56,10 +55,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
         let (infcx, value, vars) = interner
             .infer_ctxt()
             .with_next_trait_solver(true)
-            .intercrate(match solver_mode {
-                SolverMode::Normal => false,
-                SolverMode::Coherence => true,
-            })
             .build_with_canonical(DUMMY_SP, canonical);
         (SolverDelegate(infcx), value, vars)
     }
@@ -195,7 +190,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
 
     fn fetch_eligible_assoc_item(
         &self,
-        param_env: ty::ParamEnv<'tcx>,
         goal_trait_ref: ty::TraitRef<'tcx>,
         trait_assoc_def_id: DefId,
         impl_def_id: DefId,
@@ -211,12 +205,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
             // and the obligation is monomorphic, otherwise passes such as
             // transmute checking and polymorphic MIR optimizations could
             // get a result which isn't correct for all monomorphizations.
-            if param_env.reveal() == Reveal::All {
-                let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
-                !poly_trait_ref.still_further_specializable()
-            } else {
-                trace!(?node_item.item.def_id, "not eligible due to default");
-                false
+            match self.typing_mode_unchecked() {
+                TypingMode::Coherence | TypingMode::Analysis { .. } => false,
+                TypingMode::PostAnalysis => {
+                    let poly_trait_ref = self.resolve_vars_if_possible(goal_trait_ref);
+                    !poly_trait_ref.still_further_specializable()
+                }
             }
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 934fe9ec47c..52ba5621d31 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -10,6 +10,7 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{Region, RegionVid};
 use tracing::debug;
+use ty::TypingMode;
 
 use super::*;
 use crate::errors::UnableToConstructConstantValue;
@@ -79,7 +80,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
 
         let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]);
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut selcx = SelectionContext::new(&infcx);
         for polarity in [ty::PredicatePolarity::Positive, ty::PredicatePolarity::Negative] {
             let result = selcx.select(&Obligation::new(
@@ -99,7 +100,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             }
         }
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let mut fresh_preds = FxIndexSet::default();
 
         // Due to the way projections are handled by SelectionContext, we need to run
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f8fb297e36c..3cd11d7c8e8 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -18,7 +18,7 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 pub use rustc_next_trait_solver::coherence::*;
 use rustc_next_trait_solver::solve::SolverDelegateEvalExt;
 use rustc_span::symbol::sym;
@@ -195,9 +195,8 @@ fn overlap<'tcx>(
     let infcx = tcx
         .infer_ctxt()
         .skip_leak_check(skip_leak_check.is_yes())
-        .intercrate(true)
         .with_next_trait_solver(tcx.next_trait_solver_in_coherence())
-        .build();
+        .build(TypingMode::Coherence);
     let selcx = &mut SelectionContext::new(&infcx);
     if track_ambiguity_causes.is_yes() {
         selcx.enable_tracking_intercrate_ambiguity_causes();
@@ -419,7 +418,7 @@ fn impl_intersection_has_negative_obligation(
 
     // N.B. We need to unify impl headers *with* intercrate mode, even if proving negative predicates
     // do not need intercrate mode enabled.
-    let ref infcx = tcx.infer_ctxt().intercrate(true).with_next_trait_solver(true).build();
+    let ref infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::Coherence);
     let root_universe = infcx.universe();
     assert_eq!(root_universe, ty::UniverseIndex::ROOT);
 
@@ -570,7 +569,9 @@ fn try_prove_negated_where_clause<'tcx>(
     // the *existence* of a negative goal, not the non-existence of a positive goal.
     // Without this, we over-eagerly register coherence ambiguity candidates when
     // impl candidates do exist.
-    let ref infcx = root_infcx.fork_with_intercrate(false);
+    // FIXME(#132279): `TypingMode::non_body_analysis` is a bit questionable here as it
+    // would cause us to reveal opaque types to leak their auto traits.
+    let ref infcx = root_infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new(infcx);
     ocx.register_obligation(Obligation::new(
         infcx.tcx,
@@ -714,7 +715,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
 
             // It is only relevant that a goal is unknowable if it would have otherwise
             // failed.
-            let non_intercrate_infcx = infcx.fork_with_intercrate(false);
+            // FIXME(#132279): Forking with `TypingMode::non_body_analysis` is a bit questionable
+            // as it would allow us to reveal opaque types, potentially causing unexpected
+            // cycles.
+            let non_intercrate_infcx = infcx.fork_with_typing_mode(TypingMode::non_body_analysis());
             if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
                 infcx.tcx,
                 ObligationCause::dummy(),
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index a068f25fe35..bd4e3dd7d8d 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -14,7 +14,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
     TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
-    TypeVisitableExt, TypeVisitor, Upcast,
+    TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
 };
 use rustc_span::Span;
 use rustc_span::symbol::Symbol;
@@ -718,7 +718,7 @@ fn receiver_is_dispatchable<'tcx>(
         Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
     };
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     // the receiver is dispatchable iff the obligation holds
     infcx.predicate_must_hold_modulo_regions(&obligation)
 }
diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs
new file mode 100644
index 00000000000..60b3357810a
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/effects.rs
@@ -0,0 +1,153 @@
+use rustc_hir as hir;
+use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
+use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
+use rustc_middle::span_bug;
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
+use rustc_middle::ty::{self, TypingMode};
+use rustc_type_ir::solve::NoSolution;
+use thin_vec::ThinVec;
+
+use super::SelectionContext;
+
+pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
+
+pub enum EvaluationFailure {
+    Ambiguous,
+    NoSolution,
+}
+
+pub fn evaluate_host_effect_obligation<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    if matches!(selcx.infcx.typing_mode(obligation.param_env), TypingMode::Coherence) {
+        span_bug!(
+            obligation.cause.span,
+            "should not select host obligation in old solver in intercrate mode"
+        );
+    }
+
+    match evaluate_host_effect_from_bounds(selcx, obligation) {
+        Ok(result) => return Ok(result),
+        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+        Err(EvaluationFailure::NoSolution) => {}
+    }
+
+    match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
+        Ok(result) => return Ok(result),
+        Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
+        Err(EvaluationFailure::NoSolution) => {}
+    }
+
+    Err(EvaluationFailure::NoSolution)
+}
+
+fn match_candidate<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+    candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
+    if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
+        return Err(NoSolution);
+    }
+
+    let candidate = infcx.instantiate_binder_with_fresh_vars(
+        obligation.cause.span,
+        BoundRegionConversionTime::HigherRankedType,
+        candidate,
+    );
+
+    let mut nested = infcx
+        .at(&obligation.cause, obligation.param_env)
+        .eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
+        .into_obligations();
+
+    for nested in &mut nested {
+        nested.set_depth_from_parent(obligation.recursion_depth);
+    }
+
+    Ok(nested)
+}
+
+fn evaluate_host_effect_from_bounds<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    let infcx = selcx.infcx;
+    let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
+    let mut candidate = None;
+
+    for predicate in obligation.param_env.caller_bounds() {
+        let bound_predicate = predicate.kind();
+        if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
+            let data = bound_predicate.rebind(data);
+            if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
+                continue;
+            }
+
+            if !drcx.args_may_unify(
+                obligation.predicate.trait_ref.args,
+                data.skip_binder().trait_ref.args,
+            ) {
+                continue;
+            }
+
+            let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
+
+            if is_match {
+                if candidate.is_some() {
+                    return Err(EvaluationFailure::Ambiguous);
+                } else {
+                    candidate = Some(data);
+                }
+            }
+        }
+    }
+
+    if let Some(data) = candidate {
+        Ok(match_candidate(infcx, obligation, data)
+            .expect("candidate matched before, so it should match again"))
+    } else {
+        Err(EvaluationFailure::NoSolution)
+    }
+}
+
+fn evaluate_host_effect_from_selection_candiate<'tcx>(
+    selcx: &mut SelectionContext<'_, 'tcx>,
+    obligation: &HostEffectObligation<'tcx>,
+) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
+    let tcx = selcx.tcx();
+    selcx.infcx.commit_if_ok(|_| {
+        match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
+            Ok(None) => Err(EvaluationFailure::Ambiguous),
+            Err(_) => Err(EvaluationFailure::NoSolution),
+            Ok(Some(source)) => match source {
+                ImplSource::UserDefined(impl_) => {
+                    if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
+                        return Err(EvaluationFailure::NoSolution);
+                    }
+
+                    let mut nested = impl_.nested;
+                    nested.extend(
+                        tcx.const_conditions(impl_.impl_def_id)
+                            .instantiate(tcx, impl_.args)
+                            .into_iter()
+                            .map(|(trait_ref, _)| {
+                                obligation.with(
+                                    tcx,
+                                    trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
+                                )
+                            }),
+                    );
+
+                    for nested in &mut nested {
+                        nested.set_depth_from_parent(obligation.recursion_depth);
+                    }
+
+                    Ok(nested)
+                }
+                _ => Err(EvaluationFailure::NoSolution),
+            },
+        }
+    })
+}
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 1754418156d..29e60e3c428 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -13,10 +13,11 @@ use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
+use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode};
 use thin_vec::ThinVec;
 use tracing::{debug, debug_span, instrument};
 
+use super::effects::{self, HostEffectObligation};
 use super::project::{self, ProjectAndUnifyResult};
 use super::select::SelectionContext;
 use super::{
@@ -402,8 +403,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                     )
                 }
 
-                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
-                    ProcessResult::Changed(Default::default())
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
+                    let host_obligation = obligation.with(infcx.tcx, data);
+
+                    self.process_host_obligation(
+                        host_obligation,
+                        &mut pending_obligation.stalled_on,
+                    )
                 }
 
                 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
@@ -754,7 +760,9 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx;
-        if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
+        if obligation.predicate.is_global()
+            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -807,11 +815,13 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
         stalled_on: &mut Vec<TyOrConstInferVar>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
-
-        if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
+        let infcx = self.selcx.infcx;
+        if obligation.predicate.is_global()
+            && !matches!(infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
-            if self.selcx.infcx.predicate_must_hold_considering_regions(obligation) {
+            if infcx.predicate_must_hold_considering_regions(obligation) {
                 if let Some(key) = ProjectionCacheKey::from_poly_projection_obligation(
                     &mut self.selcx,
                     &project_obligation,
@@ -819,8 +829,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
                     // If `predicate_must_hold_considering_regions` succeeds, then we've
                     // evaluated all sub-obligations. We can therefore mark the 'root'
                     // obligation as complete, and skip evaluating sub-obligations.
-                    self.selcx
-                        .infcx
+                    infcx
                         .inner
                         .borrow_mut()
                         .projection_cache()
@@ -854,6 +863,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
             }
         }
     }
+
+    fn process_host_obligation(
+        &mut self,
+        host_obligation: HostEffectObligation<'tcx>,
+        stalled_on: &mut Vec<TyOrConstInferVar>,
+    ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+        match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
+            Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
+            Err(effects::EvaluationFailure::Ambiguous) => {
+                stalled_on.clear();
+                stalled_on.extend(args_infer_vars(
+                    &self.selcx,
+                    ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
+                ));
+                ProcessResult::Unchanged
+            }
+            Err(effects::EvaluationFailure::NoSolution) => {
+                ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
+            }
+        }
+    }
 }
 
 /// Returns the set of inference variables contained in `args`.
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 3e65194577e..3b17fa6b032 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 
 use super::outlives_bounds::InferCtxtExt;
 use crate::regions::InferCtxtRegionExt;
@@ -143,7 +143,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>(
     let mut infringing_inner_tys = vec![];
     for inner_ty in inner_tys {
         // We use an ocx per inner ty for better diagnostics
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
 
         ocx.register_bound(
@@ -200,7 +200,7 @@ pub fn all_fields_implement_trait<'tcx>(
     for variant in adt.variants() {
         for field in &variant.fields {
             // Do this per-field to get better error messages.
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
 
             let unnormalized_ty = field.ty(tcx, args);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index cdf24887e76..1c84f2171bc 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -6,6 +6,7 @@ pub mod auto_trait;
 pub(crate) mod coherence;
 pub mod const_evaluatable;
 mod dyn_compatibility;
+pub mod effects;
 mod engine;
 mod fulfill;
 pub mod misc;
@@ -33,7 +34,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast,
+    self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, TypingMode,
+    Upcast,
 };
 use rustc_span::Span;
 use rustc_span::def_id::DefId;
@@ -273,7 +275,7 @@ fn do_normalize_predicates<'tcx>(
     // by wfcheck anyway, so I'm not sure we have to check
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
     let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
     let predicates = ocx.normalize(&cause, elaborated_env, predicates);
 
@@ -474,11 +476,11 @@ pub fn normalize_param_env_or_error<'tcx>(
 
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
-/// hold. Used when creating vtables to check for unsatisfiable methods.
+/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
+/// used during analysis.
 pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec<ty::Clause<'tcx>>) -> bool {
     debug!("impossible_predicates(predicates={:?})", predicates);
-
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
     let param_env = ty::ParamEnv::reveal_all();
     let ocx = ObligationCtxt::new(&infcx);
     let predicates = ocx.normalize(&ObligationCause::dummy(), param_env, predicates);
@@ -567,8 +569,11 @@ fn is_impossible_associated_item(
     // since that method *may* have some substitutions where the predicates hold.
     //
     // This replicates the logic we use in coherence.
-    let infcx =
-        tcx.infer_ctxt().ignoring_regions().with_next_trait_solver(true).intercrate(true).build();
+    let infcx = tcx
+        .infer_ctxt()
+        .ignoring_regions()
+        .with_next_trait_solver(true)
+        .build(TypingMode::Coherence);
     let param_env = ty::ParamEnv::empty();
     let fresh_args = infcx.fresh_args_for_item(tcx.def_span(impl_def_id), impl_def_id);
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 38722c0ff7c..a75c07c2e8c 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -334,11 +334,6 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
 ) -> Result<Option<Term<'tcx>>, InProgress> {
     let infcx = selcx.infcx;
     debug_assert!(!selcx.infcx.next_trait_solver());
-    // Don't use the projection cache in intercrate mode -
-    // the `infcx` may be re-used between intercrate in non-intercrate
-    // mode, which could lead to using incorrect cache results.
-    let use_cache = !selcx.is_intercrate();
-
     let projection_term = infcx.resolve_vars_if_possible(projection_term);
     let cache_key = ProjectionCacheKey::new(projection_term, param_env);
 
@@ -349,13 +344,8 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
     // would not benefit from caching when proving `T: Trait<U=Foo>`
     // bounds. It might be the case that we want two distinct caches,
     // or else another kind of cache entry.
-
-    let cache_result = if use_cache {
-        infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
-    } else {
-        Ok(())
-    };
-    match cache_result {
+    let cache_entry = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
+    match cache_entry {
         Ok(()) => debug!("no cache"),
         Err(ProjectionCacheEntry::Ambiguous) => {
             // If we found ambiguity the last time, that means we will continue
@@ -378,10 +368,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             // Cache that normalizing this projection resulted in a cycle. This
             // should ensure that, unless this happens within a snapshot that's
             // rolled back, fulfillment or evaluation will notice the cycle.
-
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().recur(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().recur(cache_key);
             return Err(InProgress);
         }
         Err(ProjectionCacheEntry::Recur) => {
@@ -445,26 +432,20 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             let mut deduped = SsoHashSet::with_capacity(result.obligations.len());
             result.obligations.retain(|obligation| deduped.insert(obligation.clone()));
 
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
-            }
+            infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             obligations.extend(result.obligations);
             Ok(Some(result.value))
         }
         Ok(Projected::NoProgress(projected_ty)) => {
             let result =
                 Normalized { value: projected_ty, obligations: PredicateObligations::new() };
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
-            }
+            infcx.inner.borrow_mut().projection_cache().insert_term(cache_key, result.clone());
             // No need to extend `obligations`.
             Ok(Some(result.value))
         }
         Err(ProjectionError::TooManyCandidates) => {
             debug!("opt_normalize_projection_type: too many candidates");
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
             Ok(None)
         }
         Err(ProjectionError::TraitSelectionError(_)) => {
@@ -473,10 +454,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
             // just return `ty::err` but add the obligation `T :
             // Trait`, which when processed will cause the error to be
             // reported later
-
-            if use_cache {
-                infcx.inner.borrow_mut().projection_cache().error(cache_key);
-            }
+            infcx.inner.borrow_mut().projection_cache().error(cache_key);
             let result = normalize_to_error(selcx, param_env, projection_term, cause, depth);
             obligations.extend(result.obligations);
             Ok(Some(result.value))
@@ -1180,7 +1158,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                                             selcx.tcx(),
                                             selcx.tcx().require_lang_item(
                                                 LangItem::Sized,
-                                                Some(obligation.cause.span()),
+                                                Some(obligation.cause.span),
                                             ),
                                             [self_ty],
                                         ),
@@ -1600,7 +1578,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
                 // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
                 let sized_predicate = ty::TraitRef::new(
                     tcx,
-                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())),
+                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
                     [self_ty],
                 );
                 obligations.push(obligation.with(tcx, sized_predicate));
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 76017299f2c..9e1a2a3e7d2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -87,10 +87,9 @@ impl<'tcx> InferCtxt<'tcx> {
                 Ok(result)
             })
         } else {
-            assert!(!self.intercrate);
             let c_pred =
                 self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values);
-            self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred)
+            self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred)
         }
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index e027586563e..03fde1d1598 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -16,7 +16,7 @@ use rustc_infer::traits::{
     Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError,
 };
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
@@ -790,7 +790,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         //
                         // Note that this is only sound as projection candidates of opaque types
                         // are always applicable for auto traits.
-                    } else if self.infcx.intercrate {
+                    } else if let TypingMode::Coherence =
+                        self.infcx.typing_mode(obligation.param_env)
+                    {
                         // We do not emit auto trait candidates for opaque types in coherence.
                         // Doing so can result in weird dependency cycles.
                         candidates.ambiguous = true;
@@ -930,7 +932,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Option<ty::PolyExistentialTraitRef<'tcx>> {
         // Don't drop any candidates in intercrate mode, as it's incomplete.
         // (Not that it matters, since `Unsize` is not a stable trait.)
-        if self.infcx.intercrate {
+        //
+        // FIXME(@lcnr): This should probably only trigger during analysis,
+        // disabling candidates during codegen is also questionable.
+        if let TypingMode::Coherence = self.infcx.typing_mode(param_env) {
             return None;
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ec4114fd9d7..b1e5e526315 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2,6 +2,7 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html#selection
 
+use std::assert_matches::assert_matches;
 use std::cell::{Cell, RefCell};
 use std::fmt::{self, Display};
 use std::ops::ControlFlow;
@@ -28,7 +29,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
     self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
-    Upcast,
+    TypingMode, Upcast,
 };
 use rustc_span::Symbol;
 use rustc_span::symbol::sym;
@@ -49,7 +50,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
 use crate::solve::InferCtxtSelectExt as _;
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{ProjectionCacheKey, Unimplemented};
+use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
 
 mod _match;
 mod candidate_assembly;
@@ -222,7 +223,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// Enables tracking of intercrate ambiguity causes. See
     /// the documentation of [`Self::intercrate_ambiguity_causes`] for more.
     pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
-        assert!(self.is_intercrate());
+        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
         assert!(self.intercrate_ambiguity_causes.is_none());
         self.intercrate_ambiguity_causes = Some(FxIndexSet::default());
         debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
@@ -234,7 +235,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub fn take_intercrate_ambiguity_causes(
         &mut self,
     ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> {
-        assert!(self.is_intercrate());
+        assert_matches!(self.infcx.typing_mode_unchecked(), TypingMode::Coherence);
         self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
@@ -242,10 +243,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn is_intercrate(&self) -> bool {
-        self.infcx.intercrate
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -645,11 +642,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     self.evaluate_trait_predicate_recursively(previous_stack, obligation)
                 }
 
-                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
-                    // FIXME(effects): It should be relatively straightforward to implement
-                    // old trait solver support for `HostEffect` bounds; or at least basic
-                    // support for them.
-                    todo!()
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
+                    self.infcx.enter_forall(bound_predicate.rebind(data), |data| {
+                        match effects::evaluate_host_effect_obligation(
+                            self,
+                            &obligation.with(self.tcx(), data),
+                        ) {
+                            Ok(nested) => {
+                                self.evaluate_predicates_recursively(previous_stack, nested)
+                            }
+                            Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
+                            Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
+                        }
+                    })
                 }
 
                 ty::PredicateKind::Subtype(p) => {
@@ -1021,7 +1026,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: PolyTraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        if !self.is_intercrate()
+        if !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
             && obligation.is_global()
             && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
         {
@@ -1304,14 +1309,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<EvaluationResult> {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return None;
-        }
-
         let tcx = self.tcx();
         if self.can_use_global_caches(param_env) {
             if let Some(res) = tcx.evaluation_cache.get(&(param_env, trait_pred), tcx) {
@@ -1334,14 +1331,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return;
-        }
-
         if self.can_use_global_caches(param_env) && !trait_pred.has_infer() {
             debug!(?trait_pred, ?result, "insert_evaluation_cache global");
             // This may overwrite the cache with the same value
@@ -1468,13 +1457,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Result<(), Conflict> {
-        debug!("is_knowable(intercrate={:?})", self.is_intercrate());
-
-        if !self.is_intercrate() {
-            return Ok(());
+        let obligation = &stack.obligation;
+        match self.infcx.typing_mode(obligation.param_env) {
+            TypingMode::Coherence => {}
+            TypingMode::Analysis { .. } | TypingMode::PostAnalysis => return Ok(()),
         }
 
-        let obligation = &stack.obligation;
+        debug!("is_knowable()");
+
         let predicate = self.infcx.resolve_vars_if_possible(obligation.predicate);
 
         // Okay to skip binder because of the nature of the
@@ -1494,25 +1484,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return false;
         }
 
-        // Avoid using the global cache during coherence and just rely
-        // on the local cache. This effectively disables caching
-        // during coherence. It is really just a simplification to
-        // avoid us having to fear that coherence results "pollute"
-        // the master cache. Since coherence executes pretty quickly,
-        // it's not worth going to more trouble to increase the
-        // hit-rate, I don't think.
-        if self.is_intercrate() {
-            return false;
-        }
-
-        // Avoid using the global cache when we're defining opaque types
-        // as their hidden type may impact the result of candidate selection.
-        if !self.infcx.defining_opaque_types().is_empty() {
-            return false;
+        match self.infcx.typing_mode(param_env) {
+            // Avoid using the global cache during coherence and just rely
+            // on the local cache. It is really just a simplification to
+            // avoid us having to fear that coherence results "pollute"
+            // the master cache. Since coherence executes pretty quickly,
+            // it's not worth going to more trouble to increase the
+            // hit-rate, I don't think.
+            TypingMode::Coherence => false,
+            // Avoid using the global cache when we're defining opaque types
+            // as their hidden type may impact the result of candidate selection.
+            TypingMode::Analysis { defining_opaque_types } => defining_opaque_types.is_empty(),
+            // The global cache is only used if there are no opaque types in
+            // the defining scope or we're outside of analysis.
+            //
+            // FIXME(#132279): This is still incorrect as we treat opaque types
+            // and default associated items differently between these two modes.
+            TypingMode::PostAnalysis => true,
         }
-
-        // Otherwise, we can use the global cache.
-        true
     }
 
     fn check_candidate_cache(
@@ -1520,13 +1509,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         param_env: ty::ParamEnv<'tcx>,
         cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return None;
-        }
         let tcx = self.tcx();
         let pred = cache_fresh_trait_pred.skip_binder();
 
@@ -1558,13 +1540,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &self,
         result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
     ) -> bool {
-        // Neither the global nor local cache is aware of intercrate
-        // mode, so don't do any caching. In particular, we might
-        // re-use the same `InferCtxt` with both an intercrate
-        // and non-intercrate `SelectionContext`
-        if self.is_intercrate() {
-            return false;
-        }
         match result {
             Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
             _ => true,
@@ -2533,7 +2508,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             })?;
         nested_obligations.extend(obligations);
 
-        if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation {
+        if impl_trait_header.polarity == ty::ImplPolarity::Reservation
+            && !matches!(self.infcx.typing_mode(obligation.param_env), TypingMode::Coherence)
+        {
             debug!("reservation impls only apply in intercrate mode");
             return Err(());
         }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 0e45f7a195f..5bf3dbcbc32 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -19,7 +19,9 @@ use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_middle::bug;
 use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{
+    self, GenericArgsRef, ImplSubject, Ty, TyCtxt, TypeVisitableExt, TypingMode,
+};
 use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS};
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym};
 use specialization_graph::GraphExt;
@@ -184,7 +186,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
     let penv = tcx.param_env(impl1_def_id);
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
 
     // Attempt to prove that impl2 applies, given all of the above.
     fulfill_implication(
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index ed221e2a183..bb56d6eaf54 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -9,7 +9,8 @@ use rustc_infer::traits::util::PredicateSet;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, Upcast, VtblEntry,
+    self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast,
+    VtblEntry,
 };
 use rustc_span::{DUMMY_SP, Span, sym};
 use smallvec::{SmallVec, smallvec};
@@ -439,7 +440,7 @@ fn trait_refs_are_compatible<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
     let param_env = ty::ParamEnv::reveal_all();
     let ocx = ObligationCtxt::new(&infcx);
     let hr_source_principal =
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 11182198246..d8c1c50d79a 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -6,7 +6,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::{
     ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
@@ -30,7 +30,7 @@ pub(crate) fn codegen_select_candidate<'tcx>(
 
     // Do the initial selection for the obligation. This yields the
     // shallow result we are looking for -- that is, what specific impl.
-    let infcx = tcx.infer_ctxt().ignoring_regions().build();
+    let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::from_param_env(param_env));
     let mut selcx = SelectionContext::new(&infcx);
 
     let obligation_cause = ObligationCause::dummy();
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 3e2794f6489..d79059a39a1 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -1,7 +1,7 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt};
+use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode};
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::{Normalized, ObligationCause};
 use tracing::debug;
@@ -22,7 +22,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par
     goal: ParamEnvAnd<'tcx, T>,
 ) -> Result<T, NoSolution> {
     let ParamEnvAnd { param_env, value } = goal;
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let cause = ObligationCause::dummy();
     match infcx.at(&cause, param_env).query_normalize(value) {
         Ok(Normalized { value: normalized_value, obligations: normalized_obligations }) => {
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
index 4732e968f6b..6a98be18503 100644
--- a/compiler/rustc_transmute/Cargo.toml
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2021"
 
 [dependencies]
 # tidy-alphabetical-start
+rustc_abi = { path = "../rustc_abi", optional = true }
 rustc_ast_ir = { path = "../rustc_ast_ir", optional = true }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hir = { path = "../rustc_hir", optional = true }
@@ -12,19 +13,18 @@ rustc_infer = { path = "../rustc_infer", optional = true }
 rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_middle = { path = "../rustc_middle", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
-rustc_target = { path = "../rustc_target", optional = true }
 tracing = "0.1"
 # tidy-alphabetical-end
 
 [features]
 rustc = [
+    "dep:rustc_abi",
+    "dep:rustc_ast_ir",
     "dep:rustc_hir",
     "dep:rustc_infer",
     "dep:rustc_macros",
     "dep:rustc_middle",
     "dep:rustc_span",
-    "dep:rustc_target",
-    "dep:rustc_ast_ir",
 ]
 
 [dev-dependencies]
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index a5c47c480e1..c4c01a8fac3 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -62,10 +62,10 @@ impl Ref for ! {
 pub mod rustc {
     use std::fmt::{self, Write};
 
+    use rustc_abi::Layout;
     use rustc_middle::mir::Mutability;
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
     use rustc_middle::ty::{self, Ty};
-    use rustc_target::abi::Layout;
 
     /// A reference in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 17eddbfcd7f..f19a567cd84 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -171,12 +171,12 @@ where
 
 #[cfg(feature = "rustc")]
 pub(crate) mod rustc {
+    use rustc_abi::{
+        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
+    };
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
     use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
     use rustc_span::ErrorGuaranteed;
-    use rustc_target::abi::{
-        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
-    };
 
     use super::Tree;
     use crate::layout::rustc::{Def, Ref, layout_of};
@@ -206,7 +206,7 @@ pub(crate) mod rustc {
 
     impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
         pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
-            use rustc_target::abi::HasDataLayout;
+            use rustc_abi::HasDataLayout;
             let layout = layout_of(cx, ty)?;
 
             if let Err(e) = ty.error_reported() {
@@ -339,9 +339,7 @@ pub(crate) mod rustc {
             // 2. enums that delegate their layout to a variant
             // 3. enums with multiple variants
             match layout.variants() {
-                Variants::Single { .. }
-                    if layout.abi.is_uninhabited() && layout.size == Size::ZERO =>
-                {
+                Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => {
                     // The layout representation of uninhabited, ZST enums is
                     // defined to be like that of the `!` type, as opposed of a
                     // typical enum. Consequently, they cannot be descended into
@@ -446,7 +444,7 @@ pub(crate) mod rustc {
 
         /// Constructs a `Tree` representing the value of a enum tag.
         fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
-            use rustc_target::abi::Endian;
+            use rustc_abi::Endian;
             let size = tag.size();
             let bits = tag.to_bits(size);
             let bytes: [u8; 16];
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 16fd28201c2..f177b609485 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -190,7 +190,7 @@ fn associated_types_for_impl_traits_in_associated_fn(
 
             impl<'tcx> Visitor<'tcx> for RPITVisitor {
                 fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
-                    if let hir::TyKind::OpaqueDef(opaq, _) = ty.kind
+                    if let hir::TyKind::OpaqueDef(opaq) = ty.kind
                         && self.rpits.insert(opaq.def_id)
                     {
                         for bound in opaq.bounds {
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index 51b908881eb..c26b41d8960 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -3,7 +3,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::traits;
 
 fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
@@ -29,7 +29,7 @@ fn is_item_raw<'tcx>(
 ) -> bool {
     let (param_env, ty) = query.into_parts();
     let trait_def_id = tcx.require_lang_item(item, None);
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
 }
 
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 9b764133f2c..e258b6dae0b 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -6,7 +6,7 @@ use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::util::AsyncDropGlueMorphology;
-use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, GenericArgsRef, Instance, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_span::sym;
 use rustc_trait_selection::traits;
 use rustc_type_ir::ClosureKind;
@@ -130,7 +130,7 @@ fn resolve_associated_item<'tcx>(
                 .unwrap_or_else(|| {
                     bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
                 });
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::PostAnalysis);
             let param_env = param_env.with_reveal_all_normalized(tcx);
             let args = rcvr_args.rebase_onto(tcx, trait_def_id, impl_data.args);
             let args = translate_args(
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index e755e90aa65..94b80e2694d 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -6,7 +6,7 @@ use rustc_abi::Integer::{I8, I32};
 use rustc_abi::Primitive::{self, Float, Int, Pointer};
 use rustc_abi::{
     Abi, AbiAndPrefAlign, AddressSpace, Align, FieldsShape, HasDataLayout, LayoutCalculatorError,
-    LayoutS, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
+    LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, Variants, WrappingRange,
 };
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
@@ -131,7 +131,7 @@ fn univariant_uninterned<'tcx>(
     fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>,
     repr: &ReprOptions,
     kind: StructKind,
-) -> Result<LayoutS<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
+) -> Result<LayoutData<FieldIdx, VariantIdx>, &'tcx LayoutError<'tcx>> {
     let pack = repr.pack;
     if pack.is_some() && repr.align.is_some() {
         cx.tcx().dcx().bug("struct cannot be packed and aligned");
@@ -159,7 +159,7 @@ fn layout_of_uncached<'tcx>(
         assert!(size.bits() <= 128);
         Scalar::Initialized { value, valid_range: WrappingRange::full(size) }
     };
-    let scalar = |value: Primitive| tcx.mk_layout(LayoutS::scalar(cx, scalar_unit(value)));
+    let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value)));
 
     let univariant =
         |fields: &IndexSlice<FieldIdx, TyAndLayout<'tcx>>, repr: &ReprOptions, kind| {
@@ -170,7 +170,7 @@ fn layout_of_uncached<'tcx>(
     Ok(match *ty.kind() {
         ty::Pat(ty, pat) => {
             let layout = cx.layout_of(ty)?.layout;
-            let mut layout = LayoutS::clone(&layout.0);
+            let mut layout = LayoutData::clone(&layout.0);
             match *pat {
                 ty::PatternKind::Range { start, end, include_end } => {
                     if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi {
@@ -206,11 +206,11 @@ fn layout_of_uncached<'tcx>(
         }
 
         // Basic scalars.
-        ty::Bool => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+        ty::Bool => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
             value: Int(I8, false),
             valid_range: WrappingRange { start: 0, end: 1 },
         })),
-        ty::Char => tcx.mk_layout(LayoutS::scalar(cx, Scalar::Initialized {
+        ty::Char => tcx.mk_layout(LayoutData::scalar(cx, Scalar::Initialized {
             value: Int(I32, false),
             valid_range: WrappingRange { start: 0, end: 0x10FFFF },
         })),
@@ -220,7 +220,7 @@ fn layout_of_uncached<'tcx>(
         ty::FnPtr(..) => {
             let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
-            tcx.mk_layout(LayoutS::scalar(cx, ptr))
+            tcx.mk_layout(LayoutData::scalar(cx, ptr))
         }
 
         // The never type.
@@ -235,7 +235,7 @@ fn layout_of_uncached<'tcx>(
 
             let pointee = tcx.normalize_erasing_regions(param_env, pointee);
             if pointee.is_sized(tcx, param_env) {
-                return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
             }
 
             let metadata = if let Some(metadata_def_id) = tcx.lang_items().metadata_type()
@@ -272,7 +272,7 @@ fn layout_of_uncached<'tcx>(
                 let metadata_layout = cx.layout_of(metadata_ty)?;
                 // If the metadata is a 1-zst, then the pointer is thin.
                 if metadata_layout.is_1zst() {
-                    return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                    return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
                 }
 
                 let Abi::Scalar(metadata) = metadata_layout.abi else {
@@ -285,7 +285,7 @@ fn layout_of_uncached<'tcx>(
 
                 match unsized_part.kind() {
                     ty::Foreign(..) => {
-                        return Ok(tcx.mk_layout(LayoutS::scalar(cx, data_ptr)));
+                        return Ok(tcx.mk_layout(LayoutData::scalar(cx, data_ptr)));
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
@@ -337,7 +337,7 @@ fn layout_of_uncached<'tcx>(
 
             let largest_niche = if count != 0 { element.largest_niche } else { None };
 
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields: FieldsShape::Array { stride: element.size, count },
                 abi,
@@ -350,7 +350,7 @@ fn layout_of_uncached<'tcx>(
         }
         ty::Slice(element) => {
             let element = cx.layout_of(element)?;
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields: FieldsShape::Array { stride: element.size, count: 0 },
                 abi: Abi::Aggregate { sized: false },
@@ -361,7 +361,7 @@ fn layout_of_uncached<'tcx>(
                 unadjusted_abi_align: element.align.abi,
             })
         }
-        ty::Str => tcx.mk_layout(LayoutS {
+        ty::Str => tcx.mk_layout(LayoutData {
             variants: Variants::Single { index: FIRST_VARIANT },
             fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
             abi: Abi::Aggregate { sized: false },
@@ -532,7 +532,7 @@ fn layout_of_uncached<'tcx>(
                 FieldsShape::Array { stride: e_ly.size, count: e_len }
             };
 
-            tcx.mk_layout(LayoutS {
+            tcx.mk_layout(LayoutData {
                 variants: Variants::Single { index: FIRST_VARIANT },
                 fields,
                 abi,
@@ -835,7 +835,7 @@ fn coroutine_layout<'tcx>(
     };
     let tag_layout = TyAndLayout {
         ty: discr_int.to_ty(tcx, /* signed = */ false),
-        layout: tcx.mk_layout(LayoutS::scalar(cx, tag)),
+        layout: tcx.mk_layout(LayoutData::scalar(cx, tag)),
     };
 
     let promoted_layouts = ineligible_locals.iter().map(|local| {
@@ -991,7 +991,7 @@ fn coroutine_layout<'tcx>(
         Abi::Aggregate { sized: true }
     };
 
-    let layout = tcx.mk_layout(LayoutS {
+    let layout = tcx.mk_layout(LayoutData {
         variants: Variants::Multiple {
             tag,
             tag_encoding: TagEncoding::Direct,
diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs
index 6cf114b74c1..3db5a4f1805 100644
--- a/compiler/rustc_ty_utils/src/layout/invariant.rs
+++ b/compiler/rustc_ty_utils/src/layout/invariant.rs
@@ -10,7 +10,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa
 
     // Type-level uninhabitedness should always imply ABI uninhabitedness.
     if layout.ty.is_privately_uninhabited(tcx, cx.param_env) {
-        assert!(layout.abi.is_uninhabited());
+        assert!(layout.is_uninhabited());
     }
 
     if layout.size.bytes() % layout.align.abi.bytes() != 0 {
@@ -262,9 +262,7 @@ pub(super) fn partially_check_layout<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLa
                 )
             }
             // Skip empty variants.
-            if variant.size == Size::ZERO
-                || variant.fields.count() == 0
-                || variant.abi.is_uninhabited()
+            if variant.size == Size::ZERO || variant.fields.count() == 0 || variant.is_uninhabited()
             {
                 // These are never actually accessed anyway, so we can skip the coherence check
                 // for them. They also fail that check, since they have
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index 1ead7b731e7..0b4efab1d9c 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -1,7 +1,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 
 /// This method returns true if and only if `adt_ty` itself has been marked as
@@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 /// Note that this does *not* recursively check if the substructure of `adt_ty`
 /// implements the trait.
 fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
-    let infcx = &tcx.infer_ctxt().build();
+    let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let cause = ObligationCause::dummy();
 
     let ocx = ObligationCtxt::new(infcx);
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 3fb7d87bcc4..24b2ebc1fbe 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -8,7 +8,7 @@ use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::inherent::*;
-use crate::{self as ty, Interner, UniverseIndex};
+use crate::{self as ty, Interner, TypingMode, UniverseIndex};
 
 #[derive_where(Clone; I: Interner, V: Clone)]
 #[derive_where(Hash; I: Interner, V: Hash)]
@@ -19,7 +19,7 @@ use crate::{self as ty, Interner, UniverseIndex};
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct CanonicalQueryInput<I: Interner, V> {
     pub canonical: Canonical<I, V>,
-    pub defining_opaque_types: I::DefiningOpaqueTypes,
+    pub typing_mode: TypingMode<I>,
 }
 
 /// A "canonicalized" type `V` is one where all free inference
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index 7c6a3c65ebf..22223e4a890 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -1,9 +1,68 @@
+use derive_where::derive_where;
+#[cfg(feature = "nightly")]
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+
 use crate::fold::TypeFoldable;
+use crate::inherent::*;
 use crate::relate::RelateResult;
 use crate::relate::combine::PredicateEmittingRelation;
-use crate::solve::SolverMode;
+use crate::solve::Reveal;
 use crate::{self as ty, Interner};
 
+/// The current typing mode of an inference context. We unfortunately have some
+/// slightly different typing rules depending on the current context. See the
+/// doc comment for each variant for how and why they are used.
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+pub enum TypingMode<I: Interner> {
+    /// When checking whether impls overlap, we check whether any obligations
+    /// are guaranteed to never hold when unifying the impls. This requires us
+    /// to be complete: we must never fail to prove something which may actually
+    /// hold.
+    ///
+    /// In this typing mode we bail with ambiguity in case its not knowable
+    /// whether a trait goal may hold, e.g. because the trait may get implemented
+    /// in a downstream or sibling crate.
+    ///
+    /// We also have to be careful when generalizing aliases inside of higher-ranked
+    /// types to not unnecessarily constrain any inference variables.
+    Coherence,
+    /// Analysis includes type inference, checking that items are well-formed, and
+    /// pretty much everything else which may emit proper type errors to the user.
+    ///
+    /// We only normalize opaque types which may get defined by the current body,
+    /// which are stored in `defining_opaque_types`.
+    Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
+    /// After analysis, mostly during codegen and MIR optimizations, we're able to
+    /// reveal all opaque types.
+    PostAnalysis,
+}
+
+impl<I: Interner> TypingMode<I> {
+    /// Analysis outside of a body does not define any opaque types.
+    pub fn non_body_analysis() -> TypingMode<I> {
+        TypingMode::Analysis { defining_opaque_types: Default::default() }
+    }
+
+    /// While typechecking a body, we need to be able to define the opaque
+    /// types defined by that body.
+    pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
+        TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
+    }
+
+    /// FIXME(#132279): Using this function is questionable as the `param_env`
+    /// does not track `defining_opaque_types` and whether we're in coherence mode.
+    /// Many uses of this function should also use a not-yet implemented typing mode
+    /// which reveals already defined opaque types in the future. This function will
+    /// get completely removed at some point.
+    pub fn from_param_env(param_env: I::ParamEnv) -> TypingMode<I> {
+        match param_env.reveal() {
+            Reveal::UserFacing => TypingMode::non_body_analysis(),
+            Reveal::All => TypingMode::PostAnalysis,
+        }
+    }
+}
+
 pub trait InferCtxtLike: Sized {
     type Interner: Interner;
     fn cx(&self) -> Self::Interner;
@@ -16,7 +75,10 @@ pub trait InferCtxtLike: Sized {
         true
     }
 
-    fn solver_mode(&self) -> SolverMode;
+    fn typing_mode(
+        &self,
+        param_env_for_debug_assertion: <Self::Interner as Interner>::ParamEnv,
+    ) -> TypingMode<Self::Interner>;
 
     fn universe(&self) -> ty::UniverseIndex;
     fn create_next_universe(&self) -> ty::UniverseIndex;
@@ -43,8 +105,6 @@ pub trait InferCtxtLike: Sized {
         vid: ty::RegionVid,
     ) -> <Self::Interner as Interner>::Region;
 
-    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
-
     fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty;
     fn next_const_infer(&self) -> <Self::Interner as Interner>::Const;
     fn fresh_args_for_item(
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 6a8113b38b7..36ddddccfa2 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -11,9 +11,7 @@ use crate::inherent::*;
 use crate::ir_print::IrPrint;
 use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
-use crate::solve::{
-    CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
-};
+use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty, search_graph};
 
@@ -130,11 +128,7 @@ pub trait Interner:
     type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R;
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R;
 
     fn evaluation_is_concurrent(&self) -> bool;
 
@@ -298,6 +292,11 @@ pub trait Interner:
         self,
         binder: ty::Binder<Self, T>,
     ) -> ty::Binder<Self, T>;
+
+    fn opaque_types_defined_by(
+        self,
+        defining_anchor: Self::LocalDefId,
+    ) -> Self::DefiningOpaqueTypes;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
@@ -414,12 +413,8 @@ impl<I: Interner> search_graph::Cx for I {
     fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, I::DepNodeIndex) {
         I::with_cached_task(self, task)
     }
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R,
-    ) -> R {
-        I::with_global_cache(self, mode, f)
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R {
+        I::with_global_cache(self, f)
     }
     fn evaluation_is_concurrent(&self) -> bool {
         self.evaluation_is_concurrent()
diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs
index ac35215fbaa..0e94e989b97 100644
--- a/compiler/rustc_type_ir/src/outlives.rs
+++ b/compiler/rustc_type_ir/src/outlives.rs
@@ -110,6 +110,18 @@ impl<I: Interner> TypeVisitor<I> for OutlivesCollector<'_, I> {
             ty::Coroutine(_, args) => {
                 args.as_coroutine().tupled_upvars_ty().visit_with(self);
 
+                // Coroutines may not outlive a region unless the resume
+                // ty outlives a region. This is because the resume ty may
+                // store data that lives shorter than this outlives region
+                // across yield points, which may subsequently be accessed
+                // after the coroutine is resumed again.
+                //
+                // Conceptually, you may think of the resume arg as an upvar
+                // of `&mut Option<ResumeArgTy>`, since it is kinda like
+                // storage shared between the callee of the coroutine and the
+                // coroutine body.
+                args.as_coroutine().resume_ty().visit_with(self);
+
                 // We ignore regions in the coroutine interior as we don't
                 // want these to affect region inference
             }
diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs
index 17a3912730f..53751f7711a 100644
--- a/compiler/rustc_type_ir/src/relate/combine.rs
+++ b/compiler/rustc_type_ir/src/relate/combine.rs
@@ -6,9 +6,9 @@ use super::{
 };
 use crate::error::TypeError;
 use crate::inherent::*;
-use crate::solve::{Goal, SolverMode};
+use crate::solve::Goal;
 use crate::visit::TypeVisitableExt as _;
-use crate::{self as ty, InferCtxtLike, Interner, Upcast};
+use crate::{self as ty, InferCtxtLike, Interner, TypingMode, Upcast};
 
 pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>:
     TypeRelation<I>
@@ -128,19 +128,19 @@ where
         }
 
         (ty::Alias(ty::Opaque, _), _) | (_, ty::Alias(ty::Opaque, _)) => {
-            match infcx.solver_mode() {
-                SolverMode::Normal => {
-                    assert!(!infcx.next_trait_solver());
-                    structurally_relate_tys(relation, a, b)
-                }
+            assert!(!infcx.next_trait_solver());
+            match infcx.typing_mode(relation.param_env()) {
                 // During coherence, opaque types should be treated as *possibly*
-                // equal to any other type (except for possibly itinfcx). This is an
+                // equal to any other type. This is an
                 // extremely heavy hammer, but can be relaxed in a forwards-compatible
                 // way later.
-                SolverMode::Coherence => {
+                TypingMode::Coherence => {
                     relation.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
                     Ok(a)
                 }
+                TypingMode::Analysis { .. } | TypingMode::PostAnalysis => {
+                    structurally_relate_tys(relation, a, b)
+                }
             }
         }
 
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index 3fd2bb61ba5..5010fc09adc 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -22,7 +22,6 @@ use rustc_index::{Idx, IndexVec};
 use tracing::debug;
 
 use crate::data_structures::HashMap;
-use crate::solve::SolverMode;
 
 mod global_cache;
 use global_cache::CacheData;
@@ -48,11 +47,7 @@ pub trait Cx: Copy {
     fn get_tracked<T: Debug + Clone>(self, tracked: &Self::Tracked<T>) -> T;
     fn with_cached_task<T>(self, task: impl FnOnce() -> T) -> (T, Self::DepNodeIndex);
 
-    fn with_global_cache<R>(
-        self,
-        mode: SolverMode,
-        f: impl FnOnce(&mut GlobalCache<Self>) -> R,
-    ) -> R;
+    fn with_global_cache<R>(self, f: impl FnOnce(&mut GlobalCache<Self>) -> R) -> R;
 
     fn evaluation_is_concurrent(&self) -> bool;
 }
@@ -358,7 +353,6 @@ struct ProvisionalCacheEntry<X: Cx> {
 }
 
 pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
-    mode: SolverMode,
     root_depth: AvailableDepth,
     /// The stack of goals currently being computed.
     ///
@@ -374,9 +368,8 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
 }
 
 impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
-    pub fn new(mode: SolverMode, root_depth: usize) -> SearchGraph<D> {
+    pub fn new(root_depth: usize) -> SearchGraph<D> {
         Self {
-            mode,
             root_depth: AvailableDepth(root_depth),
             stack: Default::default(),
             provisional_cache: Default::default(),
@@ -384,10 +377,6 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         }
     }
 
-    pub fn solver_mode(&self) -> SolverMode {
-        self.mode
-    }
-
     /// Lazily update the stack entry for the parent goal.
     /// This behavior is shared between actually evaluating goals
     /// and using existing global cache entries to make sure they
@@ -829,7 +818,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         available_depth: AvailableDepth,
     ) -> Option<X::Result> {
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             cache
                 .get(cx, input, available_depth, |nested_goals| {
                     Self::candidate_is_applicable(
@@ -852,7 +841,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         available_depth: AvailableDepth,
     ) -> Option<X::Result> {
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache
                 .get(cx, input, available_depth, |nested_goals| {
                     Self::candidate_is_applicable(
@@ -1041,7 +1030,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     ) {
         let additional_depth = final_entry.reached_depth.as_usize() - self.stack.len();
         debug!(?final_entry, ?result, "insert global cache");
-        cx.with_global_cache(self.mode, |cache| {
+        cx.with_global_cache(|cache| {
             cache.insert(
                 cx,
                 input,
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index b3f8390bbf0..fe455873051 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -58,19 +58,6 @@ pub enum Reveal {
     All,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum SolverMode {
-    /// Ordinary trait solving, using everywhere except for coherence.
-    Normal,
-    /// Trait solving during coherence. There are a few notable differences
-    /// between coherence and ordinary trait solving.
-    ///
-    /// Most importantly, trait solving during coherence must not be incomplete,
-    /// i.e. return `Err(NoSolution)` for goals for which a solution exists.
-    /// This means that we must not make any guesses or arbitrary choices.
-    Coherence,
-}
-
 pub type CanonicalInput<I, T = <I as Interner>::Predicate> =
     ty::CanonicalQueryInput<I, QueryInput<I, T>>;
 pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index bc354650a8e..e4956c7c53c 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -183,15 +183,14 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use core::any::Any;
-use core::async_iter::AsyncIterator;
+use core::borrow::{Borrow, BorrowMut};
 #[cfg(not(no_global_oom_handling))]
 use core::clone::CloneToUninit;
 use core::cmp::Ordering;
-use core::error::Error;
+use core::error::{self, Error};
+use core::fmt;
 use core::future::Future;
 use core::hash::{Hash, Hasher};
-use core::iter::FusedIterator;
 use core::marker::{Tuple, Unsize};
 use core::mem::{self, SizedTypeProperties};
 use core::ops::{
@@ -201,27 +200,24 @@ use core::ops::{
 use core::pin::{Pin, PinCoerceUnsized};
 use core::ptr::{self, NonNull, Unique};
 use core::task::{Context, Poll};
-use core::{borrow, fmt, slice};
-
-#[unstable(feature = "thin_box", issue = "92791")]
-pub use thin::ThinBox;
 
 #[cfg(not(no_global_oom_handling))]
 use crate::alloc::handle_alloc_error;
 use crate::alloc::{AllocError, Allocator, Global, Layout};
-#[cfg(not(no_global_oom_handling))]
-use crate::borrow::Cow;
 use crate::raw_vec::RawVec;
 #[cfg(not(no_global_oom_handling))]
 use crate::str::from_boxed_utf8_unchecked;
-#[cfg(not(no_global_oom_handling))]
-use crate::string::String;
-use crate::vec;
-#[cfg(not(no_global_oom_handling))]
-use crate::vec::Vec;
 
+/// Conversion related impls for `Box<_>` (`From`, `downcast`, etc)
+mod convert;
+/// Iterator related impls for `Box<_>`.
+mod iter;
+/// [`ThinBox`] implementation.
 mod thin;
 
+#[unstable(feature = "thin_box", issue = "92791")]
+pub use thin::ThinBox;
+
 /// A pointer type that uniquely owns a heap allocation of type `T`.
 ///
 /// See the [module-level documentation](../../std/boxed/index.html) for more.
@@ -1768,6 +1764,41 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
+impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
+    fn clone(&self) -> Self {
+        let alloc = Box::allocator(self).clone();
+        self.to_vec_in(alloc).into_boxed_slice()
+    }
+
+    /// Copies `source`'s contents into `self` without creating a new allocation,
+    /// so long as the two are of the same length.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x = Box::new([5, 6, 7]);
+    /// let mut y = Box::new([8, 9, 10]);
+    /// let yp: *const [i32] = &*y;
+    ///
+    /// y.clone_from(&x);
+    ///
+    /// // The value is the same
+    /// assert_eq!(x, y);
+    ///
+    /// // And no allocation occurred
+    /// assert_eq!(yp, &*y);
+    /// ```
+    fn clone_from(&mut self, source: &Self) {
+        if self.len() == source.len() {
+            self.clone_from_slice(&source);
+        } else {
+            *self = source.clone();
+        }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl Clone for Box<str> {
     fn clone(&self) -> Self {
         // this makes a copy of the data
@@ -1787,6 +1818,7 @@ impl<T: ?Sized + PartialEq, A: Allocator> PartialEq for Box<T, A> {
         PartialEq::ne(&**self, &**other)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> {
     #[inline]
@@ -1810,6 +1842,7 @@ impl<T: ?Sized + PartialOrd, A: Allocator> PartialOrd for Box<T, A> {
         PartialOrd::gt(&**self, &**other)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> {
     #[inline]
@@ -1817,6 +1850,7 @@ impl<T: ?Sized + Ord, A: Allocator> Ord for Box<T, A> {
         Ord::cmp(&**self, &**other)
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Eq, A: Allocator> Eq for Box<T, A> {}
 
@@ -1879,462 +1913,6 @@ impl<T: ?Sized + Hasher, A: Allocator> Hasher for Box<T, A> {
     }
 }
 
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "from_for_ptrs", since = "1.6.0")]
-impl<T> From<T> for Box<T> {
-    /// Converts a `T` into a `Box<T>`
-    ///
-    /// The conversion allocates on the heap and moves `t`
-    /// from the stack into it.
-    ///
-    /// # Examples
-    ///
-    /// ```rust
-    /// let x = 5;
-    /// let boxed = Box::new(5);
-    ///
-    /// assert_eq!(Box::from(x), boxed);
-    /// ```
-    fn from(t: T) -> Self {
-        Box::new(t)
-    }
-}
-
-#[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
-where
-    A: 'static,
-{
-    /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
-    /// `*boxed` will be pinned in memory and unable to be moved.
-    ///
-    /// This conversion does not allocate on the heap and happens in place.
-    ///
-    /// This is also available via [`Box::into_pin`].
-    ///
-    /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
-    /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
-    /// This `From` implementation is useful if you already have a `Box<T>`, or you are
-    /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
-    fn from(boxed: Box<T, A>) -> Self {
-        Box::into_pin(boxed)
-    }
-}
-
-/// Specialization trait used for `From<&[T]>`.
-#[cfg(not(no_global_oom_handling))]
-trait BoxFromSlice<T> {
-    fn from_slice(slice: &[T]) -> Self;
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
-    #[inline]
-    default fn from_slice(slice: &[T]) -> Self {
-        slice.to_vec().into_boxed_slice()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
-    #[inline]
-    fn from_slice(slice: &[T]) -> Self {
-        let len = slice.len();
-        let buf = RawVec::with_capacity(len);
-        unsafe {
-            ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
-            buf.into_box(slice.len()).assume_init()
-        }
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_slice", since = "1.17.0")]
-impl<T: Clone> From<&[T]> for Box<[T]> {
-    /// Converts a `&[T]` into a `Box<[T]>`
-    ///
-    /// This conversion allocates on the heap
-    /// and performs a copy of `slice` and its contents.
-    ///
-    /// # Examples
-    /// ```rust
-    /// // create a &[u8] which will be used to create a Box<[u8]>
-    /// let slice: &[u8] = &[104, 101, 108, 108, 111];
-    /// let boxed_slice: Box<[u8]> = Box::from(slice);
-    ///
-    /// println!("{boxed_slice:?}");
-    /// ```
-    #[inline]
-    fn from(slice: &[T]) -> Box<[T]> {
-        <Self as BoxFromSlice<T>>::from_slice(slice)
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_cow", since = "1.45.0")]
-impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> {
-    /// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
-    ///
-    /// When `cow` is the `Cow::Borrowed` variant, this
-    /// conversion allocates on the heap and copies the
-    /// underlying slice. Otherwise, it will try to reuse the owned
-    /// `Vec`'s allocation.
-    #[inline]
-    fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
-        match cow {
-            Cow::Borrowed(slice) => Box::from(slice),
-            Cow::Owned(slice) => Box::from(slice),
-        }
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_slice", since = "1.17.0")]
-impl From<&str> for Box<str> {
-    /// Converts a `&str` into a `Box<str>`
-    ///
-    /// This conversion allocates on the heap
-    /// and performs a copy of `s`.
-    ///
-    /// # Examples
-    ///
-    /// ```rust
-    /// let boxed: Box<str> = Box::from("hello");
-    /// println!("{boxed}");
-    /// ```
-    #[inline]
-    fn from(s: &str) -> Box<str> {
-        unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_cow", since = "1.45.0")]
-impl From<Cow<'_, str>> for Box<str> {
-    /// Converts a `Cow<'_, str>` into a `Box<str>`
-    ///
-    /// When `cow` is the `Cow::Borrowed` variant, this
-    /// conversion allocates on the heap and copies the
-    /// underlying `str`. Otherwise, it will try to reuse the owned
-    /// `String`'s allocation.
-    ///
-    /// # Examples
-    ///
-    /// ```rust
-    /// use std::borrow::Cow;
-    ///
-    /// let unboxed = Cow::Borrowed("hello");
-    /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{boxed}");
-    /// ```
-    ///
-    /// ```rust
-    /// # use std::borrow::Cow;
-    /// let unboxed = Cow::Owned("hello".to_string());
-    /// let boxed: Box<str> = Box::from(unboxed);
-    /// println!("{boxed}");
-    /// ```
-    #[inline]
-    fn from(cow: Cow<'_, str>) -> Box<str> {
-        match cow {
-            Cow::Borrowed(s) => Box::from(s),
-            Cow::Owned(s) => Box::from(s),
-        }
-    }
-}
-
-#[stable(feature = "boxed_str_conv", since = "1.19.0")]
-impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> {
-    /// Converts a `Box<str>` into a `Box<[u8]>`
-    ///
-    /// This conversion does not allocate on the heap and happens in place.
-    ///
-    /// # Examples
-    /// ```rust
-    /// // create a Box<str> which will be used to create a Box<[u8]>
-    /// let boxed: Box<str> = Box::from("hello");
-    /// let boxed_str: Box<[u8]> = Box::from(boxed);
-    ///
-    /// // create a &[u8] which will be used to create a Box<[u8]>
-    /// let slice: &[u8] = &[104, 101, 108, 108, 111];
-    /// let boxed_slice = Box::from(slice);
-    ///
-    /// assert_eq!(boxed_slice, boxed_str);
-    /// ```
-    #[inline]
-    fn from(s: Box<str, A>) -> Self {
-        let (raw, alloc) = Box::into_raw_with_allocator(s);
-        unsafe { Box::from_raw_in(raw as *mut [u8], alloc) }
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_from_array", since = "1.45.0")]
-impl<T, const N: usize> From<[T; N]> for Box<[T]> {
-    /// Converts a `[T; N]` into a `Box<[T]>`
-    ///
-    /// This conversion moves the array to newly heap-allocated memory.
-    ///
-    /// # Examples
-    ///
-    /// ```rust
-    /// let boxed: Box<[u8]> = Box::from([4, 2]);
-    /// println!("{boxed:?}");
-    /// ```
-    fn from(array: [T; N]) -> Box<[T]> {
-        Box::new(array)
-    }
-}
-
-/// Casts a boxed slice to a boxed array.
-///
-/// # Safety
-///
-/// `boxed_slice.len()` must be exactly `N`.
-unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
-    boxed_slice: Box<[T], A>,
-) -> Box<[T; N], A> {
-    debug_assert_eq!(boxed_slice.len(), N);
-
-    let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
-    // SAFETY: Pointer and allocator came from an existing box,
-    // and our safety condition requires that the length is exactly `N`
-    unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
-}
-
-#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
-    type Error = Box<[T]>;
-
-    /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
-    ///
-    /// The conversion occurs in-place and does not require a
-    /// new memory allocation.
-    ///
-    /// # Errors
-    ///
-    /// Returns the old `Box<[T]>` in the `Err` variant if
-    /// `boxed_slice.len()` does not equal `N`.
-    fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
-        if boxed_slice.len() == N {
-            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
-        } else {
-            Err(boxed_slice)
-        }
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
-impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
-    type Error = Vec<T>;
-
-    /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
-    ///
-    /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
-    /// but will require a reallocation otherwise.
-    ///
-    /// # Errors
-    ///
-    /// Returns the original `Vec<T>` in the `Err` variant if
-    /// `boxed_slice.len()` does not equal `N`.
-    ///
-    /// # Examples
-    ///
-    /// This can be used with [`vec!`] to create an array on the heap:
-    ///
-    /// ```
-    /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
-    /// assert_eq!(state.len(), 100);
-    /// ```
-    fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
-        if vec.len() == N {
-            let boxed_slice = vec.into_boxed_slice();
-            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
-        } else {
-            Err(vec)
-        }
-    }
-}
-
-impl<A: Allocator> Box<dyn Any, A> {
-    /// Attempts to downcast the box to a concrete type.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::any::Any;
-    ///
-    /// fn print_if_string(value: Box<dyn Any>) {
-    ///     if let Ok(string) = value.downcast::<String>() {
-    ///         println!("String ({}): {}", string.len(), string);
-    ///     }
-    /// }
-    ///
-    /// let my_string = "Hello World".to_string();
-    /// print_if_string(Box::new(my_string));
-    /// print_if_string(Box::new(0i8));
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
-    }
-
-    /// Downcasts the box to a concrete type.
-    ///
-    /// For a safe alternative see [`downcast`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(downcast_unchecked)]
-    ///
-    /// use std::any::Any;
-    ///
-    /// let x: Box<dyn Any> = Box::new(1_usize);
-    ///
-    /// unsafe {
-    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
-    /// }
-    /// ```
-    ///
-    /// # Safety
-    ///
-    /// The contained value must be of type `T`. Calling this method
-    /// with the incorrect type is *undefined behavior*.
-    ///
-    /// [`downcast`]: Self::downcast
-    #[inline]
-    #[unstable(feature = "downcast_unchecked", issue = "90850")]
-    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
-        debug_assert!(self.is::<T>());
-        unsafe {
-            let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
-            Box::from_raw_in(raw as *mut T, alloc)
-        }
-    }
-}
-
-impl<A: Allocator> Box<dyn Any + Send, A> {
-    /// Attempts to downcast the box to a concrete type.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::any::Any;
-    ///
-    /// fn print_if_string(value: Box<dyn Any + Send>) {
-    ///     if let Ok(string) = value.downcast::<String>() {
-    ///         println!("String ({}): {}", string.len(), string);
-    ///     }
-    /// }
-    ///
-    /// let my_string = "Hello World".to_string();
-    /// print_if_string(Box::new(my_string));
-    /// print_if_string(Box::new(0i8));
-    /// ```
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
-    }
-
-    /// Downcasts the box to a concrete type.
-    ///
-    /// For a safe alternative see [`downcast`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(downcast_unchecked)]
-    ///
-    /// use std::any::Any;
-    ///
-    /// let x: Box<dyn Any + Send> = Box::new(1_usize);
-    ///
-    /// unsafe {
-    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
-    /// }
-    /// ```
-    ///
-    /// # Safety
-    ///
-    /// The contained value must be of type `T`. Calling this method
-    /// with the incorrect type is *undefined behavior*.
-    ///
-    /// [`downcast`]: Self::downcast
-    #[inline]
-    #[unstable(feature = "downcast_unchecked", issue = "90850")]
-    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
-        debug_assert!(self.is::<T>());
-        unsafe {
-            let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
-            Box::from_raw_in(raw as *mut T, alloc)
-        }
-    }
-}
-
-impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
-    /// Attempts to downcast the box to a concrete type.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::any::Any;
-    ///
-    /// fn print_if_string(value: Box<dyn Any + Send + Sync>) {
-    ///     if let Ok(string) = value.downcast::<String>() {
-    ///         println!("String ({}): {}", string.len(), string);
-    ///     }
-    /// }
-    ///
-    /// let my_string = "Hello World".to_string();
-    /// print_if_string(Box::new(my_string));
-    /// print_if_string(Box::new(0i8));
-    /// ```
-    #[inline]
-    #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
-    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
-        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
-    }
-
-    /// Downcasts the box to a concrete type.
-    ///
-    /// For a safe alternative see [`downcast`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(downcast_unchecked)]
-    ///
-    /// use std::any::Any;
-    ///
-    /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
-    ///
-    /// unsafe {
-    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
-    /// }
-    /// ```
-    ///
-    /// # Safety
-    ///
-    /// The contained value must be of type `T`. Calling this method
-    /// with the incorrect type is *undefined behavior*.
-    ///
-    /// [`downcast`]: Self::downcast
-    #[inline]
-    #[unstable(feature = "downcast_unchecked", issue = "90850")]
-    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
-        debug_assert!(self.is::<T>());
-        unsafe {
-            let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
-                Box::into_raw_with_allocator(self);
-            Box::from_raw_in(raw as *mut T, alloc)
-        }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Display + ?Sized, A: Allocator> fmt::Display for Box<T, A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -2381,71 +1959,6 @@ unsafe impl<T: ?Sized, A: Allocator> DerefPure for Box<T, A> {}
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
 impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
-    type Item = I::Item;
-    fn next(&mut self) -> Option<I::Item> {
-        (**self).next()
-    }
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (**self).size_hint()
-    }
-    fn nth(&mut self, n: usize) -> Option<I::Item> {
-        (**self).nth(n)
-    }
-    fn last(self) -> Option<I::Item> {
-        BoxIter::last(self)
-    }
-}
-
-trait BoxIter {
-    type Item;
-    fn last(self) -> Option<Self::Item>;
-}
-
-impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> {
-    type Item = I::Item;
-    default fn last(self) -> Option<I::Item> {
-        #[inline]
-        fn some<T>(_: Option<T>, x: T) -> Option<T> {
-            Some(x)
-        }
-
-        self.fold(None, some)
-    }
-}
-
-/// Specialization for sized `I`s that uses `I`s implementation of `last()`
-/// instead of the default.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> {
-    fn last(self) -> Option<I::Item> {
-        (*self).last()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> {
-    fn next_back(&mut self) -> Option<I::Item> {
-        (**self).next_back()
-    }
-    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
-        (**self).nth_back(n)
-    }
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> {
-    fn len(&self) -> usize {
-        (**self).len()
-    }
-    fn is_empty(&self) -> bool {
-        (**self).is_empty()
-    }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
-
 #[stable(feature = "boxed_closure_impls", since = "1.35.0")]
 impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
     type Output = <F as FnOnce<Args>>::Output;
@@ -2501,157 +2014,24 @@ impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
 
+#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
+unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
+
 // It is quite crucial that we only allow the `Global` allocator here.
 // Handling arbitrary custom allocators (which can affect the `Box` layout heavily!)
 // would need a lot of codegen and interpreter adjustments.
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
 
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
-impl<I> FromIterator<I> for Box<[I]> {
-    fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
-        iter.into_iter().collect::<Vec<_>>().into_boxed_slice()
-    }
-}
-
-/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<I, A: Allocator> !Iterator for Box<[I], A> {}
-
-/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
-
-/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
-/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
-
-// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
-// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
-// so those calls will still resolve to the slice implementation, by reference.
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<I, A: Allocator> IntoIterator for Box<[I], A> {
-    type IntoIter = vec::IntoIter<I, A>;
-    type Item = I;
-    fn into_iter(self) -> vec::IntoIter<I, A> {
-        self.into_vec().into_iter()
-    }
-}
-
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
-    type IntoIter = slice::Iter<'a, I>;
-    type Item = &'a I;
-    fn into_iter(self) -> slice::Iter<'a, I> {
-        self.iter()
-    }
-}
-
-#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
-impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
-    type IntoIter = slice::IterMut<'a, I>;
-    type Item = &'a mut I;
-    fn into_iter(self) -> slice::IterMut<'a, I> {
-        self.iter_mut()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl FromIterator<char> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<&'a char> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<&'a str> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl FromIterator<String> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
-impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
-    fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
-        String::from_iter(iter).into_boxed_str()
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "box_slice_clone", since = "1.3.0")]
-impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
-    fn clone(&self) -> Self {
-        let alloc = Box::allocator(self).clone();
-        self.to_vec_in(alloc).into_boxed_slice()
-    }
-
-    /// Copies `source`'s contents into `self` without creating a new allocation,
-    /// so long as the two are of the same length.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let x = Box::new([5, 6, 7]);
-    /// let mut y = Box::new([8, 9, 10]);
-    /// let yp: *const [i32] = &*y;
-    ///
-    /// y.clone_from(&x);
-    ///
-    /// // The value is the same
-    /// assert_eq!(x, y);
-    ///
-    /// // And no allocation occurred
-    /// assert_eq!(yp, &*y);
-    /// ```
-    fn clone_from(&mut self, source: &Self) {
-        if self.len() == source.len() {
-            self.clone_from_slice(&source);
-        } else {
-            *self = source.clone();
-        }
-    }
-}
-
 #[stable(feature = "box_borrow", since = "1.1.0")]
-impl<T: ?Sized, A: Allocator> borrow::Borrow<T> for Box<T, A> {
+impl<T: ?Sized, A: Allocator> Borrow<T> for Box<T, A> {
     fn borrow(&self) -> &T {
         &**self
     }
 }
 
 #[stable(feature = "box_borrow", since = "1.1.0")]
-impl<T: ?Sized, A: Allocator> borrow::BorrowMut<T> for Box<T, A> {
+impl<T: ?Sized, A: Allocator> BorrowMut<T> for Box<T, A> {
     fn borrow_mut(&mut self) -> &mut T {
         &mut **self
     }
@@ -2728,311 +2108,23 @@ impl<F: ?Sized + Future + Unpin, A: Allocator> Future for Box<F, A> {
     }
 }
 
-#[unstable(feature = "async_iterator", issue = "79024")]
-impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
-    type Item = S::Item;
-
-    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
-        Pin::new(&mut **self).poll_next(cx)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (**self).size_hint()
-    }
-}
-
-impl dyn Error {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[rustc_allow_incoherent_impl]
-    /// Attempts to downcast the box to a concrete type.
-    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
-        if self.is::<T>() {
-            unsafe {
-                let raw: *mut dyn Error = Box::into_raw(self);
-                Ok(Box::from_raw(raw as *mut T))
-            }
-        } else {
-            Err(self)
-        }
-    }
-}
-
-impl dyn Error + Send {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[rustc_allow_incoherent_impl]
-    /// 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;
-        <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send` marker.
-            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
-        })
-    }
-}
-
-impl dyn Error + Send + Sync {
-    #[inline]
-    #[stable(feature = "error_downcast", since = "1.3.0")]
-    #[rustc_allow_incoherent_impl]
-    /// Attempts to downcast the box to a concrete type.
-    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
-        let err: Box<dyn Error> = self;
-        <dyn Error>::downcast(err).map_err(|s| unsafe {
-            // Reapply the `Send + Sync` markers.
-            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
-        })
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
-    /// Converts a type of [`Error`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::fmt;
-    /// use std::mem;
-    ///
-    /// #[derive(Debug)]
-    /// struct AnError;
-    ///
-    /// impl fmt::Display for AnError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "An error")
-    ///     }
-    /// }
-    ///
-    /// impl Error for AnError {}
-    ///
-    /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
-    /// let a_boxed_error = Box::<dyn Error>::from(an_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: E) -> Box<dyn Error + 'a> {
-        Box::new(err)
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
-    /// dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::fmt;
-    /// use std::mem;
-    ///
-    /// #[derive(Debug)]
-    /// struct AnError;
-    ///
-    /// impl fmt::Display for AnError {
-    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    ///         write!(f, "An error")
-    ///     }
-    /// }
-    ///
-    /// impl Error for AnError {}
-    ///
-    /// unsafe impl Send for AnError {}
-    ///
-    /// unsafe impl Sync for AnError {}
-    ///
-    /// let an_error = AnError;
-    /// assert!(0 == mem::size_of_val(&an_error));
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
-        Box::new(err)
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_string_error = "a string error".to_string();
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    #[inline]
-    fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
-        struct StringError(String);
-
-        impl Error for StringError {
-            #[allow(deprecated)]
-            fn description(&self) -> &str {
-                &self.0
-            }
-        }
-
-        impl fmt::Display for StringError {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                fmt::Display::fmt(&self.0, f)
-            }
-        }
-
-        // Purposefully skip printing "StringError(..)"
-        impl fmt::Debug for StringError {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                fmt::Debug::fmt(&self.0, f)
-            }
-        }
-
-        Box::new(StringError(err))
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<String> for Box<dyn Error + 'a> {
-    /// Converts a [`String`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_string_error = "a string error".to_string();
-    /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(str_err: String) -> Box<dyn Error + 'a> {
-        let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
-        let err2: Box<dyn Error> = err1;
-        err2
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// [`str`]: prim@str
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_str_error = "a str error";
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    #[inline]
-    fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "string_box_error", since = "1.6.0")]
-impl<'a> From<&str> for Box<dyn Error + 'a> {
-    /// Converts a [`str`] into a box of dyn [`Error`].
-    ///
-    /// [`str`]: prim@str
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    ///
-    /// let a_str_error = "a str error";
-    /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: &str) -> Box<dyn Error + 'a> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
-    /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    /// use std::borrow::Cow;
-    ///
-    /// let a_cow_str_error = Cow::from("a str error");
-    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
-    /// assert!(
-    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
-        From::from(String::from(err))
-    }
-}
-
-#[cfg(not(no_global_oom_handling))]
-#[stable(feature = "cow_box_error", since = "1.22.0")]
-impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
-    /// Converts a [`Cow`] into a box of dyn [`Error`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::error::Error;
-    /// use std::mem;
-    /// use std::borrow::Cow;
-    ///
-    /// let a_cow_str_error = Cow::from("a str error");
-    /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
-    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
-    /// ```
-    fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
-        From::from(String::from(err))
-    }
-}
-
 #[stable(feature = "box_error", since = "1.8.0")]
-impl<T: core::error::Error> core::error::Error for Box<T> {
+impl<E: Error> Error for Box<E> {
     #[allow(deprecated, deprecated_in_future)]
     fn description(&self) -> &str {
-        core::error::Error::description(&**self)
+        Error::description(&**self)
     }
 
     #[allow(deprecated)]
-    fn cause(&self) -> Option<&dyn core::error::Error> {
-        core::error::Error::cause(&**self)
+    fn cause(&self) -> Option<&dyn Error> {
+        Error::cause(&**self)
     }
 
-    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
-        core::error::Error::source(&**self)
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        Error::source(&**self)
     }
 
-    fn provide<'b>(&'b self, request: &mut core::error::Request<'b>) {
-        core::error::Error::provide(&**self, request);
+    fn provide<'b>(&'b self, request: &mut error::Request<'b>) {
+        Error::provide(&**self, request);
     }
 }
-
-#[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
-unsafe impl<T: ?Sized, A: Allocator> PinCoerceUnsized for Box<T, A> {}
diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs
new file mode 100644
index 00000000000..19a583ca546
--- /dev/null
+++ b/library/alloc/src/boxed/convert.rs
@@ -0,0 +1,747 @@
+use core::any::Any;
+use core::error::Error;
+use core::mem;
+use core::pin::Pin;
+#[cfg(not(no_global_oom_handling))]
+use core::{fmt, ptr};
+
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::borrow::Cow;
+use crate::boxed::Box;
+#[cfg(not(no_global_oom_handling))]
+use crate::raw_vec::RawVec;
+#[cfg(not(no_global_oom_handling))]
+use crate::str::from_boxed_utf8_unchecked;
+#[cfg(not(no_global_oom_handling))]
+use crate::string::String;
+#[cfg(not(no_global_oom_handling))]
+use crate::vec::Vec;
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "from_for_ptrs", since = "1.6.0")]
+impl<T> From<T> for Box<T> {
+    /// Converts a `T` into a `Box<T>`
+    ///
+    /// The conversion allocates on the heap and moves `t`
+    /// from the stack into it.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// let x = 5;
+    /// let boxed = Box::new(5);
+    ///
+    /// assert_eq!(Box::from(x), boxed);
+    /// ```
+    fn from(t: T) -> Self {
+        Box::new(t)
+    }
+}
+
+#[stable(feature = "pin", since = "1.33.0")]
+impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
+where
+    A: 'static,
+{
+    /// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
+    /// `*boxed` will be pinned in memory and unable to be moved.
+    ///
+    /// This conversion does not allocate on the heap and happens in place.
+    ///
+    /// This is also available via [`Box::into_pin`].
+    ///
+    /// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
+    /// can also be written more concisely using <code>[Box::pin]\(x)</code>.
+    /// This `From` implementation is useful if you already have a `Box<T>`, or you are
+    /// constructing a (pinned) `Box` in a different way than with [`Box::new`].
+    fn from(boxed: Box<T, A>) -> Self {
+        Box::into_pin(boxed)
+    }
+}
+
+/// Specialization trait used for `From<&[T]>`.
+#[cfg(not(no_global_oom_handling))]
+trait BoxFromSlice<T> {
+    fn from_slice(slice: &[T]) -> Self;
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Clone> BoxFromSlice<T> for Box<[T]> {
+    #[inline]
+    default fn from_slice(slice: &[T]) -> Self {
+        slice.to_vec().into_boxed_slice()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+impl<T: Copy> BoxFromSlice<T> for Box<[T]> {
+    #[inline]
+    fn from_slice(slice: &[T]) -> Self {
+        let len = slice.len();
+        let buf = RawVec::with_capacity(len);
+        unsafe {
+            ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
+            buf.into_box(slice.len()).assume_init()
+        }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl<T: Clone> From<&[T]> for Box<[T]> {
+    /// Converts a `&[T]` into a `Box<[T]>`
+    ///
+    /// This conversion allocates on the heap
+    /// and performs a copy of `slice` and its contents.
+    ///
+    /// # Examples
+    /// ```rust
+    /// // create a &[u8] which will be used to create a Box<[u8]>
+    /// let slice: &[u8] = &[104, 101, 108, 108, 111];
+    /// let boxed_slice: Box<[u8]> = Box::from(slice);
+    ///
+    /// println!("{boxed_slice:?}");
+    /// ```
+    #[inline]
+    fn from(slice: &[T]) -> Box<[T]> {
+        <Self as BoxFromSlice<T>>::from_slice(slice)
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl<T: Clone> From<Cow<'_, [T]>> for Box<[T]> {
+    /// Converts a `Cow<'_, [T]>` into a `Box<[T]>`
+    ///
+    /// When `cow` is the `Cow::Borrowed` variant, this
+    /// conversion allocates on the heap and copies the
+    /// underlying slice. Otherwise, it will try to reuse the owned
+    /// `Vec`'s allocation.
+    #[inline]
+    fn from(cow: Cow<'_, [T]>) -> Box<[T]> {
+        match cow {
+            Cow::Borrowed(slice) => Box::from(slice),
+            Cow::Owned(slice) => Box::from(slice),
+        }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_slice", since = "1.17.0")]
+impl From<&str> for Box<str> {
+    /// Converts a `&str` into a `Box<str>`
+    ///
+    /// This conversion allocates on the heap
+    /// and performs a copy of `s`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// let boxed: Box<str> = Box::from("hello");
+    /// println!("{boxed}");
+    /// ```
+    #[inline]
+    fn from(s: &str) -> Box<str> {
+        unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_cow", since = "1.45.0")]
+impl From<Cow<'_, str>> for Box<str> {
+    /// Converts a `Cow<'_, str>` into a `Box<str>`
+    ///
+    /// When `cow` is the `Cow::Borrowed` variant, this
+    /// conversion allocates on the heap and copies the
+    /// underlying `str`. Otherwise, it will try to reuse the owned
+    /// `String`'s allocation.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use std::borrow::Cow;
+    ///
+    /// let unboxed = Cow::Borrowed("hello");
+    /// let boxed: Box<str> = Box::from(unboxed);
+    /// println!("{boxed}");
+    /// ```
+    ///
+    /// ```rust
+    /// # use std::borrow::Cow;
+    /// let unboxed = Cow::Owned("hello".to_string());
+    /// let boxed: Box<str> = Box::from(unboxed);
+    /// println!("{boxed}");
+    /// ```
+    #[inline]
+    fn from(cow: Cow<'_, str>) -> Box<str> {
+        match cow {
+            Cow::Borrowed(s) => Box::from(s),
+            Cow::Owned(s) => Box::from(s),
+        }
+    }
+}
+
+#[stable(feature = "boxed_str_conv", since = "1.19.0")]
+impl<A: Allocator> From<Box<str, A>> for Box<[u8], A> {
+    /// Converts a `Box<str>` into a `Box<[u8]>`
+    ///
+    /// This conversion does not allocate on the heap and happens in place.
+    ///
+    /// # Examples
+    /// ```rust
+    /// // create a Box<str> which will be used to create a Box<[u8]>
+    /// let boxed: Box<str> = Box::from("hello");
+    /// let boxed_str: Box<[u8]> = Box::from(boxed);
+    ///
+    /// // create a &[u8] which will be used to create a Box<[u8]>
+    /// let slice: &[u8] = &[104, 101, 108, 108, 111];
+    /// let boxed_slice = Box::from(slice);
+    ///
+    /// assert_eq!(boxed_slice, boxed_str);
+    /// ```
+    #[inline]
+    fn from(s: Box<str, A>) -> Self {
+        let (raw, alloc) = Box::into_raw_with_allocator(s);
+        unsafe { Box::from_raw_in(raw as *mut [u8], alloc) }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "box_from_array", since = "1.45.0")]
+impl<T, const N: usize> From<[T; N]> for Box<[T]> {
+    /// Converts a `[T; N]` into a `Box<[T]>`
+    ///
+    /// This conversion moves the array to newly heap-allocated memory.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// let boxed: Box<[u8]> = Box::from([4, 2]);
+    /// println!("{boxed:?}");
+    /// ```
+    fn from(array: [T; N]) -> Box<[T]> {
+        Box::new(array)
+    }
+}
+
+/// Casts a boxed slice to a boxed array.
+///
+/// # Safety
+///
+/// `boxed_slice.len()` must be exactly `N`.
+unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
+    boxed_slice: Box<[T], A>,
+) -> Box<[T; N], A> {
+    debug_assert_eq!(boxed_slice.len(), N);
+
+    let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
+    // SAFETY: Pointer and allocator came from an existing box,
+    // and our safety condition requires that the length is exactly `N`
+    unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
+}
+
+#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
+impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
+    type Error = Box<[T]>;
+
+    /// Attempts to convert a `Box<[T]>` into a `Box<[T; N]>`.
+    ///
+    /// The conversion occurs in-place and does not require a
+    /// new memory allocation.
+    ///
+    /// # Errors
+    ///
+    /// Returns the old `Box<[T]>` in the `Err` variant if
+    /// `boxed_slice.len()` does not equal `N`.
+    fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
+        if boxed_slice.len() == N {
+            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
+        } else {
+            Err(boxed_slice)
+        }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
+impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
+    type Error = Vec<T>;
+
+    /// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
+    ///
+    /// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
+    /// but will require a reallocation otherwise.
+    ///
+    /// # Errors
+    ///
+    /// Returns the original `Vec<T>` in the `Err` variant if
+    /// `boxed_slice.len()` does not equal `N`.
+    ///
+    /// # Examples
+    ///
+    /// This can be used with [`vec!`] to create an array on the heap:
+    ///
+    /// ```
+    /// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
+    /// assert_eq!(state.len(), 100);
+    /// ```
+    fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
+        if vec.len() == N {
+            let boxed_slice = vec.into_boxed_slice();
+            Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
+        } else {
+            Err(vec)
+        }
+    }
+}
+
+impl<A: Allocator> Box<dyn Any, A> {
+    /// Attempts to downcast the box to a concrete type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::any::Any;
+    ///
+    /// fn print_if_string(value: Box<dyn Any>) {
+    ///     if let Ok(string) = value.downcast::<String>() {
+    ///         println!("String ({}): {}", string.len(), string);
+    ///     }
+    /// }
+    ///
+    /// let my_string = "Hello World".to_string();
+    /// print_if_string(Box::new(my_string));
+    /// print_if_string(Box::new(0i8));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
+        }
+    }
+}
+
+impl<A: Allocator> Box<dyn Any + Send, A> {
+    /// Attempts to downcast the box to a concrete type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::any::Any;
+    ///
+    /// fn print_if_string(value: Box<dyn Any + Send>) {
+    ///     if let Ok(string) = value.downcast::<String>() {
+    ///         println!("String ({}): {}", string.len(), string);
+    ///     }
+    /// }
+    ///
+    /// let my_string = "Hello World".to_string();
+    /// print_if_string(Box::new(my_string));
+    /// print_if_string(Box::new(0i8));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any + Send> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
+        }
+    }
+}
+
+impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
+    /// Attempts to downcast the box to a concrete type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::any::Any;
+    ///
+    /// fn print_if_string(value: Box<dyn Any + Send + Sync>) {
+    ///     if let Ok(string) = value.downcast::<String>() {
+    ///         println!("String ({}): {}", string.len(), string);
+    ///     }
+    /// }
+    ///
+    /// let my_string = "Hello World".to_string();
+    /// print_if_string(Box::new(my_string));
+    /// print_if_string(Box::new(0i8));
+    /// ```
+    #[inline]
+    #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
+    pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
+        if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
+    }
+
+    /// Downcasts the box to a concrete type.
+    ///
+    /// For a safe alternative see [`downcast`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(downcast_unchecked)]
+    ///
+    /// use std::any::Any;
+    ///
+    /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
+    ///
+    /// unsafe {
+    ///     assert_eq!(*x.downcast_unchecked::<usize>(), 1);
+    /// }
+    /// ```
+    ///
+    /// # Safety
+    ///
+    /// The contained value must be of type `T`. Calling this method
+    /// with the incorrect type is *undefined behavior*.
+    ///
+    /// [`downcast`]: Self::downcast
+    #[inline]
+    #[unstable(feature = "downcast_unchecked", issue = "90850")]
+    pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
+        debug_assert!(self.is::<T>());
+        unsafe {
+            let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
+                Box::into_raw_with_allocator(self);
+            Box::from_raw_in(raw as *mut T, alloc)
+        }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
+    /// Converts a type of [`Error`] into a box of dyn [`Error`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::fmt;
+    /// use std::mem;
+    ///
+    /// #[derive(Debug)]
+    /// struct AnError;
+    ///
+    /// impl fmt::Display for AnError {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         write!(f, "An error")
+    ///     }
+    /// }
+    ///
+    /// impl Error for AnError {}
+    ///
+    /// let an_error = AnError;
+    /// assert!(0 == mem::size_of_val(&an_error));
+    /// let a_boxed_error = Box::<dyn Error>::from(an_error);
+    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(err: E) -> Box<dyn Error + 'a> {
+        Box::new(err)
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
+    /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
+    /// dyn [`Error`] + [`Send`] + [`Sync`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::fmt;
+    /// use std::mem;
+    ///
+    /// #[derive(Debug)]
+    /// struct AnError;
+    ///
+    /// impl fmt::Display for AnError {
+    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         write!(f, "An error")
+    ///     }
+    /// }
+    ///
+    /// impl Error for AnError {}
+    ///
+    /// unsafe impl Send for AnError {}
+    ///
+    /// unsafe impl Sync for AnError {}
+    ///
+    /// let an_error = AnError;
+    /// assert!(0 == mem::size_of_val(&an_error));
+    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
+    /// assert!(
+    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
+        Box::new(err)
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<String> for Box<dyn Error + Send + Sync + 'a> {
+    /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    ///
+    /// let a_string_error = "a string error".to_string();
+    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
+    /// assert!(
+    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    #[inline]
+    fn from(err: String) -> Box<dyn Error + Send + Sync + 'a> {
+        struct StringError(String);
+
+        impl Error for StringError {
+            #[allow(deprecated)]
+            fn description(&self) -> &str {
+                &self.0
+            }
+        }
+
+        impl fmt::Display for StringError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt::Display::fmt(&self.0, f)
+            }
+        }
+
+        // Purposefully skip printing "StringError(..)"
+        impl fmt::Debug for StringError {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt::Debug::fmt(&self.0, f)
+            }
+        }
+
+        Box::new(StringError(err))
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl<'a> From<String> for Box<dyn Error + 'a> {
+    /// Converts a [`String`] into a box of dyn [`Error`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    ///
+    /// let a_string_error = "a string error".to_string();
+    /// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
+    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(str_err: String) -> Box<dyn Error + 'a> {
+        let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
+        let err2: Box<dyn Error> = err1;
+        err2
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
+    /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+    ///
+    /// [`str`]: prim@str
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    ///
+    /// let a_str_error = "a str error";
+    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
+    /// assert!(
+    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    #[inline]
+    fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
+        From::from(String::from(err))
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "string_box_error", since = "1.6.0")]
+impl<'a> From<&str> for Box<dyn Error + 'a> {
+    /// Converts a [`str`] into a box of dyn [`Error`].
+    ///
+    /// [`str`]: prim@str
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    ///
+    /// let a_str_error = "a str error";
+    /// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
+    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(err: &str) -> Box<dyn Error + 'a> {
+        From::from(String::from(err))
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
+    /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    /// use std::borrow::Cow;
+    ///
+    /// let a_cow_str_error = Cow::from("a str error");
+    /// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
+    /// assert!(
+    ///     mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
+        From::from(String::from(err))
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "cow_box_error", since = "1.22.0")]
+impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + 'a> {
+    /// Converts a [`Cow`] into a box of dyn [`Error`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::error::Error;
+    /// use std::mem;
+    /// use std::borrow::Cow;
+    ///
+    /// let a_cow_str_error = Cow::from("a str error");
+    /// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
+    /// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
+    /// ```
+    fn from(err: Cow<'b, str>) -> Box<dyn Error + 'a> {
+        From::from(String::from(err))
+    }
+}
+
+impl dyn Error {
+    /// Attempts to downcast the box to a concrete type.
+    #[inline]
+    #[stable(feature = "error_downcast", since = "1.3.0")]
+    #[rustc_allow_incoherent_impl]
+    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
+        if self.is::<T>() {
+            unsafe {
+                let raw: *mut dyn Error = Box::into_raw(self);
+                Ok(Box::from_raw(raw as *mut T))
+            }
+        } else {
+            Err(self)
+        }
+    }
+}
+
+impl dyn Error + Send {
+    /// Attempts to downcast the box to a concrete type.
+    #[inline]
+    #[stable(feature = "error_downcast", since = "1.3.0")]
+    #[rustc_allow_incoherent_impl]
+    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
+        let err: Box<dyn Error> = self;
+        <dyn Error>::downcast(err).map_err(|s| unsafe {
+            // Reapply the `Send` marker.
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
+        })
+    }
+}
+
+impl dyn Error + Send + Sync {
+    /// Attempts to downcast the box to a concrete type.
+    #[inline]
+    #[stable(feature = "error_downcast", since = "1.3.0")]
+    #[rustc_allow_incoherent_impl]
+    pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
+        let err: Box<dyn Error> = self;
+        <dyn Error>::downcast(err).map_err(|s| unsafe {
+            // Reapply the `Send + Sync` markers.
+            mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
+        })
+    }
+}
diff --git a/library/alloc/src/boxed/iter.rs b/library/alloc/src/boxed/iter.rs
new file mode 100644
index 00000000000..90582aa49c6
--- /dev/null
+++ b/library/alloc/src/boxed/iter.rs
@@ -0,0 +1,194 @@
+use core::async_iter::AsyncIterator;
+use core::iter::FusedIterator;
+use core::pin::Pin;
+use core::slice;
+use core::task::{Context, Poll};
+
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
+use crate::borrow::Cow;
+use crate::boxed::Box;
+#[cfg(not(no_global_oom_handling))]
+use crate::string::String;
+use crate::vec;
+#[cfg(not(no_global_oom_handling))]
+use crate::vec::Vec;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator + ?Sized, A: Allocator> Iterator for Box<I, A> {
+    type Item = I::Item;
+    fn next(&mut self) -> Option<I::Item> {
+        (**self).next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (**self).size_hint()
+    }
+    fn nth(&mut self, n: usize) -> Option<I::Item> {
+        (**self).nth(n)
+    }
+    fn last(self) -> Option<I::Item> {
+        BoxIter::last(self)
+    }
+}
+
+trait BoxIter {
+    type Item;
+    fn last(self) -> Option<Self::Item>;
+}
+
+impl<I: Iterator + ?Sized, A: Allocator> BoxIter for Box<I, A> {
+    type Item = I::Item;
+    default fn last(self) -> Option<I::Item> {
+        #[inline]
+        fn some<T>(_: Option<T>, x: T) -> Option<T> {
+            Some(x)
+        }
+
+        self.fold(None, some)
+    }
+}
+
+/// Specialization for sized `I`s that uses `I`s implementation of `last()`
+/// instead of the default.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator, A: Allocator> BoxIter for Box<I, A> {
+    fn last(self) -> Option<I::Item> {
+        (*self).last()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator + ?Sized, A: Allocator> DoubleEndedIterator for Box<I, A> {
+    fn next_back(&mut self) -> Option<I::Item> {
+        (**self).next_back()
+    }
+    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
+        (**self).nth_back(n)
+    }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A> {
+    fn len(&self) -> usize {
+        (**self).len()
+    }
+    fn is_empty(&self) -> bool {
+        (**self).is_empty()
+    }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
+
+#[unstable(feature = "async_iterator", issue = "79024")]
+impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
+    type Item = S::Item;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        Pin::new(&mut **self).poll_next(cx)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (**self).size_hint()
+    }
+}
+
+/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<I, A: Allocator> !Iterator for Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
+
+// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<I, A: Allocator> IntoIterator for Box<[I], A> {
+    type IntoIter = vec::IntoIter<I, A>;
+    type Item = I;
+    fn into_iter(self) -> vec::IntoIter<I, A> {
+        self.into_vec().into_iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
+    type IntoIter = slice::Iter<'a, I>;
+    type Item = &'a I;
+    fn into_iter(self) -> slice::Iter<'a, I> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "1.80.0")]
+impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
+    type IntoIter = slice::IterMut<'a, I>;
+    type Item = &'a mut I;
+    fn into_iter(self) -> slice::IterMut<'a, I> {
+        self.iter_mut()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_slice_from_iter", since = "1.32.0")]
+impl<I> FromIterator<I> for Box<[I]> {
+    fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
+        iter.into_iter().collect::<Vec<_>>().into_boxed_slice()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl FromIterator<char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<&'a char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<&'a str> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl FromIterator<String> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "1.80.0")]
+impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 9fdd51ce331..fc8646e96d9 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -376,6 +376,21 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
     unsafe fn from_ptr_in(ptr: *mut RcInner<T>, alloc: A) -> Self {
         unsafe { Self::from_inner_in(NonNull::new_unchecked(ptr), alloc) }
     }
+
+    // Non-inlined part of `drop`.
+    #[inline(never)]
+    unsafe fn drop_slow(&mut self) {
+        // Reconstruct the "strong weak" pointer and drop it when this
+        // variable goes out of scope. This ensures that the memory is
+        // deallocated even if the destructor of `T` panics.
+        let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };
+
+        // Destroy the contained object.
+        // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed.
+        unsafe {
+            ptr::drop_in_place(&mut (*self.ptr.as_ptr()).value);
+        }
+    }
 }
 
 impl<T> Rc<T> {
@@ -2252,21 +2267,12 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Rc<T, A> {
     /// drop(foo);    // Doesn't print anything
     /// drop(foo2);   // Prints "dropped!"
     /// ```
+    #[inline]
     fn drop(&mut self) {
         unsafe {
             self.inner().dec_strong();
             if self.inner().strong() == 0 {
-                // destroy the contained object
-                ptr::drop_in_place(Self::get_mut_unchecked(self));
-
-                // remove the implicit "strong weak" pointer now that we've
-                // destroyed the contents.
-                self.inner().dec_weak();
-
-                if self.inner().weak() == 0 {
-                    self.alloc
-                        .deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()));
-                }
+                self.drop_slow();
             }
         }
     }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 15a1b0f2834..98a2fe24257 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -1872,15 +1872,17 @@ impl<T: ?Sized, A: Allocator> Arc<T, A> {
     // Non-inlined part of `drop`.
     #[inline(never)]
     unsafe fn drop_slow(&mut self) {
+        // Drop the weak ref collectively held by all strong references when this
+        // variable goes out of scope. This ensures that the memory is deallocated
+        // even if the destructor of `T` panics.
+        // Take a reference to `self.alloc` instead of cloning because 1. it'll last long
+        // enough, and 2. you should be able to drop `Arc`s with unclonable allocators
+        let _weak = Weak { ptr: self.ptr, alloc: &self.alloc };
+
         // Destroy the data at this time, even though we must not free the box
         // allocation itself (there might still be weak pointers lying around).
-        unsafe { ptr::drop_in_place(Self::get_mut_unchecked(self)) };
-
-        // Drop the weak ref collectively held by all strong references
-        // Take a reference to `self.alloc` instead of cloning because 1. it'll
-        // last long enough, and 2. you should be able to drop `Arc`s with
-        // unclonable allocators
-        drop(Weak { ptr: self.ptr, alloc: &self.alloc });
+        // We cannot use `get_mut_unchecked` here, because `self.alloc` is borrowed.
+        unsafe { ptr::drop_in_place(&mut (*self.ptr.as_ptr()).data) };
     }
 
     /// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to
diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs
index dc27c578b57..a259c0131ec 100644
--- a/library/alloc/tests/arc.rs
+++ b/library/alloc/tests/arc.rs
@@ -1,5 +1,5 @@
 use std::any::Any;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::iter::TrustedLen;
 use std::mem;
 use std::sync::{Arc, Weak};
@@ -89,7 +89,7 @@ fn eq() {
 
 // The test code below is identical to that in `rc.rs`.
 // For better maintainability we therefore define this type alias.
-type Rc<T> = Arc<T>;
+type Rc<T, A = std::alloc::Global> = Arc<T, A>;
 
 const SHARED_ITER_MAX: u16 = 100;
 
@@ -210,6 +210,42 @@ fn weak_may_dangle() {
     // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
 }
 
+/// Test that a panic from a destructor does not leak the allocation.
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn panic_no_leak() {
+    use std::alloc::{AllocError, Allocator, Global, Layout};
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+    use std::ptr::NonNull;
+
+    struct AllocCount(Cell<i32>);
+    unsafe impl Allocator for AllocCount {
+        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+            self.0.set(self.0.get() + 1);
+            Global.allocate(layout)
+        }
+        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+            self.0.set(self.0.get() - 1);
+            unsafe { Global.deallocate(ptr, layout) }
+        }
+    }
+
+    struct PanicOnDrop;
+    impl Drop for PanicOnDrop {
+        fn drop(&mut self) {
+            panic!("PanicOnDrop");
+        }
+    }
+
+    let alloc = AllocCount(Cell::new(0));
+    let rc = Rc::new_in(PanicOnDrop, &alloc);
+    assert_eq!(alloc.0.get(), 1);
+
+    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
+    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
+    assert_eq!(alloc.0.get(), 0);
+}
+
 /// This is similar to the doc-test for `Arc::make_mut()`, but on an unsized type (slice).
 #[test]
 fn make_mut_unsized() {
diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs
index bfc31a626fa..6a8ba5c92fb 100644
--- a/library/alloc/tests/boxed.rs
+++ b/library/alloc/tests/boxed.rs
@@ -4,6 +4,7 @@ use core::mem::MaybeUninit;
 use core::ptr::NonNull;
 
 #[test]
+#[cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
 fn uninitialized_zero_size_box() {
     assert_eq!(
         &*Box::<()>::new_uninit() as *const _,
@@ -59,6 +60,44 @@ fn box_deref_lval() {
     assert_eq!(x.get(), 1000);
 }
 
+/// Test that a panic from a destructor does not leak the allocation.
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn panic_no_leak() {
+    use std::alloc::{AllocError, Allocator, Global, Layout};
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+    use std::ptr::NonNull;
+
+    struct AllocCount(Cell<i32>);
+    unsafe impl Allocator for AllocCount {
+        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+            self.0.set(self.0.get() + 1);
+            Global.allocate(layout)
+        }
+        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+            self.0.set(self.0.get() - 1);
+            unsafe { Global.deallocate(ptr, layout) }
+        }
+    }
+
+    struct PanicOnDrop {
+        _data: u8,
+    }
+    impl Drop for PanicOnDrop {
+        fn drop(&mut self) {
+            panic!("PanicOnDrop");
+        }
+    }
+
+    let alloc = AllocCount(Cell::new(0));
+    let b = Box::new_in(PanicOnDrop { _data: 42 }, &alloc);
+    assert_eq!(alloc.0.get(), 1);
+
+    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(b))).unwrap_err();
+    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
+    assert_eq!(alloc.0.get(), 0);
+}
+
 #[allow(unused)]
 pub struct ConstAllocator;
 
diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs
index 29dbdcf225e..451765d7242 100644
--- a/library/alloc/tests/rc.rs
+++ b/library/alloc/tests/rc.rs
@@ -1,5 +1,5 @@
 use std::any::Any;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
 use std::iter::TrustedLen;
 use std::mem;
 use std::rc::{Rc, Weak};
@@ -206,6 +206,42 @@ fn weak_may_dangle() {
     // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
 }
 
+/// Test that a panic from a destructor does not leak the allocation.
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn panic_no_leak() {
+    use std::alloc::{AllocError, Allocator, Global, Layout};
+    use std::panic::{AssertUnwindSafe, catch_unwind};
+    use std::ptr::NonNull;
+
+    struct AllocCount(Cell<i32>);
+    unsafe impl Allocator for AllocCount {
+        fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+            self.0.set(self.0.get() + 1);
+            Global.allocate(layout)
+        }
+        unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
+            self.0.set(self.0.get() - 1);
+            unsafe { Global.deallocate(ptr, layout) }
+        }
+    }
+
+    struct PanicOnDrop;
+    impl Drop for PanicOnDrop {
+        fn drop(&mut self) {
+            panic!("PanicOnDrop");
+        }
+    }
+
+    let alloc = AllocCount(Cell::new(0));
+    let rc = Rc::new_in(PanicOnDrop, &alloc);
+    assert_eq!(alloc.0.get(), 1);
+
+    let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err();
+    assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop");
+    assert_eq!(alloc.0.get(), 0);
+}
+
 #[allow(unused)]
 mod pin_coerce_unsized {
     use alloc::rc::{Rc, UniqueRc};
diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs
index 3f1c58bbd72..32d15c386cb 100644
--- a/library/core/benches/lib.rs
+++ b/library/core/benches/lib.rs
@@ -8,7 +8,6 @@
 #![feature(iter_array_chunks)]
 #![feature(iter_next_chunk)]
 #![feature(iter_advance_by)]
-#![feature(isqrt)]
 
 extern crate test;
 
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 0b106244793..7e6c042274d 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -304,6 +304,7 @@ pub use once::OnceCell;
 /// ```
 ///
 /// See the [module-level documentation](self) for more.
+#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
 #[rustc_pub_transparent]
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index 9c667edb476..206bbf5690e 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -320,8 +320,9 @@ impl char {
     /// '1'.is_digit(37);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_char_is_digit", issue = "132241")]
     #[inline]
-    pub fn is_digit(self, radix: u32) -> bool {
+    pub const fn is_digit(self, radix: u32) -> bool {
         self.to_digit(radix).is_some()
     }
 
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 0f4386190ee..93dd351b029 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -464,7 +464,9 @@ impl CStr {
     /// behavior when `ptr` is used inside the `unsafe` block:
     ///
     /// ```no_run
-    /// # #![allow(unused_must_use)] #![allow(temporary_cstring_as_ptr)]
+    /// # #![allow(unused_must_use)]
+    /// # #![cfg_attr(bootstrap, expect(temporary_cstring_as_ptr))]
+    /// # #![cfg_attr(not(bootstrap), expect(dangling_pointers_from_temporaries))]
     /// use std::ffi::CString;
     ///
     /// // Do not do this:
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 9c3bf827438..115fdd7a140 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -134,6 +134,7 @@
 #![feature(const_raw_ptr_comparison)]
 #![feature(const_size_of_val)]
 #![feature(const_size_of_val_raw)]
+#![feature(const_sockaddr_setters)]
 #![feature(const_strict_overflow_ops)]
 #![feature(const_swap)]
 #![feature(const_try)]
@@ -149,7 +150,6 @@
 #![feature(ip)]
 #![feature(is_ascii_octdigit)]
 #![feature(is_val_statically_known)]
-#![feature(isqrt)]
 #![feature(lazy_get)]
 #![feature(link_cfg)]
 #![feature(non_null_from_ref)]
@@ -185,7 +185,9 @@
 #![feature(cfg_target_has_atomic_equal_alignment)]
 #![feature(cfg_ub_checks)]
 #![feature(const_for)]
+#![feature(const_is_char_boundary)]
 #![feature(const_precise_live_drops)]
+#![feature(const_str_split_at)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
 #![feature(doc_cfg)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 1237fc82a17..1c5c58d64a2 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1063,9 +1063,10 @@ pub trait FnPtr: Copy + Clone {
 }
 
 /// Derive macro generating impls of traits related to smart pointers.
-#[rustc_builtin_macro(SmartPointer, attributes(pointee))]
+#[rustc_builtin_macro(CoercePointee, attributes(pointee))]
 #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize)]
-#[unstable(feature = "derive_smart_pointer", issue = "123430")]
-pub macro SmartPointer($item:item) {
+#[unstable(feature = "derive_coerce_pointee", issue = "123430")]
+#[cfg(not(bootstrap))]
+pub macro CoercePointee($item:item) {
     /* compiler built-in */
 }
diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs
index a46495add6a..9204797e6e1 100644
--- a/library/core/src/net/socket_addr.rs
+++ b/library/core/src/net/socket_addr.rs
@@ -198,9 +198,10 @@ impl SocketAddr {
     /// socket.set_ip(IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
     /// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(10, 10, 0, 1)));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: IpAddr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: IpAddr) {
         // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away.
         match (self, new_ip) {
             (&mut SocketAddr::V4(ref mut a), IpAddr::V4(new_ip)) => a.set_ip(new_ip),
@@ -241,9 +242,10 @@ impl SocketAddr {
     /// socket.set_port(1025);
     /// assert_eq!(socket.port(), 1025);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         match *self {
             SocketAddr::V4(ref mut a) => a.set_port(new_port),
             SocketAddr::V6(ref mut a) => a.set_port(new_port),
@@ -346,9 +348,10 @@ impl SocketAddrV4 {
     /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
     /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: Ipv4Addr) {
         self.ip = new_ip;
     }
 
@@ -381,9 +384,10 @@ impl SocketAddrV4 {
     /// socket.set_port(4242);
     /// assert_eq!(socket.port(), 4242);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
 }
@@ -442,9 +446,10 @@ impl SocketAddrV6 {
     /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
     /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_ip(&mut self, new_ip: Ipv6Addr) {
         self.ip = new_ip;
     }
 
@@ -477,9 +482,10 @@ impl SocketAddrV6 {
     /// socket.set_port(4242);
     /// assert_eq!(socket.port(), 4242);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_port(&mut self, new_port: u16) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_port(&mut self, new_port: u16) {
         self.port = new_port;
     }
 
@@ -524,9 +530,10 @@ impl SocketAddrV6 {
     /// socket.set_flowinfo(56);
     /// assert_eq!(socket.flowinfo(), 56);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.flowinfo = new_flowinfo;
     }
 
@@ -566,9 +573,10 @@ impl SocketAddrV6 {
     /// socket.set_scope_id(42);
     /// assert_eq!(socket.scope_id(), 42);
     /// ```
-    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     #[inline]
-    pub fn set_scope_id(&mut self, new_scope_id: u32) {
+    #[stable(feature = "sockaddr_setters", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")]
+    pub const fn set_scope_id(&mut self, new_scope_id: u32) {
         self.scope_id = new_scope_id;
     }
 }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 1d640ea74c4..3a9060df286 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1629,11 +1629,10 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_isqrt(), Some(3));")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2880,11 +2879,10 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -3181,44 +3179,6 @@ macro_rules! int_impl {
             }
         }
 
-        /// Calculates the middle point of `self` and `rhs`.
-        ///
-        /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a
-        /// sufficiently-large signed integral type. This implies that the result is
-        /// always rounded towards negative infinity and that no overflow will ever occur.
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_midpoint)]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")]
-        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")]
-        /// ```
-        #[unstable(feature = "num_midpoint", issue = "110840")]
-        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
-        #[rustc_allow_const_fn_unstable(const_num_midpoint)]
-        #[must_use = "this returns the result of the operation, \
-                      without modifying the original"]
-        #[inline]
-        pub const fn midpoint(self, rhs: Self) -> Self {
-            const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs();
-
-            // Map an $SelfT to an $UnsignedT
-            // ex: i8 [-128; 127] to [0; 255]
-            const fn map(a: $SelfT) -> $UnsignedT {
-                (a as $UnsignedT) ^ U
-            }
-
-            // Map an $UnsignedT to an $SelfT
-            // ex: u8 [0; 255] to [-128; 127]
-            const fn demap(a: $UnsignedT) -> $SelfT {
-                (a ^ U) as $SelfT
-            }
-
-            demap(<$UnsignedT>::midpoint(map(self), map(rhs)))
-        }
-
         /// Returns the logarithm of the number with respect to an arbitrary base,
         /// rounded down.
         ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index f95cfd33ae5..6a0b40ff517 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -124,6 +124,37 @@ macro_rules! midpoint_impl {
             ((self ^ rhs) >> 1) + (self & rhs)
         }
     };
+    ($SelfT:ty, signed) => {
+        /// Calculates the middle point of `self` and `rhs`.
+        ///
+        /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+        /// sufficiently-large signed integral type. This implies that the result is
+        /// always rounded towards zero and that no overflow will ever occur.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_midpoint)]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+        #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+        /// ```
+        #[unstable(feature = "num_midpoint", issue = "110840")]
+        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn midpoint(self, rhs: Self) -> Self {
+            // Use the well known branchless algorithm from Hacker's Delight to compute
+            // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
+            let t = ((self ^ rhs) >> 1) + (self & rhs);
+            // Except that it fails for integers whose sum is an odd negative number as
+            // their floor is one less than their average. So we adjust the result.
+            t + (if t < 0 { 1 } else { 0 } & (self ^ rhs))
+        }
+    };
     ($SelfT:ty, $WideT:ty, unsigned) => {
         /// Calculates the middle point of `self` and `rhs`.
         ///
@@ -147,6 +178,32 @@ macro_rules! midpoint_impl {
             ((self as $WideT + rhs as $WideT) / 2) as $SelfT
         }
     };
+    ($SelfT:ty, $WideT:ty, signed) => {
+        /// Calculates the middle point of `self` and `rhs`.
+        ///
+        /// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a
+        /// sufficiently-large signed integral type. This implies that the result is
+        /// always rounded towards zero and that no overflow will ever occur.
+        ///
+        /// # Examples
+        ///
+        /// ```
+        /// #![feature(num_midpoint)]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")]
+        #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(2), 0);")]
+        #[doc = concat!("assert_eq!((-7", stringify!($SelfT), ").midpoint(0), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-7), -3);")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(7), 3);")]
+        /// ```
+        #[unstable(feature = "num_midpoint", issue = "110840")]
+        #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
+            ((self as $WideT + rhs as $WideT) / 2) as $SelfT
+        }
+    };
 }
 
 macro_rules! widening_impl {
@@ -300,6 +357,7 @@ impl i8 {
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i8, i16, signed }
 }
 
 impl i16 {
@@ -323,6 +381,7 @@ impl i16 {
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i16, i32, signed }
 }
 
 impl i32 {
@@ -346,6 +405,7 @@ impl i32 {
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i32, i64, signed }
 }
 
 impl i64 {
@@ -369,6 +429,7 @@ impl i64 {
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i64, signed }
 }
 
 impl i128 {
@@ -394,6 +455,7 @@ impl i128 {
         from_xe_bytes_doc = "",
         bound_condition = "",
     }
+    midpoint_impl! { i128, signed }
 }
 
 #[cfg(target_pointer_width = "16")]
@@ -418,6 +480,7 @@ impl isize {
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 16-bit targets",
     }
+    midpoint_impl! { isize, i32, signed }
 }
 
 #[cfg(target_pointer_width = "32")]
@@ -442,6 +505,7 @@ impl isize {
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 32-bit targets",
     }
+    midpoint_impl! { isize, i64, signed }
 }
 
 #[cfg(target_pointer_width = "64")]
@@ -466,6 +530,7 @@ impl isize {
         from_xe_bytes_doc = usize_isize_from_xe_bytes_doc!(),
         bound_condition = " on 64-bit targets",
     }
+    midpoint_impl! { isize, signed }
 }
 
 /// If the 6th bit is set ascii is lower case.
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index fdb84827e27..f6e271954fe 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -1527,7 +1527,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         /// # use std::num::NonZero;
         /// #
         /// # fn main() { test().unwrap(); }
@@ -1539,8 +1538,8 @@ macro_rules! nonzero_integer_signedness_dependent_methods {
         /// # Some(())
         /// # }
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 9c5fe563d93..eb4ea4b3c40 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -2753,11 +2753,10 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(isqrt)]
         #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".isqrt(), 3);")]
         /// ```
-        #[unstable(feature = "isqrt", issue = "116226")]
-        #[rustc_const_unstable(feature = "isqrt", issue = "116226")]
+        #[stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "isqrt", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index bf9bfd84b56..4a6fca5085c 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1612,6 +1612,9 @@ mod prim_ref {}
 /// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers)
 /// with your required signature.
 ///
+/// Note that FFI requires additional care to ensure that the ABI for both sides of the call match.
+/// The exact requirements are not currently documented.
+///
 /// ### Safety
 ///
 /// Plain function pointers are obtained by casting either plain functions, or closures that don't
@@ -1750,8 +1753,13 @@ mod prim_ref {}
 /// is also used rarely. So, most likely you do not have to worry about ABI compatibility.
 ///
 /// But assuming such circumstances, what are the rules? For this section, we are only considering
-/// the ABI of direct Rust-to-Rust calls, not linking in general -- once functions are imported via
-/// `extern` blocks, there are more things to consider that we do not go into here.
+/// the ABI of direct Rust-to-Rust calls (with both definition and callsite visible to the
+/// Rust compiler), not linking in general -- once functions are imported via `extern` blocks, there
+/// are more things to consider that we do not go into here. Note that this also applies to
+/// passing/calling functions across language boundaries via function pointers.
+///
+/// **Nothing in this section should be taken as a guarantee for non-Rust-to-Rust calls, even with
+/// types from `core::ffi` or `libc`**.
 ///
 /// For two signatures to be considered *ABI-compatible*, they must use a compatible ABI string,
 /// must take the same number of arguments, the individual argument types and the return types must
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index 89addc4cb74..9ef99e9dae8 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -185,8 +185,9 @@ impl str {
     /// ```
     #[must_use]
     #[stable(feature = "is_char_boundary", since = "1.9.0")]
+    #[rustc_const_unstable(feature = "const_is_char_boundary", issue = "131516")]
     #[inline]
-    pub fn is_char_boundary(&self, index: usize) -> bool {
+    pub const fn is_char_boundary(&self, index: usize) -> bool {
         // 0 is always ok.
         // Test for 0 explicitly so that it can optimize out the check
         // easily and skip reading string data for that case.
@@ -195,8 +196,8 @@ impl str {
             return true;
         }
 
-        match self.as_bytes().get(index) {
-            // For `None` we have two options:
+        if index >= self.len() {
+            // For `true` we have two options:
             //
             // - index == self.len()
             //   Empty strings are valid, so return true
@@ -205,9 +206,9 @@ impl str {
             //
             // The check is placed exactly here, because it improves generated
             // code on higher opt-levels. See PR #84751 for more details.
-            None => index == self.len(),
-
-            Some(&b) => b.is_utf8_char_boundary(),
+            index == self.len()
+        } else {
+            self.as_bytes()[index].is_utf8_char_boundary()
         }
     }
 
@@ -637,7 +638,8 @@ impl str {
     #[inline]
     #[must_use]
     #[stable(feature = "str_split_at", since = "1.4.0")]
-    pub fn split_at(&self, mid: usize) -> (&str, &str) {
+    #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+    pub const fn split_at(&self, mid: usize) -> (&str, &str) {
         match self.split_at_checked(mid) {
             None => slice_error_fail(self, 0, mid),
             Some(pair) => pair,
@@ -677,7 +679,8 @@ impl str {
     #[inline]
     #[must_use]
     #[stable(feature = "str_split_at", since = "1.4.0")]
-    pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
+    #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+    pub const fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
         // is_char_boundary checks that the index is in [0, .len()]
         if self.is_char_boundary(mid) {
             // SAFETY: just checked that `mid` is on a char boundary.
@@ -716,11 +719,12 @@ impl str {
     #[inline]
     #[must_use]
     #[stable(feature = "split_at_checked", since = "1.80.0")]
-    pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
+    #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+    pub const fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
         // is_char_boundary checks that the index is in [0, .len()]
         if self.is_char_boundary(mid) {
             // SAFETY: just checked that `mid` is on a char boundary.
-            Some(unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) })
+            Some(unsafe { self.split_at_unchecked(mid) })
         } else {
             None
         }
@@ -756,7 +760,9 @@ impl str {
     #[inline]
     #[must_use]
     #[stable(feature = "split_at_checked", since = "1.80.0")]
-    pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
+    #[rustc_const_unstable(feature = "const_str_split_at", issue = "131518")]
+    #[rustc_allow_const_fn_unstable(const_is_char_boundary)]
+    pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
         // is_char_boundary checks that the index is in [0, .len()]
         if self.is_char_boundary(mid) {
             // SAFETY: just checked that `mid` is on a char boundary.
@@ -772,7 +778,25 @@ impl str {
     ///
     /// The caller must ensure that `mid` is a valid byte offset from the start
     /// of the string and falls on the boundary of a UTF-8 code point.
-    unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) {
+    const unsafe fn split_at_unchecked(&self, mid: usize) -> (&str, &str) {
+        let len = self.len();
+        let ptr = self.as_ptr();
+        // SAFETY: caller guarantees `mid` is on a char boundary.
+        unsafe {
+            (
+                from_utf8_unchecked(slice::from_raw_parts(ptr, mid)),
+                from_utf8_unchecked(slice::from_raw_parts(ptr.add(mid), len - mid)),
+            )
+        }
+    }
+
+    /// Divides one string slice into two at an index.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that `mid` is a valid byte offset from the start
+    /// of the string and falls on the boundary of a UTF-8 code point.
+    const unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) {
         let len = self.len();
         let ptr = self.as_mut_ptr();
         // SAFETY: caller guarantees `mid` is on a char boundary.
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 8c898718865..2a9f1660a62 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -53,7 +53,6 @@
 #![feature(ip)]
 #![feature(ip_from)]
 #![feature(is_ascii_octdigit)]
-#![feature(isqrt)]
 #![feature(iter_advance_by)]
 #![feature(iter_array_chunks)]
 #![feature(iter_chain)]
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 1608080d6b6..474d57049ab 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -369,8 +369,8 @@ macro_rules! int_module {
                 assert_eq_const_safe!(<$T>::midpoint(3, 4), 3);
                 assert_eq_const_safe!(<$T>::midpoint(4, 3), 3);
 
-                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1);
-                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), 0);
+                assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), 0);
                 assert_eq_const_safe!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN);
                 assert_eq_const_safe!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX);
 
diff --git a/library/core/tests/num/midpoint.rs b/library/core/tests/num/midpoint.rs
new file mode 100644
index 00000000000..71e98006784
--- /dev/null
+++ b/library/core/tests/num/midpoint.rs
@@ -0,0 +1,54 @@
+//! Test the following expectations:
+//!  - midpoint(a, b) == (a + b) / 2
+//!  - midpoint(a, b) == midpoint(b, a)
+//!  - midpoint(-a, -b) == -midpoint(a, b)
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_i8() {
+    for a in i8::MIN..=i8::MAX {
+        for b in i8::MIN..=i8::MAX {
+            assert_eq!(i8::midpoint(a, b), ((a as i16 + b as i16) / 2) as i8);
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_obvious_impl_u8() {
+    for a in u8::MIN..=u8::MAX {
+        for b in u8::MIN..=u8::MAX {
+            assert_eq!(u8::midpoint(a, b), ((a as u16 + b as u16) / 2) as u8);
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_i8() {
+    for a in i8::MIN..=i8::MAX {
+        for b in i8::MIN..=i8::MAX {
+            assert_eq!(i8::midpoint(a, b), i8::midpoint(b, a));
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_order_expectation_u8() {
+    for a in u8::MIN..=u8::MAX {
+        for b in u8::MIN..=u8::MAX {
+            assert_eq!(u8::midpoint(a, b), u8::midpoint(b, a));
+        }
+    }
+}
+
+#[test]
+#[cfg(not(miri))]
+fn midpoint_negative_expectation() {
+    for a in 0..=i8::MAX {
+        for b in 0..=i8::MAX {
+            assert_eq!(i8::midpoint(-a, -b), -i8::midpoint(a, b));
+        }
+    }
+}
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 6da9b9a1329..0add9a01e68 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -28,6 +28,7 @@ mod dec2flt;
 mod flt2dec;
 mod int_log;
 mod int_sqrt;
+mod midpoint;
 mod ops;
 mod wrapping;
 
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index ae47bb7adf4..15770248b31 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -32,6 +32,7 @@
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
+#![feature(extend_one)]
 #![recursion_limit = "256"]
 #![allow(internal_features)]
 #![deny(ffi_unwind_calls)]
@@ -43,6 +44,7 @@ pub mod bridge;
 
 mod diagnostic;
 mod escape;
+mod to_tokens;
 
 use std::ffi::CStr;
 use std::ops::{Range, RangeBounds};
@@ -52,6 +54,8 @@ use std::{error, fmt};
 
 #[unstable(feature = "proc_macro_diagnostic", issue = "54140")]
 pub use diagnostic::{Diagnostic, Level, MultiSpan};
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+pub use to_tokens::ToTokens;
 
 use crate::escape::{EscapeOptions, escape_bytes};
 
diff --git a/library/proc_macro/src/to_tokens.rs b/library/proc_macro/src/to_tokens.rs
new file mode 100644
index 00000000000..8f697b416d5
--- /dev/null
+++ b/library/proc_macro/src/to_tokens.rs
@@ -0,0 +1,310 @@
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+use std::rc::Rc;
+
+use crate::{ConcatTreesHelper, Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
+
+/// Types that can be interpolated inside a [`quote!`] invocation.
+///
+/// [`quote!`]: crate::quote!
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+pub trait ToTokens {
+    /// Write `self` to the given `TokenStream`.
+    ///
+    /// # Example
+    ///
+    /// Example implementation for a struct representing Rust paths like
+    /// `std::cmp::PartialEq`:
+    ///
+    /// ```
+    /// #![feature(proc_macro_totokens)]
+    ///
+    /// use std::iter;
+    /// use proc_macro::{Spacing, Punct, TokenStream, TokenTree, ToTokens};
+    ///
+    /// pub struct Path {
+    ///     pub global: bool,
+    ///     pub segments: Vec<PathSegment>,
+    /// }
+    ///
+    /// impl ToTokens for Path {
+    ///     fn to_tokens(&self, tokens: &mut TokenStream) {
+    ///         for (i, segment) in self.segments.iter().enumerate() {
+    ///             if i > 0 || self.global {
+    ///                 // Double colon `::`
+    ///                 tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Joint))));
+    ///                 tokens.extend(iter::once(TokenTree::from(Punct::new(':', Spacing::Alone))));
+    ///             }
+    ///             segment.to_tokens(tokens);
+    ///         }
+    ///     }
+    /// }
+    /// #
+    /// # pub struct PathSegment;
+    /// #
+    /// # impl ToTokens for PathSegment {
+    /// #     fn to_tokens(&self, tokens: &mut TokenStream) {
+    /// #         unimplemented!()
+    /// #     }
+    /// # }
+    /// ```
+    fn to_tokens(&self, tokens: &mut TokenStream);
+
+    /// Convert `self` directly into a `TokenStream` object.
+    ///
+    /// This method is implicitly implemented using `to_tokens`, and acts as a
+    /// convenience method for consumers of the `ToTokens` trait.
+    fn to_token_stream(&self) -> TokenStream {
+        let mut tokens = TokenStream::new();
+        self.to_tokens(&mut tokens);
+        tokens
+    }
+
+    /// Convert `self` directly into a `TokenStream` object.
+    ///
+    /// This method is implicitly implemented using `to_tokens`, and acts as a
+    /// convenience method for consumers of the `ToTokens` trait.
+    fn into_token_stream(self) -> TokenStream
+    where
+        Self: Sized,
+    {
+        self.to_token_stream()
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for TokenTree {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend_one(self.clone());
+    }
+
+    fn into_token_stream(self) -> TokenStream {
+        let mut builder = ConcatTreesHelper::new(1);
+        builder.push(self);
+        builder.build()
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for TokenStream {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend(self.clone());
+    }
+
+    fn into_token_stream(self) -> TokenStream {
+        self
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Literal {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend_one(TokenTree::from(self.clone()));
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Ident {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend_one(TokenTree::from(self.clone()));
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Punct {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend_one(TokenTree::from(self.clone()));
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for Group {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        tokens.extend_one(TokenTree::from(self.clone()));
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for &T {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (**self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for &mut T {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (**self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for Box<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (**self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ?Sized> ToTokens for Rc<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (**self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens + ToOwned + ?Sized> ToTokens for Cow<'_, T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        (**self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl<T: ToTokens> ToTokens for Option<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        if let Some(t) = self {
+            t.to_tokens(tokens);
+        }
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u8 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::u8_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u16 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::u16_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u32 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::u32_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u64 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::u64_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for u128 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::u128_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i8 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::i8_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i16 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::i16_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i32 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::i32_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i64 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::i64_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for i128 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::i128_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for f32 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::f32_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for f64 {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::f64_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for usize {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::usize_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for isize {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::isize_suffixed(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for bool {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        let word = if *self { "true" } else { "false" };
+        Ident::new(word, Span::call_site()).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for char {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::character(*self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for str {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::string(self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for String {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::string(self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for CStr {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::c_string(self).to_tokens(tokens)
+    }
+}
+
+#[unstable(feature = "proc_macro_totokens", issue = "130977")]
+impl ToTokens for CString {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        Literal::c_string(self).to_tokens(tokens)
+    }
+}
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 8a0d2a7f5cf..3079c8b1d90 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1197,7 +1197,7 @@ impl OpenOptions {
 
     /// Sets the option for truncating a previous file.
     ///
-    /// If a file is successfully opened with this option set it will truncate
+    /// If a file is successfully opened with this option set to true, it will truncate
     /// the file to 0 length if it already exists.
     ///
     /// The file must be opened with write access for truncate to work.
diff --git a/library/std/src/sys/sync/condvar/no_threads.rs b/library/std/src/sys/sync/condvar/no_threads.rs
index 36b89c5f5be..2a67ed766aa 100644
--- a/library/std/src/sys/sync/condvar/no_threads.rs
+++ b/library/std/src/sys/sync/condvar/no_threads.rs
@@ -5,7 +5,7 @@ pub struct Condvar {}
 
 impl Condvar {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> Condvar {
         Condvar {}
     }
diff --git a/library/std/src/sys/sync/condvar/xous.rs b/library/std/src/sys/sync/condvar/xous.rs
index cb55a3e3369..b9e5f47abfc 100644
--- a/library/std/src/sys/sync/condvar/xous.rs
+++ b/library/std/src/sys/sync/condvar/xous.rs
@@ -20,7 +20,6 @@ unsafe impl Sync for Condvar {}
 
 impl Condvar {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Condvar {
         Condvar { counter: AtomicUsize::new(0), timed_out: AtomicUsize::new(0) }
     }
diff --git a/library/std/src/sys/sync/mutex/no_threads.rs b/library/std/src/sys/sync/mutex/no_threads.rs
index 4a13c55fb8b..7b243575e01 100644
--- a/library/std/src/sys/sync/mutex/no_threads.rs
+++ b/library/std/src/sys/sync/mutex/no_threads.rs
@@ -10,7 +10,7 @@ unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> Mutex {
         Mutex { locked: Cell::new(false) }
     }
diff --git a/library/std/src/sys/sync/mutex/xous.rs b/library/std/src/sys/sync/mutex/xous.rs
index 233e638f913..c6b954c1711 100644
--- a/library/std/src/sys/sync/mutex/xous.rs
+++ b/library/std/src/sys/sync/mutex/xous.rs
@@ -24,7 +24,6 @@ pub struct Mutex {
 
 impl Mutex {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
     pub const fn new() -> Mutex {
         Mutex { locked: AtomicUsize::new(0), contended: AtomicBool::new(false) }
     }
diff --git a/library/std/src/sys/sync/once/no_threads.rs b/library/std/src/sys/sync/once/no_threads.rs
index cdcffe790f5..fb1b496510a 100644
--- a/library/std/src/sys/sync/once/no_threads.rs
+++ b/library/std/src/sys/sync/once/no_threads.rs
@@ -35,7 +35,7 @@ unsafe impl Sync for Once {}
 
 impl Once {
     #[inline]
-    #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
     pub const fn new() -> Once {
         Once { state: Cell::new(State::Incomplete) }
     }
diff --git a/library/std/src/sys/sync/rwlock/no_threads.rs b/library/std/src/sys/sync/rwlock/no_threads.rs
index 789ef9b29e5..6965e2e2cab 100644
--- a/library/std/src/sys/sync/rwlock/no_threads.rs
+++ b/library/std/src/sys/sync/rwlock/no_threads.rs
@@ -10,7 +10,7 @@ unsafe impl Sync for RwLock {} // no threads on this platform
 
 impl RwLock {
     #[inline]
-    #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+    #[cfg_attr(bootstrap, rustc_const_stable(feature = "const_locks", since = "1.63.0"))]
     pub const fn new() -> RwLock {
         RwLock { mode: Cell::new(0) }
     }
diff --git a/library/stdarch b/library/stdarch
-Subproject c881fe3231b3947a4766aa15a26a93022fbb872
+Subproject ff9a4445038eae46fd095188740946808581bc0
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 27bbc8bd8ff..e13d4ccc618 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -15,7 +15,6 @@ use std::path::{Path, PathBuf};
 use std::process::Stdio;
 use std::{env, fs, str};
 
-use build_helper::git::get_closest_merge_commit;
 use serde_derive::Deserialize;
 
 use crate::core::build_steps::tool::SourceType;
@@ -27,7 +26,7 @@ use crate::core::builder::{
 use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
 use crate::utils::exec::command;
 use crate::utils::helpers::{
-    self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
+    exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
 };
 use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode};
 
@@ -125,23 +124,9 @@ impl Step for Std {
         // Force compilation of the standard library from source if the `library` is modified. This allows
         // library team to compile the standard library without needing to compile the compiler with
         // the `rust.download-rustc=true` option.
-        let force_recompile =
-            if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
-                let closest_merge_commit =
-                    get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
-                        .unwrap();
-
-                // Check if `library` has changes (returns false otherwise)
-                !t!(helpers::git(Some(&builder.src))
-                    .args(["diff-index", "--quiet", &closest_merge_commit])
-                    .arg("--")
-                    .arg(builder.src.join("library"))
-                    .as_command_mut()
-                    .status())
-                .success()
-            } else {
-                false
-            };
+        let force_recompile = builder.rust_info().is_managed_git_subrepository()
+            && builder.download_rustc()
+            && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none();
 
         run.builder.ensure(Std {
             compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 087dde0d9c6..139ca7eb52e 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -2871,14 +2871,7 @@ impl Config {
 
         // Warn if there were changes to the compiler or standard library since the ancestor commit.
         let mut git = helpers::git(Some(&self.src));
-        git.args(["diff-index", "--quiet", &commit, "--"]);
-
-        // Handle running from a directory other than the top level
-        let top_level = &self.src;
-
-        for path in modified_paths {
-            git.arg(top_level.join(path));
-        }
+        git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths);
 
         let has_changes = !t!(git.as_command_mut().status()).success();
         if has_changes {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index a9db0377a50..ba74cabcd30 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -541,7 +541,7 @@ impl Build {
         }
         let output = helpers::git(Some(&self.src))
             .args(["config", "--file"])
-            .arg(self.config.src.join(".gitmodules"))
+            .arg(".gitmodules")
             .args(["--get-regexp", "path"])
             .run_capture(self)
             .stdout();
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 8aabfaafbab..ece5f174d06 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -56,9 +56,9 @@ ENV \
     CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
     CXX_x86_64_fortanix_unknown_sgx=clang++-11 \
     CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \
+    AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \
     CC_aarch64_unknown_uefi=clang-11 \
     CXX_aarch64_unknown_uefi=clang++-11 \
     CC_i686_unknown_uefi=clang-11 \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
index fd0f5da8c49..f42e6f770eb 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile
@@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++
 
 ENV HOSTS=x86_64-unknown-freebsd
 
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index 0f8ebb987c3..fdc8a7310c8 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -51,7 +51,8 @@ ENV SCRIPT \
            /scripts/check-default-config-profiles.sh && \
            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
            python3 ../x.py clippy bootstrap -Dwarnings && \
-           python3 ../x.py clippy compiler library -Aclippy::all -Dclippy::correctness && \
+           python3 ../x.py clippy library -Aclippy::all -Dclippy::correctness && \
+           python3 ../x.py clippy compiler -Aclippy::all -Dclippy::correctness -Dclippy::clone_on_ref_ptr && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh
index 4826b81d56c..0d02636db91 100755
--- a/src/ci/docker/scripts/freebsd-toolchain.sh
+++ b/src/ci/docker/scripts/freebsd-toolchain.sh
@@ -5,8 +5,8 @@ set -eux
 
 arch=$1
 binutils_version=2.40
-freebsd_version=13.2
-triple=$arch-unknown-freebsd13
+freebsd_version=12.3
+triple=$arch-unknown-freebsd12
 sysroot=/usr/local/$triple
 
 hide_output() {
@@ -59,7 +59,7 @@ done
 
 # Originally downloaded from:
 # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz
-URL=https://ci-mirrors.rust-lang.org/rustc/2024-02-18-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
+URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz
 curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 
 # Clang can do cross-builds out of the box, if we give it the right
@@ -68,7 +68,7 @@ curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}"
 # there might be other problems.)
 #
 # The --target option is last because the cross-build of LLVM uses
-# --target without an OS version ("-freebsd" vs. "-freebsd13").  This
+# --target without an OS version ("-freebsd" vs. "-freebsd12").  This
 # makes Clang default to libstdc++ (which no longer exists), and also
 # controls other features, like GNU-style symbol table hashing and
 # anything predicated on the version number in the __FreeBSD__
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index e05d9a40f00..18f76ac6fe0 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -66,9 +66,10 @@
     - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md)
     - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md)
     - [powerpc64-ibm-aix](platform-support/aix.md)
+    - [riscv32e*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md)
+    - [riscv32i*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv32im-risc0-zkvm-elf](platform-support/riscv32im-risc0-zkvm-elf.md)
     - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
-    - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md)
     - [riscv64gc-unknown-linux-gnu](platform-support/riscv64gc-unknown-linux-gnu.md)
     - [riscv64gc-unknown-linux-musl](platform-support/riscv64gc-unknown-linux-musl.md)
     - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 5da03d26eb4..04bb40d750c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -100,7 +100,7 @@ target | notes
 [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
 [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
 `s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
-`x86_64-unknown-freebsd` | 64-bit FreeBSD (version 13.2)
+`x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
 [`x86_64-unknown-netbsd`](platform-support/netbsd.md) | NetBSD/amd64
@@ -166,7 +166,7 @@ target | std | notes
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI]
 [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI]
-`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD (version 13.2) [^x86_32-floats-return-ABI]
+`i686-unknown-freebsd` | ✓ | 32-bit FreeBSD [^x86_32-floats-return-ABI]
 `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI]
 [`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI
 [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI)
@@ -258,7 +258,7 @@ target | std | host | notes
 [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? |  | ARM64 TEEOS |
 [`aarch64-unknown-nto-qnx700`](platform-support/nto-qnx.md) | ? |  | ARM64 QNX Neutrino 7.0 RTOS |
 [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
-`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD (version 13.2)
+`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ |  | ARM64 Hermit
 `aarch64-unknown-illumos` | ✓ | ✓ | ARM64 illumos
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
@@ -277,14 +277,14 @@ target | std | host | notes
 `armv4t-unknown-linux-gnueabi` | ? |  | Armv4T Linux
 [`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * |  | Bare Armv5TE
 `armv5te-unknown-linux-uclibceabi` | ? |  | Armv5TE Linux with uClibc
-`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD (version 13.2)
+`armv6-unknown-freebsd` | ✓ | ✓ | Armv6 FreeBSD
 [`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv6 NetBSD w/hard-float
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | Armv6k Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 [`armv7-rtems-eabihf`](platform-support/armv7-rtems-eabihf.md) | ? |  | RTEMS OS for ARM BSPs
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ✓ |  | Armv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat
-`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD (version 13.2)
+`armv7-unknown-freebsd` | ✓ | ✓ | Armv7-A FreeBSD
 [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float
 [`armv7-unknown-trusty`](platform-support/trusty.md) | ? |  |
 [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ |  | Armv7-A for VxWorks
@@ -343,9 +343,9 @@ target | std | host | notes
 [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * |  |
 [`powerpc-wrs-vxworks-spe`](platform-support/vxworks.md) | ✓ |  |
 [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
-`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2, version 13.2)
-`powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD (version 13.2)
-`powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD (version 13.2)
+`powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
+`powerpc64le-unknown-freebsd` |   |   | PPC64LE FreeBSD
+`powerpc-unknown-freebsd` |   |   | PowerPC FreeBSD
 `powerpc64-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3
 [`powerpc64-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 `powerpc64le-unknown-linux-musl` | ? |  | 64-bit PowerPC Linux with musl 1.2.3, Little Endian
@@ -361,7 +361,7 @@ target | std | host | notes
 [`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ |  | RISC-V ESP-IDF
 [`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ |  |
 [`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ |   | RISC-V Hermit
-`riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD (version 13.2)
+`riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-fuchsia` |   |   | RISC-V Fuchsia
 [`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
 [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
@@ -414,8 +414,8 @@ target | std | host | notes
 [`riscv32imafc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 32bit with NuttX
 [`riscv64imac-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
 [`riscv64gc-unknown-nuttx-elf`](platform-support/nuttx.md) | * |  | RISC-V 64bit with NuttX
-[`riscv32e-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
-[`riscv32em-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
-[`riscv32emc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
+[`riscv32e-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32E ISA)
+[`riscv32em-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EM ISA)
+[`riscv32emc-unknown-none-elf`](platform-support/riscv32e-unknown-none-elf.md) | * |  | Bare RISC-V (RV32EMC ISA)
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md
index c3ce71a1835..5a198062b95 100644
--- a/src/doc/rustc/src/platform-support/aix.md
+++ b/src/doc/rustc/src/platform-support/aix.md
@@ -6,8 +6,8 @@ Rust for AIX operating system, currently only 64-bit PowerPC is supported.
 
 ## Target maintainers
 
-- QIU Chaofan `qiucofan@cn.ibm.com`, https://github.com/ecnelises
-- Kai LUO, `lkail@cn.ibm.com`, https://github.com/bzEq
+- David Tenty `daltenty@ibm.com`, https://github.com/daltenty
+- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr
 
 ## Requirements
 
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 5643c6a0188..489f46e1cb9 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -7,17 +7,9 @@ updatable, and performant.
 
 ## Target maintainers
 
-The [Fuchsia team]:
+See [`fuchsia.toml`] in the `team` repository for current target maintainers.
 
-- Tyler Mandry ([@tmandry](https://github.com/tmandry))
-- David Koloski ([@djkoloski](https://github.com/djkoloski))
-- Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3))
-- Erick Tryzelaar ([@erickt](https://github.com/erickt))
-
-As the team evolves over time, the specific members listed here may differ from
-the members reported by the API. The API should be considered to be
-authoritative if this occurs. Instead of pinging individual members, use
-`@rustbot ping fuchsia` to contact the team on GitHub.
+[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml
 
 ## Table of contents
 
@@ -525,14 +517,6 @@ ${SDK_PATH}/tools/${ARCH}/ffx repository publish \
     pkg/repo
 ```
 
-Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
-
-```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
-    --repository hello-fuchsia \
-    pkg/repo
-```
-
 ## Running a Fuchsia component on an emulator
 
 At this point, we are ready to run our Fuchsia
@@ -590,7 +574,8 @@ Now, start a package repository server to serve our
 package to the emulator:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/ffx repository server start
+${SDK_PATH}/tools/${ARCH}/ffx repository server start \
+    --background --repository hello-fuchsia --repo-path pkg-repo
 ```
 
 Once the repository server is up and running, register it with the target Fuchsia system running in the emulator:
diff --git a/src/etc/cat-and-grep.sh b/src/etc/cat-and-grep.sh
index 238f7f5b660..68c6993ac15 100755
--- a/src/etc/cat-and-grep.sh
+++ b/src/etc/cat-and-grep.sh
@@ -33,7 +33,6 @@ while getopts ':vieh' OPTION; do
     case "$OPTION" in
         v)
             INVERT=1
-            ERROR_MSG='should not be found'
             ;;
         i)
             GREPFLAGS="i$GREPFLAGS"
diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py
index 599e1e8102c..851b01a7458 100755
--- a/src/etc/htmldocck.py
+++ b/src/etc/htmldocck.py
@@ -250,7 +250,7 @@ def get_known_directive_names():
         os.path.join(
             # We go back to `src`.
             os.path.dirname(os.path.dirname(__file__)),
-            "tools/compiletest/src/command-list.rs",
+            "tools/compiletest/src/directive-list.rs",
         ),
         "r",
         encoding="utf8"
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 1f3cb4a61b8..a6d9676dd84 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
-use rustc_middle::ty::{self, Upcast};
+use rustc_middle::ty::{self, TypingMode, Upcast};
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::DefId;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -38,7 +38,7 @@ pub(crate) fn synthesize_blanket_impls(
             if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) {
                 continue;
             }
-            let infcx = tcx.infer_ctxt().build();
+            let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
             let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id);
             let impl_ty = ty.instantiate(tcx, args);
             let param_env = ty::ParamEnv::empty();
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index e7f921eef7f..97529e420e3 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -248,9 +248,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
         // Check to see if it is a macro 2.0 or built-in macro
         if matches!(
             CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
-            LoadedMacro::MacroDef(def, _)
-                if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
-                    if !ast_def.macro_rules)
+            LoadedMacro::MacroDef { def, .. } if !def.macro_rules
         ) {
             once(crate_name).chain(relative).collect()
         } else {
@@ -747,24 +745,12 @@ fn build_macro(
     is_doc_hidden: bool,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
-        LoadedMacro::MacroDef(item_def, _) => match macro_kind {
+        LoadedMacro::MacroDef { def, .. } => match macro_kind {
             MacroKind::Bang => {
-                if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
-                    let vis =
-                        cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
-                    clean::MacroItem(clean::Macro {
-                        source: utils::display_macro_source(
-                            cx,
-                            name,
-                            def,
-                            def_id,
-                            vis,
-                            is_doc_hidden,
-                        ),
-                    })
-                } else {
-                    unreachable!()
-                }
+                let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
+                clean::MacroItem(clean::Macro {
+                    source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
+                })
             }
             MacroKind::Derive | MacroKind::Attr => {
                 clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ea349f878e0..58663fcbafe 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -45,7 +45,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
 use rustc_hir_analysis::lower_ty;
 use rustc_middle::metadata::Reexport;
 use rustc_middle::middle::resolve_bound_vars as rbv;
-use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode};
 use rustc_middle::{bug, span_bug};
 use rustc_span::ExpnKind;
 use rustc_span::hygiene::{AstPass, MacroKind};
@@ -1829,7 +1829,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             Array(Box::new(clean_ty(ty, cx)), length.into())
         }
         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
-        TyKind::OpaqueDef(ty, _) => {
+        TyKind::OpaqueDef(ty) => {
             ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
@@ -1863,7 +1863,7 @@ fn normalize<'tcx>(
     use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
     // Try to normalize `<X as Y>::T` to a type
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let normalized = infcx
         .at(&ObligationCause::dummy(), cx.param_env)
         .query_normalize(ty)
@@ -2399,7 +2399,7 @@ pub(crate) fn clean_variant_def_with_args<'tcx>(
     use rustc_trait_selection::infer::TyCtxtInferExt;
     use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
     let kind = match variant.ctor_kind() {
         Some(CtorKind::Const) => VariantKind::CLike,
         Some(CtorKind::Fn) => VariantKind::Tuple(
diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs
index 093755103f3..234f40c6c1a 100644
--- a/src/librustdoc/doctest/runner.rs
+++ b/src/librustdoc/doctest/runner.rs
@@ -198,10 +198,6 @@ fn generate_mergeable_doctest(
     } else {
         writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs)
             .unwrap();
-        if scraped_test.langstr.no_run {
-            // To prevent having warnings about unused items since they're not called.
-            writeln!(output, "#![allow(unused)]").unwrap();
-        }
         if doctest.has_main_fn {
             output.push_str(&doctest.everything_else);
         } else {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index ea2f930ab83..47c21d89177 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -16,16 +16,15 @@ use itertools::Itertools;
 use rustc_attr::{ConstStability, StabilityLevel, StableSince};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_metadata::creader::{CStore, LoadedMacro};
-use rustc_middle::ty;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt, TypingMode};
 use rustc_span::symbol::kw;
 use rustc_span::{Symbol, sym};
 use rustc_target::spec::abi::Abi;
 use tracing::{debug, trace};
-use {rustc_ast as ast, rustc_hir as hir};
 
 use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
 use crate::clean::types::ExternalLocation;
@@ -554,10 +553,8 @@ fn generate_macro_def_id_path(
     // Check to see if it is a macro 2.0 or built-in macro.
     // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
     let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) {
-        LoadedMacro::MacroDef(def, _) => {
-            // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
-            matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)
-        }
+        // If `def.macro_rules` is `true`, then it's not a macro 2.0.
+        LoadedMacro::MacroDef { def, .. } => !def.macro_rules,
         _ => false,
     };
 
@@ -615,7 +612,7 @@ fn generate_item_def_id_path(
     // No need to try to infer the actual parent item if it's not an associated item from the `impl`
     // block.
     if def_id != original_def_id && matches!(tcx.def_kind(def_id), DefKind::Impl { .. }) {
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
         def_id = infcx
             .at(&ObligationCause::dummy(), tcx.param_env(def_id))
             .query_normalize(ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity()))
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index c958458b662..d1939adc1a5 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -759,7 +759,10 @@ pub(crate) fn get_function_type_for_search<'tcx>(
         }
     });
     let (mut inputs, mut output, where_clause) = match item.kind {
-        clean::FunctionItem(ref f) | clean::MethodItem(ref f, _) | clean::TyMethodItem(ref f) => {
+        clean::ForeignFunctionItem(ref f, _)
+        | clean::FunctionItem(ref f)
+        | clean::MethodItem(ref f, _)
+        | clean::TyMethodItem(ref f) => {
             get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
         }
         _ => return None,
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index cd4e597ff28..79209cee94f 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -60,8 +60,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
                         span_bug!(tcx.def_span(ty_def_id), "not an adt")
                     };
                     let name = adt.variant(variant_idx).name;
-                    let is_unsized = variant_layout.abi.is_unsized();
-                    let is_uninhabited = variant_layout.abi.is_uninhabited();
+                    let is_unsized = variant_layout.is_unsized();
+                    let is_uninhabited = variant_layout.is_uninhabited();
                     let size = variant_layout.size.bytes() - tag_size;
                     let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
                     (name, type_layout_size)
@@ -72,8 +72,8 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>(
         };
 
         let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
-            let is_unsized = layout.abi.is_unsized();
-            let is_uninhabited = layout.abi.is_uninhabited();
+            let is_unsized = layout.is_unsized();
+            let is_uninhabited = layout.is_uninhabited();
             let size = layout.size.bytes();
             TypeLayoutSize { is_unsized, is_uninhabited, size }
         });
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index ae4d55e93ac..1042d254749 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -230,7 +230,7 @@ h4.code-header {
 	padding: 0;
 	white-space: pre-wrap;
 }
-.structfield {
+.structfield, .sub-variant-field {
 	margin: 0.6em 0;
 }
 
@@ -959,7 +959,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
 	background: var(--table-alt-row-background-color);
 }
 
-.docblock .stab, .docblock-short .stab {
+.docblock .stab, .docblock-short .stab, .docblock p code {
 	display: inline-block;
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 0066ed64325..77dbe9b78a1 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -166,7 +166,7 @@ declare_with_version! { RENAMED(RENAMED_VERSION): &[(&str, &str)] = &[
     #[clippy::version = ""]
     ("clippy::positional_named_format_parameters", "named_arguments_used_positionally"),
     #[clippy::version = ""]
-    ("clippy::temporary_cstring_as_ptr", "temporary_cstring_as_ptr"),
+    ("clippy::temporary_cstring_as_ptr", "dangling_pointers_from_temporaries"),
     #[clippy::version = ""]
     ("clippy::undropped_manually_drops", "undropped_manually_drops"),
     #[clippy::version = ""]
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index cabc6592258..6ca599ed361 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -9,7 +9,8 @@ use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Saf
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
-    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
+    self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt,
+    TypeckResults,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::symbol::sym;
@@ -203,7 +204,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                             // 'cuz currently nothing changes after deleting this check.
                             local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                         }) {
-                            match cx.tcx.infer_ctxt().build().err_ctxt().type_implements_fn_trait(
+                            match cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().type_implements_fn_trait(
                                 cx.param_env,
                                 Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
                                 ty::PredicatePolarity::Positive,
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index cfd11e9339f..c74ba088b78 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -117,7 +117,7 @@ fn check_needless_must_use(
     } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
         // Ignore async functions unless Future::Output type is a must_use type
         if sig.header.is_async() {
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id))
                 && !is_must_use_ty(cx, future_ty)
             {
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index a4dbe134f36..cf08c16458b 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             if is_future {
                 let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
                 let span = decl.output.span();
-                let infcx = cx.tcx.infer_ctxt().build();
+                let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
                 let cause = traits::ObligationCause::misc(span, fn_def_id);
                 ocx.register_bound(cause, cx.param_env, ret_ty, send_trait);
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 5a3930b8bb8..d55be2b036a 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -420,15 +420,6 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::OpaqueDef(opaque, bounds) => {
-                let len = self.lts.len();
-                self.visit_opaque_ty(opaque);
-                self.lts.truncate(len);
-                self.lts.extend(bounds.iter().filter_map(|bound| match bound {
-                    GenericArg::Lifetime(&l) => Some(l),
-                    _ => None,
-                }));
-            },
             TyKind::BareFn(&BareFnTy { decl, .. }) => {
                 let mut sub_visitor = RefVisitor::new(self.cx);
                 sub_visitor.visit_fn_decl(decl);
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 67255c1af79..c904137da1a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,9 +4,11 @@ use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, Body, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl,
-    FnRetTy, GenericArg, GenericBound, ImplItem, Item, LifetimeName, Node, TraitRef, Ty, TyKind,
+    FnRetTy, GenericBound, ImplItem, Item, Node, OpaqueTy, TraitRef, Ty, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
+use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Span, sym};
@@ -44,21 +46,22 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
         decl: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         span: Span,
-        def_id: LocalDefId,
+        fn_def_id: LocalDefId,
     ) {
         if let Some(header) = kind.header()
             && !header.asyncness.is_async()
             // Check that this function returns `impl Future`
             && let FnRetTy::Return(ret_ty) = decl.output
-            && let Some((trait_ref, output_lifetimes)) = future_trait_ref(cx, ret_ty)
+            && let TyKind::OpaqueDef(opaque) = ret_ty.kind
+            && let Some(trait_ref) = future_trait_ref(cx, opaque)
             && let Some(output) = future_output_ty(trait_ref)
-            && captures_all_lifetimes(decl.inputs, &output_lifetimes)
+            && captures_all_lifetimes(cx, fn_def_id, opaque.def_id)
             // Check that the body of the function consists of one async block
             && let ExprKind::Block(block, _) = body.value.kind
             && block.stmts.is_empty()
             && let Some(closure_body) = desugared_async_block(cx, block)
             && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) =
-                cx.tcx.hir_node_by_def_id(def_id)
+                cx.tcx.hir_node_by_def_id(fn_def_id)
         {
             let header_span = span.with_hi(ret_ty.span.hi());
 
@@ -101,12 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn {
     }
 }
 
-fn future_trait_ref<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: &'tcx Ty<'tcx>,
-) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
-    if let TyKind::OpaqueDef(opaque, bounds) = ty.kind
-        && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
+fn future_trait_ref<'tcx>(cx: &LateContext<'tcx>, opaque: &'tcx OpaqueTy<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
+    if let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
             if let GenericBound::Trait(poly) = bound {
                 Some(&poly.trait_ref)
             } else {
@@ -115,18 +114,7 @@ fn future_trait_ref<'tcx>(
         })
         && trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait()
     {
-        let output_lifetimes = bounds
-            .iter()
-            .filter_map(|bound| {
-                if let GenericArg::Lifetime(lt) = bound {
-                    Some(lt.res)
-                } else {
-                    None
-                }
-            })
-            .collect();
-
-        return Some((trait_ref, output_lifetimes));
+        return Some(trait_ref);
     }
 
     None
@@ -145,27 +133,35 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
     None
 }
 
-fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) -> bool {
-    let input_lifetimes: Vec<LifetimeName> = inputs
+fn captures_all_lifetimes(cx: &LateContext<'_>, fn_def_id: LocalDefId, opaque_def_id: LocalDefId) -> bool {
+    let early_input_params = ty::GenericArgs::identity_for_item(cx.tcx, fn_def_id);
+    let late_input_params = cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(fn_def_id));
+
+    let num_early_lifetimes = early_input_params
         .iter()
-        .filter_map(|ty| {
-            if let TyKind::Ref(lt, _) = ty.kind {
-                Some(lt.res)
-            } else {
-                None
-            }
+        .filter(|param| param.as_region().is_some())
+        .count();
+    let num_late_lifetimes = late_input_params
+        .iter()
+        .filter(|param_kind| matches!(param_kind, ty::BoundVariableKind::Region(_)))
+        .count();
+
+    // There is no lifetime, so they are all captured.
+    if num_early_lifetimes == 0 && num_late_lifetimes == 0 {
+        return true;
+    }
+
+    // By construction, each captured lifetime only appears once in `opaque_captured_lifetimes`.
+    let num_captured_lifetimes = cx
+        .tcx
+        .opaque_captured_lifetimes(opaque_def_id)
+        .iter()
+        .filter(|&(lifetime, _)| match *lifetime {
+            ResolvedArg::EarlyBound(_) | ResolvedArg::LateBound(ty::INNERMOST, _, _) => true,
+            _ => false,
         })
-        .collect();
-
-    // The lint should trigger in one of these cases:
-    // - There are no input lifetimes
-    // - There's only one output lifetime bound using `+ '_`
-    // - All input lifetimes are explicitly bound to the output
-    input_lifetimes.is_empty()
-        || (output_lifetimes.len() == 1 && matches!(output_lifetimes[0], LifetimeName::Infer))
-        || input_lifetimes
-            .iter()
-            .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt))
+        .count();
+    num_captured_lifetimes == num_early_lifetimes + num_late_lifetimes
 }
 
 fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index cfa1fdb8137..82549413fa9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -568,7 +568,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
                             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
                             !cx.tcx
                                 .infer_ctxt()
-                                .build()
+                                .build(cx.typing_mode())
                                 .predicate_must_hold_modulo_regions(&obligation)
                         }) {
                             return false;
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f6db12ed84e..f7fa31d83aa 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -278,7 +278,7 @@ fn needless_borrow_count<'tcx>(
 
             let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, &args_with_referent_ty[..]);
             let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
-            let infcx = cx.tcx.infer_ctxt().build();
+            let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
             infcx.predicate_must_hold_modulo_regions(&obligation)
         })
     };
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 392cfcb813e..2e5195d459f 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -160,7 +160,7 @@ impl NoEffect {
                                 // Remove `impl Future<Output = T>` to get `T`
                                 if cx.tcx.ty_is_opaque_future(ret_ty)
                                     && let Some(true_ret_ty) =
-                                        cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty)
+                                        cx.tcx.infer_ctxt().build(cx.typing_mode()).err_ctxt().get_impl_future_output_ty(ret_ty)
                                 {
                                     ret_ty = true_ret_ty;
                                 }
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index f5fcf521b96..a548c6ef3b1 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -695,7 +695,7 @@ fn matches_preds<'tcx>(
     ty: Ty<'tcx>,
     preds: &'tcx [ty::PolyExistentialPredicate<'tcx>],
 ) -> bool {
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());
     preds
         .iter()
         .all(|&p| match cx.tcx.instantiate_bound_regions_with_erased(p) {
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index ec3a693d2ef..3b05abc546f 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -114,7 +114,7 @@ fn into_iter_bound<'tcx>(
                     if !cx
                         .tcx
                         .infer_ctxt()
-                        .build()
+                        .build(cx.typing_mode())
                         .predicate_must_hold_modulo_regions(&obligation)
                     {
                         return None;
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 181d414cbbd..8004bc68b2e 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1231,16 +1231,13 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             TyKind::Path(ref qpath) => self.hash_qpath(qpath),
-            TyKind::OpaqueDef(_, arg_list) => {
-                self.hash_generic_args(arg_list);
-            },
             TyKind::TraitObject(_, lifetime, _) => {
                 self.hash_lifetime(lifetime);
             },
             TyKind::Typeof(anon_const) => {
                 self.hash_body(anon_const.body);
             },
-            TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {},
+            TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::OpaqueDef(_) | TyKind::AnonAdt(_) => {},
         }
     }
 
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index a00196c4b51..6b3078f52af 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -185,9 +185,7 @@ impl<'b, 'tcx> PossibleBorrowerMap<'b, 'tcx> {
             vis.into_map(cx)
         };
         let maybe_storage_live_result = MaybeStorageLive::new(Cow::Owned(BitSet::new_empty(mir.local_decls.len())))
-            .into_engine(cx.tcx, mir)
-            .pass_name("redundant_clone")
-            .iterate_to_fixpoint()
+            .iterate_to_fixpoint(cx.tcx, mir, Some("redundant_clone"))
             .into_results_cursor(mir);
         let mut vis = PossibleBorrowerVisitor::new(cx, mir, possible_origin);
         vis.visit_body(mir);
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 46739862de6..dbadc8432f6 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
@@ -17,7 +17,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt, TypingMode};
 use rustc_span::Span;
 use rustc_span::symbol::sym;
 use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@@ -420,7 +420,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
             TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
         );
 
-        let infcx = tcx.infer_ctxt().build();
+        let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(obligation.param_env));
         let mut selcx = SelectionContext::new(&infcx);
         let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
             return false;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 07c3d0eada0..c618bfe4488 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -19,7 +19,7 @@ use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
     GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr, TypingMode,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -268,7 +268,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         return false;
     }
 
-    let infcx = tcx.infer_ctxt().build();
+    let infcx = tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let args = args
         .into_iter()
         .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
@@ -362,7 +362,7 @@ fn is_normalizable_helper<'tcx>(
     }
     // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
     cache.insert(ty, false);
-    let infcx = cx.tcx.infer_ctxt().build();
+    let infcx = cx.tcx.infer_ctxt().build(TypingMode::from_param_env(param_env));
     let cause = ObligationCause::dummy();
     let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() {
         match ty.kind() {
@@ -1268,7 +1268,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
         let cause = ObligationCause::dummy();
         match tcx
             .infer_ctxt()
-            .build()
+            .build(TypingMode::from_param_env(param_env))
             .at(&cause, param_env)
             .query_normalize(Ty::new_projection_from_args(tcx, ty.def_id, ty.args))
         {
@@ -1284,7 +1284,7 @@ pub fn make_normalized_projection_with_regions<'tcx>(
 
 pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
     let cause = ObligationCause::dummy();
-    match tcx.infer_ctxt().build().at(&cause, param_env).query_normalize(ty) {
+    match tcx.infer_ctxt().build(TypingMode::from_param_env(param_env)).at(&cause, param_env).query_normalize(ty) {
         Ok(ty) => ty.value,
         Err(_) => ty,
     }
diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs
index 146b04ab813..0de53a75c62 100644
--- a/src/tools/clippy/tests/ui/cast.rs
+++ b/src/tools/clippy/tests/ui/cast.rs
@@ -1,7 +1,6 @@
 //@no-rustfix
 
 #![feature(repr128)]
-#![feature(isqrt)]
 #![allow(incomplete_features)]
 #![warn(
     clippy::cast_precision_loss,
diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr
index 7824bdfac25..452482fc88e 100644
--- a/src/tools/clippy/tests/ui/cast.stderr
+++ b/src/tools/clippy/tests/ui/cast.stderr
@@ -1,5 +1,5 @@
 error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:26:5
+  --> tests/ui/cast.rs:25:5
    |
 LL |     x0 as f32;
    |     ^^^^^^^^^
@@ -8,37 +8,37 @@ LL |     x0 as f32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]`
 
 error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:30:5
+  --> tests/ui/cast.rs:29:5
    |
 LL |     x1 as f32;
    |     ^^^^^^^^^
 
 error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:32:5
+  --> tests/ui/cast.rs:31:5
    |
 LL |     x1 as f64;
    |     ^^^^^^^^^
 
 error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:35:5
+  --> tests/ui/cast.rs:34:5
    |
 LL |     x2 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)
-  --> tests/ui/cast.rs:38:5
+  --> tests/ui/cast.rs:37:5
    |
 LL |     x3 as f32;
    |     ^^^^^^^^^
 
 error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)
-  --> tests/ui/cast.rs:40:5
+  --> tests/ui/cast.rs:39:5
    |
 LL |     x3 as f64;
    |     ^^^^^^^^^
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:43:5
+  --> tests/ui/cast.rs:42:5
    |
 LL |     1f32 as i32;
    |     ^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     1f32 as i32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]`
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:45:5
+  --> tests/ui/cast.rs:44:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     1f32 as u32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:45:5
+  --> tests/ui/cast.rs:44:5
    |
 LL |     1f32 as u32;
    |     ^^^^^^^^^^^
@@ -65,7 +65,7 @@ LL |     1f32 as u32;
    = help: to override `-D warnings` add `#[allow(clippy::cast_sign_loss)]`
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:49:5
+  --> tests/ui/cast.rs:48:5
    |
 LL |     1f64 as f32;
    |     ^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     1f64 as f32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:51:5
+  --> tests/ui/cast.rs:50:5
    |
 LL |     1i32 as i8;
    |     ^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |     i8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:53:5
+  --> tests/ui/cast.rs:52:5
    |
 LL |     1i32 as u8;
    |     ^^^^^^^^^^
@@ -97,7 +97,7 @@ LL |     u8::try_from(1i32);
    |     ~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `isize` may truncate the value
-  --> tests/ui/cast.rs:55:5
+  --> tests/ui/cast.rs:54:5
    |
 LL |     1f64 as isize;
    |     ^^^^^^^^^^^^^
@@ -105,7 +105,7 @@ LL |     1f64 as isize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may truncate the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
@@ -113,13 +113,13 @@ LL |     1f64 as usize;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:57:5
+  --> tests/ui/cast.rs:56:5
    |
 LL |     1f64 as usize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u32` to `u16` may truncate the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^^^^^^^^
@@ -131,7 +131,7 @@ LL |     u16::try_from(1f32 as u32);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f32` to `u32` may truncate the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
@@ -139,13 +139,13 @@ LL |     1f32 as u32 as u16;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:60:5
+  --> tests/ui/cast.rs:59:5
    |
 LL |     1f32 as u32 as u16;
    |     ^^^^^^^^^^^
 
 error: casting `i32` to `i8` may truncate the value
-  --> tests/ui/cast.rs:65:22
+  --> tests/ui/cast.rs:64:22
    |
 LL |         let _x: i8 = 1i32 as _;
    |                      ^^^^^^^^^
@@ -157,7 +157,7 @@ LL |         let _x: i8 = 1i32.try_into();
    |                      ~~~~~~~~~~~~~~~
 
 error: casting `f32` to `i32` may truncate the value
-  --> tests/ui/cast.rs:67:9
+  --> tests/ui/cast.rs:66:9
    |
 LL |         1f32 as i32;
    |         ^^^^^^^^^^^
@@ -165,7 +165,7 @@ LL |         1f32 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f64` to `i32` may truncate the value
-  --> tests/ui/cast.rs:69:9
+  --> tests/ui/cast.rs:68:9
    |
 LL |         1f64 as i32;
    |         ^^^^^^^^^^^
@@ -173,7 +173,7 @@ LL |         1f64 as i32;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:71:9
+  --> tests/ui/cast.rs:70:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |         1f32 as u8;
    = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ...
 
 error: casting `f32` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:71:9
+  --> tests/ui/cast.rs:70:9
    |
 LL |         1f32 as u8;
    |         ^^^^^^^^^^
 
 error: casting `u8` to `i8` may wrap around the value
-  --> tests/ui/cast.rs:76:5
+  --> tests/ui/cast.rs:75:5
    |
 LL |     1u8 as i8;
    |     ^^^^^^^^^
@@ -196,31 +196,31 @@ LL |     1u8 as i8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]`
 
 error: casting `u16` to `i16` may wrap around the value
-  --> tests/ui/cast.rs:79:5
+  --> tests/ui/cast.rs:78:5
    |
 LL |     1u16 as i16;
    |     ^^^^^^^^^^^
 
 error: casting `u32` to `i32` may wrap around the value
-  --> tests/ui/cast.rs:81:5
+  --> tests/ui/cast.rs:80:5
    |
 LL |     1u32 as i32;
    |     ^^^^^^^^^^^
 
 error: casting `u64` to `i64` may wrap around the value
-  --> tests/ui/cast.rs:83:5
+  --> tests/ui/cast.rs:82:5
    |
 LL |     1u64 as i64;
    |     ^^^^^^^^^^^
 
 error: casting `usize` to `isize` may wrap around the value
-  --> tests/ui/cast.rs:85:5
+  --> tests/ui/cast.rs:84:5
    |
 LL |     1usize as isize;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `usize` to `i8` may truncate the value
-  --> tests/ui/cast.rs:88:5
+  --> tests/ui/cast.rs:87:5
    |
 LL |     1usize as i8;
    |     ^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL |     i8::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may truncate the value
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:90:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     i16::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i16` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:91:5
+  --> tests/ui/cast.rs:90:5
    |
 LL |     1usize as i16;
    |     ^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     1usize as i16;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:95:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
@@ -265,19 +265,19 @@ LL |     i32::try_from(1usize);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:96:5
+  --> tests/ui/cast.rs:95:5
    |
 LL |     1usize as i32;
    |     ^^^^^^^^^^^^^
 
 error: casting `usize` to `i64` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:100:5
+  --> tests/ui/cast.rs:99:5
    |
 LL |     1usize as i64;
    |     ^^^^^^^^^^^^^
 
 error: casting `u16` to `isize` may wrap around the value on targets with 16-bit wide pointers
-  --> tests/ui/cast.rs:105:5
+  --> tests/ui/cast.rs:104:5
    |
 LL |     1u16 as isize;
    |     ^^^^^^^^^^^^^
@@ -286,13 +286,13 @@ LL |     1u16 as isize;
    = note: for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types
 
 error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:109:5
+  --> tests/ui/cast.rs:108:5
    |
 LL |     1u32 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:112:5
+  --> tests/ui/cast.rs:111:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
@@ -304,55 +304,55 @@ LL |     isize::try_from(1u64);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers
-  --> tests/ui/cast.rs:112:5
+  --> tests/ui/cast.rs:111:5
    |
 LL |     1u64 as isize;
    |     ^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:117:5
+  --> tests/ui/cast.rs:116:5
    |
 LL |     -1i32 as u32;
    |     ^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:120:5
+  --> tests/ui/cast.rs:119:5
    |
 LL |     -1isize as usize;
    |     ^^^^^^^^^^^^^^^^
 
 error: casting `i8` to `u8` may lose the sign of the value
-  --> tests/ui/cast.rs:131:5
+  --> tests/ui/cast.rs:130:5
    |
 LL |     (i8::MIN).abs() as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:135:5
+  --> tests/ui/cast.rs:134:5
    |
 LL |     (-1i64).abs() as u64;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `isize` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:136:5
+  --> tests/ui/cast.rs:135:5
    |
 LL |     (-1isize).abs() as usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:143:5
+  --> tests/ui/cast.rs:142:5
    |
 LL |     (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `u64` may lose the sign of the value
-  --> tests/ui/cast.rs:158:5
+  --> tests/ui/cast.rs:157:5
    |
 LL |     (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i64` to `i8` may truncate the value
-  --> tests/ui/cast.rs:209:5
+  --> tests/ui/cast.rs:208:5
    |
 LL |     (-99999999999i64).min(1) as i8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL |     i8::try_from((-99999999999i64).min(1));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:223:5
+  --> tests/ui/cast.rs:222:5
    |
 LL |     999999u64.clamp(0, 256) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL |     u8::try_from(999999u64.clamp(0, 256));
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2` to `u8` may truncate the value
-  --> tests/ui/cast.rs:246:21
+  --> tests/ui/cast.rs:245:21
    |
 LL |             let _ = self as u8;
    |                     ^^^^^^^^^^
@@ -388,7 +388,7 @@ LL |             let _ = u8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E2::B` to `u8` will truncate the value
-  --> tests/ui/cast.rs:248:21
+  --> tests/ui/cast.rs:247:21
    |
 LL |             let _ = Self::B as u8;
    |                     ^^^^^^^^^^^^^
@@ -397,7 +397,7 @@ LL |             let _ = Self::B as u8;
    = help: to override `-D warnings` add `#[allow(clippy::cast_enum_truncation)]`
 
 error: casting `main::E5` to `i8` may truncate the value
-  --> tests/ui/cast.rs:290:21
+  --> tests/ui/cast.rs:289:21
    |
 LL |             let _ = self as i8;
    |                     ^^^^^^^^^^
@@ -409,13 +409,13 @@ LL |             let _ = i8::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E5::A` to `i8` will truncate the value
-  --> tests/ui/cast.rs:292:21
+  --> tests/ui/cast.rs:291:21
    |
 LL |             let _ = Self::A as i8;
    |                     ^^^^^^^^^^^^^
 
 error: casting `main::E6` to `i16` may truncate the value
-  --> tests/ui/cast.rs:309:21
+  --> tests/ui/cast.rs:308:21
    |
 LL |             let _ = self as i16;
    |                     ^^^^^^^^^^^
@@ -427,7 +427,7 @@ LL |             let _ = i16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:328:21
+  --> tests/ui/cast.rs:327:21
    |
 LL |             let _ = self as usize;
    |                     ^^^^^^^^^^^^^
@@ -439,7 +439,7 @@ LL |             let _ = usize::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `main::E10` to `u16` may truncate the value
-  --> tests/ui/cast.rs:375:21
+  --> tests/ui/cast.rs:374:21
    |
 LL |             let _ = self as u16;
    |                     ^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |             let _ = u16::try_from(self);
    |                     ~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:386:13
+  --> tests/ui/cast.rs:385:13
    |
 LL |     let c = (q >> 16) as u8;
    |             ^^^^^^^^^^^^^^^
@@ -463,7 +463,7 @@ LL |     let c = u8::try_from(q >> 16);
    |             ~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:390:13
+  --> tests/ui/cast.rs:389:13
    |
 LL |     let c = (q / 1000) as u8;
    |             ^^^^^^^^^^^^^^^^
@@ -475,85 +475,85 @@ LL |     let c = u8::try_from(q / 1000);
    |             ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:402:9
+  --> tests/ui/cast.rs:401:9
    |
 LL |         (x * x) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:407:32
+  --> tests/ui/cast.rs:406:32
    |
 LL |     let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
    |                                ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:409:5
+  --> tests/ui/cast.rs:408:5
    |
 LL |     (2_i32).checked_pow(3).unwrap() as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:410:5
+  --> tests/ui/cast.rs:409:5
    |
 LL |     (-2_i32).pow(3) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:415:5
+  --> tests/ui/cast.rs:414:5
    |
 LL |     (-5_i32 % 2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:417:5
+  --> tests/ui/cast.rs:416:5
    |
 LL |     (-5_i32 % -2) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:420:5
+  --> tests/ui/cast.rs:419:5
    |
 LL |     (-2_i32 >> 1) as u32;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:424:5
+  --> tests/ui/cast.rs:423:5
    |
 LL |     (x * x) as u32;
    |     ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:425:5
+  --> tests/ui/cast.rs:424:5
    |
 LL |     (x * x * x) as u32;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:429:5
+  --> tests/ui/cast.rs:428:5
    |
 LL |     (y * y * y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:431:5
+  --> tests/ui/cast.rs:430:5
    |
 LL |     (y * y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:432:5
+  --> tests/ui/cast.rs:431:5
    |
 LL |     (y * y / y * 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:434:5
+  --> tests/ui/cast.rs:433:5
    |
 LL |     (y / y * y * -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `/`
-  --> tests/ui/cast.rs:434:6
+  --> tests/ui/cast.rs:433:6
    |
 LL |     (y / y * y * -2) as u16;
    |      ^^^^^
@@ -561,97 +561,97 @@ LL |     (y / y * y * -2) as u16;
    = note: `#[deny(clippy::eq_op)]` on by default
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:437:5
+  --> tests/ui/cast.rs:436:5
    |
 LL |     (y + y + y + -2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:439:5
+  --> tests/ui/cast.rs:438:5
    |
 LL |     (y + y + y + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:443:5
+  --> tests/ui/cast.rs:442:5
    |
 LL |     (z + -2) as u16;
    |     ^^^^^^^^^^^^^^^
 
 error: casting `i16` to `u16` may lose the sign of the value
-  --> tests/ui/cast.rs:445:5
+  --> tests/ui/cast.rs:444:5
    |
 LL |     (z + z + 2) as u16;
    |     ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:448:9
+  --> tests/ui/cast.rs:447:9
    |
 LL |         (a * a * b * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:449:9
+  --> tests/ui/cast.rs:448:9
    |
 LL |         (a * b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:451:9
+  --> tests/ui/cast.rs:450:9
    |
 LL |         (a * -b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:453:9
+  --> tests/ui/cast.rs:452:9
    |
 LL |         (a * b * c * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:454:9
+  --> tests/ui/cast.rs:453:9
    |
 LL |         (a * -2) as u32;
    |         ^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:456:9
+  --> tests/ui/cast.rs:455:9
    |
 LL |         (a * b * c * -2) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:458:9
+  --> tests/ui/cast.rs:457:9
    |
 LL |         (a / b) as u32;
    |         ^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:459:9
+  --> tests/ui/cast.rs:458:9
    |
 LL |         (a / b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:461:9
+  --> tests/ui/cast.rs:460:9
    |
 LL |         (a / b + b * c) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:463:9
+  --> tests/ui/cast.rs:462:9
    |
 LL |         a.saturating_pow(3) as u32;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:465:9
+  --> tests/ui/cast.rs:464:9
    |
 LL |         (a.abs() * b.pow(2) / c.abs()) as u32
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `i32` to `u32` may lose the sign of the value
-  --> tests/ui/cast.rs:473:21
+  --> tests/ui/cast.rs:472:21
    |
 LL |             let _ = i32::MIN as u32; // cast_sign_loss
    |                     ^^^^^^^^^^^^^^^
@@ -662,7 +662,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `u32` to `u8` may truncate the value
-  --> tests/ui/cast.rs:474:21
+  --> tests/ui/cast.rs:473:21
    |
 LL |             let _ = u32::MAX as u8; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^
@@ -678,7 +678,7 @@ LL |             let _ = u8::try_from(u32::MAX); // cast_possible_truncation
    |                     ~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `f64` to `f32` may truncate the value
-  --> tests/ui/cast.rs:475:21
+  --> tests/ui/cast.rs:474:21
    |
 LL |             let _ = std::f64::consts::PI as f32; // cast_possible_truncation
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -690,7 +690,7 @@ LL |     m!();
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers
-  --> tests/ui/cast.rs:484:5
+  --> tests/ui/cast.rs:483:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -702,13 +702,13 @@ LL |     usize::try_from(bar.unwrap().unwrap())
    |
 
 error: casting `i64` to `usize` may lose the sign of the value
-  --> tests/ui/cast.rs:484:5
+  --> tests/ui/cast.rs:483:5
    |
 LL |     bar.unwrap().unwrap() as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:499:5
+  --> tests/ui/cast.rs:498:5
    |
 LL |     (256 & 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,7 +720,7 @@ LL |     u8::try_from(256 & 999999u64);
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 error: casting `u64` to `u8` may truncate the value
-  --> tests/ui/cast.rs:501:5
+  --> tests/ui/cast.rs:500:5
    |
 LL |     (255 % 999999u64) as u8;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr
index c0e81791589..63c568a153b 100644
--- a/src/tools/clippy/tests/ui/issue_4266.stderr
+++ b/src/tools/clippy/tests/ui/issue_4266.stderr
@@ -11,7 +11,7 @@ error: the following explicit lifetimes could be elided: 'a
   --> tests/ui/issue_4266.rs:10:21
    |
 LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
-   |                     ^^      ^^
+   |                     ^^      ^^          ^^
 
 error: methods called `new` usually take no `self`
   --> tests/ui/issue_4266.rs:31:22
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index b810fd8224f..0d6e07aa546 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -54,7 +54,7 @@
 #![allow(enum_intrinsics_non_enums)]
 #![allow(non_fmt_panics)]
 #![allow(named_arguments_used_positionally)]
-#![allow(temporary_cstring_as_ptr)]
+#![allow(dangling_pointers_from_temporaries)]
 #![allow(undropped_manually_drops)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
@@ -120,7 +120,7 @@
 #![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::mismatched_target_os`
 #![warn(non_fmt_panics)] //~ ERROR: lint `clippy::panic_params`
 #![warn(named_arguments_used_positionally)] //~ ERROR: lint `clippy::positional_named_format_parameters`
-#![warn(temporary_cstring_as_ptr)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
+#![warn(dangling_pointers_from_temporaries)] //~ ERROR: lint `clippy::temporary_cstring_as_ptr`
 #![warn(undropped_manually_drops)] //~ ERROR: lint `clippy::undropped_manually_drops`
 #![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
 #![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 46d9f0fac59..b906079d7df 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,11 +1,17 @@
+error: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> tests/ui/rename.rs:57:10
+   |
+LL | #![allow(temporary_cstring_as_ptr)]
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
+
 error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
   --> tests/ui/rename.rs:63:9
    |
 LL | #![warn(clippy::almost_complete_letter_range)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
 
 error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
   --> tests/ui/rename.rs:64:9
@@ -361,11 +367,11 @@ error: lint `clippy::positional_named_format_parameters` has been renamed to `na
 LL | #![warn(clippy::positional_named_format_parameters)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
 
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
   --> tests/ui/rename.rs:123:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
 
 error: lint `clippy::undropped_manually_drops` has been renamed to `undropped_manually_drops`
   --> tests/ui/rename.rs:124:9
@@ -397,5 +403,5 @@ error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_e
 LL | #![warn(clippy::reverse_range_loop)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
 
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
 
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index b6a89dd49e6..cef6b525a7b 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -18,6 +18,7 @@ build_helper = { path = "../build_helper" }
 tracing = "0.1"
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 regex = "1.0"
+semver = { version = "1.0.23", features = ["serde"] }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 rustfix = "0.8.1"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 69ac4644941..e82b88eef79 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -7,6 +7,7 @@ use std::sync::OnceLock;
 use std::{fmt, iter};
 
 use build_helper::git::GitConfig;
+use semver::Version;
 use serde::de::{Deserialize, Deserializer, Error as _};
 use test::{ColorConfig, OutputFormat};
 
@@ -298,7 +299,7 @@ pub struct Config {
     pub lldb_version: Option<u32>,
 
     /// Version of LLVM
-    pub llvm_version: Option<u32>,
+    pub llvm_version: Option<Version>,
 
     /// Is LLVM a system LLVM
     pub system_llvm: bool,
diff --git a/src/tools/compiletest/src/command-list.rs b/src/tools/compiletest/src/directive-list.rs
index 4d57907f26f..4d57907f26f 100644
--- a/src/tools/compiletest/src/command-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index d75cdefe635..bfcdd747eb4 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -6,6 +6,7 @@ use std::io::prelude::*;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
+use semver::Version;
 use tracing::*;
 
 use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
@@ -709,11 +710,11 @@ fn line_directive<'line>(
     Some(DirectiveLine { line_number, revision, raw_directive })
 }
 
-// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
+// To prevent duplicating the list of directives between `compiletest`,`htmldocck` and `jsondocck`,
 // we put it into a common file which is included in rust code and parsed here.
 // FIXME: This setup is temporary until we figure out how to improve this situation.
 //        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!("command-list.rs");
+include!("directive-list.rs");
 
 const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
     "count",
@@ -1113,26 +1114,39 @@ fn parse_normalize_rule(header: &str) -> Option<(String, String)> {
     Some((regex, replacement))
 }
 
-pub fn extract_llvm_version(version: &str) -> Option<u32> {
-    let pat = |c: char| !c.is_ascii_digit() && c != '.';
-    let version_without_suffix = match version.find(pat) {
-        Some(pos) => &version[..pos],
+/// Given an llvm version string that looks like `1.2.3-rc1`, extract as semver. Note that this
+/// accepts more than just strict `semver` syntax (as in `major.minor.patch`); this permits omitting
+/// minor and patch version components so users can write e.g. `//@ min-llvm-version: 19` instead of
+/// having to write `//@ min-llvm-version: 19.0.0`.
+///
+/// Currently panics if the input string is malformed, though we really should not use panic as an
+/// error handling strategy.
+///
+/// FIXME(jieyouxu): improve error handling
+pub fn extract_llvm_version(version: &str) -> Version {
+    // The version substring we're interested in usually looks like the `1.2.3`, without any of the
+    // fancy suffix like `-rc1` or `meow`.
+    let version = version.trim();
+    let uninterested = |c: char| !c.is_ascii_digit() && c != '.';
+    let version_without_suffix = match version.split_once(uninterested) {
+        Some((prefix, _suffix)) => prefix,
         None => version,
     };
-    let components: Vec<u32> = version_without_suffix
+
+    let components: Vec<u64> = version_without_suffix
         .split('.')
-        .map(|s| s.parse().expect("Malformed version component"))
+        .map(|s| s.parse().expect("llvm version component should consist of only digits"))
         .collect();
-    let version = match *components {
-        [a] => a * 10_000,
-        [a, b] => a * 10_000 + b * 100,
-        [a, b, c] => a * 10_000 + b * 100 + c,
-        _ => panic!("Malformed version"),
-    };
-    Some(version)
+
+    match &components[..] {
+        [major] => Version::new(*major, 0, 0),
+        [major, minor] => Version::new(*major, *minor, 0),
+        [major, minor, patch] => Version::new(*major, *minor, *patch),
+        _ => panic!("malformed llvm version string, expected only 1-3 components: {version}"),
+    }
 }
 
-pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
+pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<Version> {
     let output = Command::new(binary_path).arg("--version").output().ok()?;
     if !output.status.success() {
         return None;
@@ -1140,7 +1154,7 @@ pub fn extract_llvm_version_from_binary(binary_path: &str) -> Option<u32> {
     let version = String::from_utf8(output.stdout).ok()?;
     for line in version.lines() {
         if let Some(version) = line.split("LLVM version ").nth(1) {
-            return extract_llvm_version(version);
+            return Some(extract_llvm_version(version));
         }
     }
     None
@@ -1247,15 +1261,17 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
     false
 }
 
-/// Takes a directive of the form `"<version1> [- <version2>]"`,
-/// returns the numeric representation of `<version1>` and `<version2>` as
-/// tuple: `(<version1> as u32, <version2> as u32)`.
+/// Takes a directive of the form `"<version1> [- <version2>]"`, returns the numeric representation
+/// of `<version1>` and `<version2>` as tuple: `(<version1>, <version2>)`.
 ///
-/// If the `<version2>` part is omitted, the second component of the tuple
-/// is the same as `<version1>`.
-fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
+/// If the `<version2>` part is omitted, the second component of the tuple is the same as
+/// `<version1>`.
+fn extract_version_range<'a, F, VersionTy: Clone>(
+    line: &'a str,
+    parse: F,
+) -> Option<(VersionTy, VersionTy)>
 where
-    F: Fn(&str) -> Option<u32>,
+    F: Fn(&'a str) -> Option<VersionTy>,
 {
     let mut splits = line.splitn(2, "- ").map(str::trim);
     let min = splits.next().unwrap();
@@ -1273,7 +1289,7 @@ where
     let max = match max {
         Some("") => return None,
         Some(max) => parse(max)?,
-        _ => min,
+        _ => min.clone(),
     };
 
     Some((min, max))
@@ -1489,43 +1505,55 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
             };
         }
     }
-    if let Some(actual_version) = config.llvm_version {
-        if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) {
-            let min_version = extract_llvm_version(rest).unwrap();
-            // Ignore if actual version is smaller the minimum required
-            // version
-            if actual_version < min_version {
+    if let Some(actual_version) = &config.llvm_version {
+        // 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") {
+            let min_version = extract_llvm_version(&version_string);
+            // Ignore if actual version is smaller than the minimum required version.
+            if *actual_version < min_version {
                 return IgnoreDecision::Ignore {
-                    reason: format!("ignored when the LLVM version is older than {rest}"),
+                    reason: format!(
+                        "ignored when the LLVM version {actual_version} is older than {min_version}"
+                    ),
                 };
             }
-        } else if let Some(rest) = line.strip_prefix("min-system-llvm-version:").map(str::trim) {
-            let min_version = extract_llvm_version(rest).unwrap();
+        } else if let Some(version_string) =
+            config.parse_name_value_directive(line, "min-system-llvm-version")
+        {
+            let min_version = extract_llvm_version(&version_string);
             // Ignore if using system LLVM and actual version
             // is smaller the minimum required version
-            if config.system_llvm && actual_version < min_version {
+            if config.system_llvm && *actual_version < min_version {
                 return IgnoreDecision::Ignore {
-                    reason: format!("ignored when the system LLVM version is older than {rest}"),
+                    reason: format!(
+                        "ignored when the system LLVM version {actual_version} is older than {min_version}"
+                    ),
                 };
             }
-        } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) {
+        } else if let Some(version_range) =
+            config.parse_name_value_directive(line, "ignore-llvm-version")
+        {
             // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
             let (v_min, v_max) =
-                extract_version_range(rest, extract_llvm_version).unwrap_or_else(|| {
-                    panic!("couldn't parse version range: {:?}", rest);
-                });
+                extract_version_range(&version_range, |s| Some(extract_llvm_version(s)))
+                    .unwrap_or_else(|| {
+                        panic!("couldn't parse version range: \"{version_range}\"");
+                    });
             if v_max < v_min {
-                panic!("Malformed LLVM version range: max < min")
+                panic!("malformed LLVM version range where {v_max} < {v_min}")
             }
             // Ignore if version lies inside of range.
-            if actual_version >= v_min && actual_version <= v_max {
+            if *actual_version >= v_min && *actual_version <= v_max {
                 if v_min == v_max {
                     return IgnoreDecision::Ignore {
-                        reason: format!("ignored when the LLVM version is {rest}"),
+                        reason: format!("ignored when the LLVM version is {actual_version}"),
                     };
                 } else {
                     return IgnoreDecision::Ignore {
-                        reason: format!("ignored when the LLVM version is between {rest}"),
+                        reason: format!(
+                            "ignored when the LLVM version is between {v_min} and {v_max}"
+                        ),
                     };
                 }
             }
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index c3c9496c4d2..2e6effcab98 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -1,9 +1,13 @@
 use std::io::Read;
 use std::path::Path;
 
-use super::iter_header;
+use semver::Version;
+
+use super::{
+    EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header,
+    parse_normalize_rule,
+};
 use crate::common::{Config, Debugger, Mode};
-use crate::header::{EarlyProps, HeadersCache, parse_normalize_rule};
 
 fn make_test_description<R: Read>(
     config: &Config,
@@ -408,18 +412,66 @@ fn channel() {
 }
 
 #[test]
+fn test_extract_llvm_version() {
+    // Note: officially, semver *requires* that versions at the minimum have all three
+    // `major.minor.patch` numbers, though for test-writer's convenience we allow omitting the minor
+    // and patch numbers (which will be stubbed out as 0).
+    assert_eq!(extract_llvm_version("0"), Version::new(0, 0, 0));
+    assert_eq!(extract_llvm_version("0.0"), Version::new(0, 0, 0));
+    assert_eq!(extract_llvm_version("0.0.0"), Version::new(0, 0, 0));
+    assert_eq!(extract_llvm_version("1"), Version::new(1, 0, 0));
+    assert_eq!(extract_llvm_version("1.2"), Version::new(1, 2, 0));
+    assert_eq!(extract_llvm_version("1.2.3"), Version::new(1, 2, 3));
+    assert_eq!(extract_llvm_version("4.5.6git"), Version::new(4, 5, 6));
+    assert_eq!(extract_llvm_version("4.5.6-rc1"), Version::new(4, 5, 6));
+    assert_eq!(extract_llvm_version("123.456.789-rc1"), Version::new(123, 456, 789));
+    assert_eq!(extract_llvm_version("8.1.2-rust"), Version::new(8, 1, 2));
+    assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Version::new(9, 0, 1));
+    assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Version::new(9, 3, 1));
+    assert_eq!(extract_llvm_version("10.0.0-rust"), Version::new(10, 0, 0));
+    assert_eq!(extract_llvm_version("11.1.0"), Version::new(11, 1, 0));
+    assert_eq!(extract_llvm_version("12.0.0libcxx"), Version::new(12, 0, 0));
+    assert_eq!(extract_llvm_version("12.0.0-rc3"), Version::new(12, 0, 0));
+    assert_eq!(extract_llvm_version("13.0.0git"), Version::new(13, 0, 0));
+}
+
+#[test]
+#[should_panic]
+fn test_llvm_version_invalid_components() {
+    extract_llvm_version("4.x.6");
+}
+
+#[test]
+#[should_panic]
+fn test_llvm_version_invalid_prefix() {
+    extract_llvm_version("meow4.5.6");
+}
+
+#[test]
+#[should_panic]
+fn test_llvm_version_too_many_components() {
+    extract_llvm_version("4.5.6.7");
+}
+
+#[test]
 fn test_extract_version_range() {
-    use super::{extract_llvm_version, extract_version_range};
-
-    assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506)));
-    assert_eq!(extract_version_range("0   - 4.5.6", extract_llvm_version), Some((0, 40506)));
-    assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None);
-    assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None);
-    assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None);
-    assert_eq!(extract_version_range("-", extract_llvm_version), None);
-    assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
-    assert_eq!(extract_version_range("   - 4.5.6", extract_llvm_version), None);
-    assert_eq!(extract_version_range("0  -", extract_llvm_version), None);
+    let wrapped_extract = |s: &str| Some(extract_llvm_version(s));
+
+    assert_eq!(
+        extract_version_range("1.2.3 - 4.5.6", wrapped_extract),
+        Some((Version::new(1, 2, 3), Version::new(4, 5, 6)))
+    );
+    assert_eq!(
+        extract_version_range("0   - 4.5.6", wrapped_extract),
+        Some((Version::new(0, 0, 0), Version::new(4, 5, 6)))
+    );
+    assert_eq!(extract_version_range("1.2.3 -", wrapped_extract), None);
+    assert_eq!(extract_version_range("1.2.3 - ", wrapped_extract), None);
+    assert_eq!(extract_version_range("- 4.5.6", wrapped_extract), None);
+    assert_eq!(extract_version_range("-", wrapped_extract), None);
+    assert_eq!(extract_version_range(" - 4.5.6", wrapped_extract), None);
+    assert_eq!(extract_version_range("   - 4.5.6", wrapped_extract), None);
+    assert_eq!(extract_version_range("0  -", wrapped_extract), None);
 }
 
 #[test]
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 490df313228..ccf8057bf5c 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -228,7 +228,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
     };
     let llvm_version =
-        matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else(
+        matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else(
             || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
         );
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 3a6eca7dc5d..a8a71c196fc 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1096,6 +1096,10 @@ impl<'test> TestCx<'test> {
         self.config.target.contains("vxworks") && !self.is_vxworks_pure_static()
     }
 
+    fn has_aux_dir(&self) -> bool {
+        !self.props.aux.builds.is_empty() || !self.props.aux.crates.is_empty()
+    }
+
     fn aux_output_dir(&self) -> PathBuf {
         let aux_dir = self.aux_output_dir_name();
 
@@ -1649,7 +1653,11 @@ impl<'test> TestCx<'test> {
         }
 
         if let LinkToAux::Yes = link_to_aux {
-            rustc.arg("-L").arg(self.aux_output_dir_name());
+            // if we pass an `-L` argument to a directory that doesn't exist,
+            // macOS ld emits warnings which disrupt the .stderr files
+            if self.has_aux_dir() {
+                rustc.arg("-L").arg(self.aux_output_dir_name());
+            }
         }
 
         rustc.args(&self.props.compile_flags);
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index e7ae773ffa1..04bc2d7787d 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -329,6 +329,7 @@ impl TestCx<'_> {
             .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
             .arg("--edition=2021")
             .arg(&self.testpaths.file.join("rmake.rs"))
+            .arg("-Cprefer-dynamic")
             // Provide necessary library search paths for rustc.
             .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap());
 
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index 680579c59ae..fec746904de 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -1,7 +1,6 @@
 use std::ffi::OsString;
 
 use crate::debuggers::{extract_gdb_version, extract_lldb_version};
-use crate::header::extract_llvm_version;
 use crate::is_test;
 
 #[test]
@@ -67,15 +66,3 @@ fn is_test_test() {
     assert!(!is_test(&OsString::from("#a_dog_gif")));
     assert!(!is_test(&OsString::from("~a_temp_file")));
 }
-
-#[test]
-fn test_extract_llvm_version() {
-    assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102));
-    assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001));
-    assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301));
-    assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000));
-    assert_eq!(extract_llvm_version("11.1.0"), Some(110100));
-    assert_eq!(extract_llvm_version("12.0.0libcxx"), Some(120000));
-    assert_eq!(extract_llvm_version("12.0.0-rc3"), Some(120000));
-    assert_eq!(extract_llvm_version("13.0.0git"), Some(130000));
-}
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index b264405ac3e..c08bbbc769a 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -123,7 +123,7 @@ fn print_err(msg: &str, lineno: usize) {
 
 // FIXME: This setup is temporary until we figure out how to improve this situation.
 //        See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>.
-include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/command-list.rs"));
+include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs"));
 
 /// Get a list of commands from a file. Does the work of ensuring the commands
 /// are syntactically valid.
diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml
index 8b0916f5111..2e491319822 100644
--- a/src/tools/miri/.github/workflows/ci.yml
+++ b/src/tools/miri/.github/workflows/ci.yml
@@ -1,11 +1,7 @@
 name: CI
 
 on:
-  push:
-    # Run in PRs and for bors, but not on master.
-    branches:
-      - 'auto'
-      - 'try'
+  merge_group:
   pull_request:
     branches:
       - 'master'
@@ -38,7 +34,7 @@ jobs:
       # The `style` job only runs on Linux; this makes sure the Windows-host-specific
       # code is also covered by clippy.
       - name: Check clippy
-        if: matrix.os == 'windows-latest'
+        if: ${{ matrix.os == 'windows-latest' }}
         run: ./miri clippy -- -D warnings
 
       - name: Test Miri
@@ -62,27 +58,25 @@ jobs:
       - name: rustdoc
         run: RUSTDOCFLAGS="-Dwarnings" ./miri doc --document-private-items
 
-  # These jobs doesn't actually test anything, but they're only used to tell
-  # bors the build completed, as there is no practical way to detect when a
-  # workflow is successful listening to webhooks only.
-  #
+  # Summary job for the merge queue.
   # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
-  end-success:
-    name: bors build finished
-    runs-on: ubuntu-latest
+  # And they should be added below in `cron-fail-notify` as well.
+  conclusion:
     needs: [build, style]
-    if: github.event.pusher.name == 'bors' && success()
-    steps:
-      - name: mark the job as a success
-        run: exit 0
-  end-failure:
-    name: bors build finished
+    # We need to ensure this job does *not* get skipped if its dependencies fail,
+    # because a skipped job is considered a success by GitHub. So we have to
+    # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+    # when the workflow is canceled manually.
+    if: ${{ !cancelled() }}
     runs-on: ubuntu-latest
-    needs: [build, style]
-    if: github.event.pusher.name == 'bors' && (failure() || cancelled())
     steps:
-      - name: mark the job as a failure
-        run: exit 1
+      # Manually check the status of all dependencies. `if: failure()` does not work.
+      - name: Conclusion
+        run: |
+            # Print the dependent jobs to see them in the CI log
+            jq -C <<< '${{ toJson(needs) }}'
+            # Check if all jobs that we depend on (in the needs array) were successful.
+            jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
 
   cron-fail-notify:
     name: cronjob failure notification
@@ -93,7 +87,7 @@ jobs:
         # ... and create a PR.
         pull-requests: write
     needs: [build, style]
-    if: github.event_name == 'schedule' && failure()
+    if: ${{ github.event_name == 'schedule' && failure() }}
     steps:
       # Send a Zulip notification
       - name: Install zulip-send
@@ -145,7 +139,7 @@ jobs:
           git push -u origin $BRANCH
       - name: Create Pull Request
         run: |
-          PR=$(gh pr create -B master --title 'Automatic Rustup' --body '')
+          PR=$(gh pr create -B master --title 'Automatic Rustup' --body 'Please close and re-open this PR to trigger CI, then enable auto-merge.')
           ~/.local/bin/zulip-send --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com \
             --stream miri --subject "Miri Build Failure ($(date -u +%Y-%m))" \
             --message "A PR doing a rustc-pull [has been automatically created]($PR) for your convenience."
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index ad1b2f4d0c3..4e7cbc50ca0 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -154,7 +154,7 @@ case $HOST_TARGET in
     TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
     TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
     TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
-    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname
+    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX time hashmap threadname pthread
     TEST_TARGET=wasm32-wasip2          run_tests_minimal $BASIC wasm
     TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
     TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 8b9e7efdff9..133edd3191d 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-17a19e684cdf3ca088af8b4da6a6209d128913f4
+814df6e50eaf89b90793e7d9618bb60f1f18377a
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
index 1684abeec6b..5624c4c479e 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs
@@ -424,7 +424,11 @@ impl<'history, 'ecx, 'tcx> DiagnosticCx<'history, 'ecx, 'tcx> {
     }
 
     #[inline(never)] // This is only called on fatal code paths
-    pub(super) fn protector_error(&self, item: &Item, kind: ProtectorKind) -> InterpErrorKind<'tcx> {
+    pub(super) fn protector_error(
+        &self,
+        item: &Item,
+        kind: ProtectorKind,
+    ) -> InterpErrorKind<'tcx> {
         let protected = match kind {
             ProtectorKind::WeakProtector => "weakly protected",
             ProtectorKind::StrongProtector => "strongly protected",
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 09ec2cb46b0..776d2561b43 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -145,6 +145,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(Scalar::from_bool(branch), dest)?;
             }
 
+            "floorf16" | "ceilf16" | "truncf16" | "roundf16" | "rintf16" => {
+                let [f] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f16()?;
+                let mode = match intrinsic_name {
+                    "floorf16" => Round::TowardNegative,
+                    "ceilf16" => Round::TowardPositive,
+                    "truncf16" => Round::TowardZero,
+                    "roundf16" => Round::NearestTiesToAway,
+                    "rintf16" => Round::NearestTiesToEven,
+                    _ => bug!(),
+                };
+                let res = f.round_to_integral(mode).value;
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
             "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
                 let [f] = check_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
@@ -175,6 +190,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
+            "floorf128" | "ceilf128" | "truncf128" | "roundf128" | "rintf128" => {
+                let [f] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f128()?;
+                let mode = match intrinsic_name {
+                    "floorf128" => Round::TowardNegative,
+                    "ceilf128" => Round::TowardPositive,
+                    "truncf128" => Round::TowardZero,
+                    "roundf128" => Round::NearestTiesToAway,
+                    "rintf128" => Round::NearestTiesToEven,
+                    _ => bug!(),
+                };
+                let res = f.round_to_integral(mode).value;
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
 
             #[rustfmt::skip]
             | "sinf32"
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 0799b93dbb0..f15b83a054f 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -1,7 +1,8 @@
 use either::Either;
 use rustc_apfloat::{Float, Round};
+use rustc_middle::ty::FloatTy;
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::{mir, ty, ty::FloatTy};
+use rustc_middle::{mir, ty};
 use rustc_span::{Symbol, sym};
 use rustc_target::abi::{Endian, HasDataLayout};
 
@@ -630,12 +631,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let (right, right_len) = this.project_to_simd(right)?;
                 let (dest, dest_len) = this.project_to_simd(dest)?;
 
-                let index = generic_args[2]
-                    .expect_const()
-                    .try_to_valtree()
-                    .unwrap()
-                    .0
-                    .unwrap_branch();
+                let index =
+                    generic_args[2].expect_const().try_to_valtree().unwrap().0.unwrap_branch();
                 let index_len = index.len();
 
                 assert_eq!(left_len, right_len);
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 660f2e493bc..938d1ca319e 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -147,7 +147,7 @@ pub use crate::range_map::RangeMap;
 pub use crate::shims::EmulateItemResult;
 pub use crate::shims::env::{EnvVars, EvalContextExt as _};
 pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
-pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
+pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
 pub use crate::shims::os_str::EvalContextExt as _;
 pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
 pub use crate::shims::time::EvalContextExt as _;
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index f6f91e58969..12f8facfd02 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -447,8 +447,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
@@ -464,8 +463,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else {
                     // On size overflow, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
@@ -486,8 +484,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
                     if this.target_os_is_unix() {
-                        let einval = this.eval_libc("ENOMEM");
-                        this.set_last_error(einval)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                     }
                     this.write_null(dest)?;
                 }
diff --git a/src/tools/miri/src/shims/io_error.rs b/src/tools/miri/src/shims/io_error.rs
index 38aa181cb4f..04491f0542b 100644
--- a/src/tools/miri/src/shims/io_error.rs
+++ b/src/tools/miri/src/shims/io_error.rs
@@ -141,6 +141,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(-1))
     }
 
+    /// Sets the last OS error and return `-1` as a `i64`-typed Scalar
+    fn set_last_error_and_return_i64(
+        &mut self,
+        err: impl Into<IoError>,
+    ) -> InterpResult<'tcx, Scalar> {
+        let this = self.eval_context_mut();
+        this.set_last_error(err)?;
+        interp_ok(Scalar::from_i64(-1))
+    }
+
     /// Gets the last error variable.
     fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs
index 12c7679608d..6436823b0fd 100644
--- a/src/tools/miri/src/shims/time.rs
+++ b/src/tools/miri/src/shims/time.rs
@@ -81,9 +81,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if relative_clocks.contains(&clk_id) {
             this.machine.clock.now().duration_since(this.machine.clock.epoch())
         } else {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         };
 
         let tv_sec = duration.as_secs();
@@ -109,9 +107,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Using tz is obsolete and should always be null
         let tz = this.read_pointer(tz_op)?;
         if !this.ptr_is_null(tz)? {
-            let einval = this.eval_libc("EINVAL");
-            this.set_last_error(einval)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         let duration = system_time_to_duration(&SystemTime::now())?;
@@ -323,9 +319,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let duration = match this.read_timespec(&req)? {
             Some(duration) => duration,
             None => {
-                let einval = this.eval_libc("EINVAL");
-                this.set_last_error(einval)?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("EINVAL"));
             }
         };
 
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
index 583a1f65009..b6f04951fc7 100644
--- a/src/tools/miri/src/shims/unix/android/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -1,6 +1,7 @@
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 
+use crate::shims::unix::android::thread::prctl;
 use crate::*;
 
 pub fn is_dyn_sym(_name: &str) -> bool {
@@ -25,6 +26,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
+            // Threading
+            "prctl" => prctl(this, link_name, abi, args, dest)?,
+
             _ => return interp_ok(EmulateItemResult::NotSupported),
         }
         interp_ok(EmulateItemResult::NeedsReturn)
diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs
index 09c6507b24f..1f2a74bac59 100644
--- a/src/tools/miri/src/shims/unix/android/mod.rs
+++ b/src/tools/miri/src/shims/unix/android/mod.rs
@@ -1 +1,2 @@
 pub mod foreign_items;
+pub mod thread;
diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs
new file mode 100644
index 00000000000..6f5f0f74a22
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/android/thread.rs
@@ -0,0 +1,57 @@
+use rustc_span::Symbol;
+use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
+
+use crate::helpers::check_min_arg_count;
+use crate::shims::unix::thread::EvalContextExt as _;
+use crate::*;
+
+const TASK_COMM_LEN: usize = 16;
+
+pub fn prctl<'tcx>(
+    this: &mut MiriInterpCx<'tcx>,
+    link_name: Symbol,
+    abi: Abi,
+    args: &[OpTy<'tcx>],
+    dest: &MPlaceTy<'tcx>,
+) -> InterpResult<'tcx> {
+    // We do not use `check_shim` here because `prctl` is variadic. The argument
+    // count is checked bellow.
+    this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?;
+
+    // FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
+    let pr_set_name = 15;
+    let pr_get_name = 16;
+
+    let [op] = check_min_arg_count("prctl", args)?;
+    let res = match this.read_scalar(op)?.to_i32()? {
+        op if op == pr_set_name => {
+            let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
+            let name = this.read_scalar(name)?;
+            let thread = this.pthread_self()?;
+            // The Linux kernel silently truncates long names.
+            // https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
+            let res =
+                this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
+            assert!(res);
+            Scalar::from_u32(0)
+        }
+        op if op == pr_get_name => {
+            let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
+            let name = this.read_scalar(name)?;
+            let thread = this.pthread_self()?;
+            let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
+            this.check_ptr_access(
+                name.to_pointer(this)?,
+                Size::from_bytes(TASK_COMM_LEN),
+                CheckInAllocMsg::MemoryAccessTest,
+            )?;
+            let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
+            assert!(res);
+            Scalar::from_u32(0)
+        }
+        op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
+    };
+    this.write_scalar(res, dest)?;
+    interp_ok(())
+}
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e3914640037..f3db56695fc 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         interp_ok(Scalar::from_i32(this.machine.fds.insert(fd)))
     }
@@ -432,7 +432,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let this = self.eval_context_mut();
 
         let Some(fd) = this.machine.fds.get(old_fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         if new_fd_num != old_fd_num {
             // Close new_fd if it is previously opened.
@@ -448,7 +448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
 
         // We need to check that there aren't unsupported options in `op`.
@@ -498,11 +498,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
                 // always sets this flag when opening a file. However we still need to check that the
                 // file itself is open.
-                interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
-                    this.eval_libc_i32("FD_CLOEXEC")
+                if !this.machine.fds.is_fd_num(fd_num) {
+                    this.set_last_error_and_return_i32(LibcError("EBADF"))
                 } else {
-                    this.fd_not_found()?
-                }))
+                    interp_ok(this.eval_libc("FD_CLOEXEC"))
+                }
             }
             cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => {
                 // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part
@@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 if let Some(fd) = this.machine.fds.get(fd_num) {
                     interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start)))
                 } else {
-                    interp_ok(Scalar::from_i32(this.fd_not_found()?))
+                    this.set_last_error_and_return_i32(LibcError("EBADF"))
                 }
             }
             cmd if this.tcx.sess.target.os == "macos"
@@ -547,7 +547,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let fd_num = this.read_scalar(fd_op)?.to_i32()?;
 
         let Some(fd) = this.machine.fds.remove(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let result = fd.close(this.machine.communicate(), this)?;
         // return `0` if close is successful
@@ -555,17 +555,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
     }
 
-    /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
-    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
-    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
-    /// types (like `read`, that returns an `i64`).
-    fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
-        let this = self.eval_context_mut();
-        let ebadf = this.eval_libc("EBADF");
-        this.set_last_error(ebadf)?;
-        interp_ok((-1).into())
-    }
-
     /// Read data from `fd` into buffer specified by `buf` and `count`.
     ///
     /// If `offset` is `None`, reads data from current cursor position associated with `fd`
@@ -599,9 +588,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // We temporarily dup the FD to be able to retain mutable access to `this`.
         let Some(fd) = this.machine.fds.get(fd_num) else {
             trace!("read: FD not found");
-            let res: i32 = this.fd_not_found()?;
-            this.write_int(res, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
         trace!("read: FD mapped to {fd:?}");
@@ -646,9 +633,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // We temporarily dup the FD to be able to retain mutable access to `this`.
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            let res: i32 = this.fd_not_found()?;
-            this.write_int(res, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
 
         match offset {
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 7ba98981920..355c93c444c 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -362,8 +362,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
                 match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
                     None => {
-                        let enmem = this.eval_libc("ENOMEM");
-                        this.set_last_error(enmem)?;
+                        this.set_last_error(LibcError("ENOMEM"))?;
                         this.write_null(dest)?;
                     }
                     Some(len) => {
@@ -653,13 +652,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let chunk_size = CpuAffinityMask::chunk_size(this);
 
                 if this.ptr_is_null(mask)? {
-                    let efault = this.eval_libc("EFAULT");
-                    this.set_last_error(efault)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
                 } else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
                     // we only copy whole chunks of size_of::<c_ulong>()
-                    this.set_last_error(LibcError("EINVAL"))?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                 } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
                     let cpuset = cpuset.clone();
                     // we only copy whole chunks of size_of::<c_ulong>()
@@ -668,9 +664,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.write_null(dest)?;
                 } else {
                     // The thread whose ID is pid could not be found
-                    let esrch = this.eval_libc("ESRCH");
-                    this.set_last_error(esrch)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("ESRCH"), dest)?;
                 }
             }
             "sched_setaffinity" => {
@@ -695,9 +689,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 };
 
                 if this.ptr_is_null(mask)? {
-                    let efault = this.eval_libc("EFAULT");
-                    this.set_last_error(efault)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EFAULT"), dest)?;
                 } else {
                     // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
                     // Any unspecified bytes are treated as zero here (none of the CPUs are configured).
@@ -713,8 +705,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         }
                         None => {
                             // The intersection between the mask and the available CPUs was empty.
-                            this.set_last_error(LibcError("EINVAL"))?;
-                            this.write_int(-1, dest)?;
+                            this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                         }
                     }
                 }
@@ -770,9 +761,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // macOS: https://keith.github.io/xcode-man-pages/getentropy.2.html
                 // Solaris/Illumos: https://illumos.org/man/3C/getentropy
                 if bufsize > 256 {
-                    let err = this.eval_libc("EIO");
-                    this.set_last_error(err)?;
-                    this.write_int(-1, dest)?;
+                    this.set_last_error_and_return(LibcError("EIO"), dest)?;
                 } else {
                     this.gen_random(buf, bufsize)?;
                     this.write_null(dest)?;
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index 5204e57705a..71953aca989 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -29,6 +29,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
+                    /* truncate */ false,
                 )?;
             }
             "pthread_get_name_np" => {
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 4b3ae8e0520..f7436d7f089 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -149,6 +149,7 @@ impl FileDescription for FileHandle {
             // to handle possible errors correctly.
             let result = self.file.sync_all();
             // Now we actually close the file and return the result.
+            drop(*self);
             interp_ok(result)
         } else {
             // We drop the file, this closes it but ignores any errors
@@ -157,6 +158,7 @@ impl FileDescription for FileHandle {
             // `/dev/urandom` which are read-only. Check
             // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439
             // for a deeper discussion.
+            drop(*self);
             interp_ok(Ok(()))
         }
     }
@@ -229,6 +231,8 @@ impl FileDescription for FileHandle {
                 TRUE => Ok(()),
                 FALSE => {
                     let mut err = io::Error::last_os_error();
+                    // This only runs on Windows hosts so we can use `raw_os_error`.
+                    // We have to be careful not to forward that error code to target code.
                     let code: u32 = err.raw_os_error().unwrap().try_into().unwrap();
                     if matches!(code, ERROR_IO_PENDING | ERROR_LOCK_VIOLATION) {
                         if lock_nb {
@@ -337,15 +341,10 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     _ => interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
                 }
             }
-            Err(e) =>
-                match e.raw_os_error() {
-                    Some(error) => interp_ok(error),
-                    None =>
-                        throw_unsup_format!(
-                            "the error {} couldn't be converted to a return value",
-                            e
-                        ),
-                },
+            Err(_) => {
+                // Fallback on error
+                interp_ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
+            }
         }
     }
 }
@@ -528,8 +527,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let o_tmpfile = this.eval_libc_i32("O_TMPFILE");
             if flag & o_tmpfile == o_tmpfile {
                 // if the flag contains `O_TMPFILE` then we return a graceful error
-                this.set_last_error(LibcError("EOPNOTSUPP"))?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("EOPNOTSUPP"));
             }
         }
 
@@ -548,9 +546,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 // O_NOFOLLOW only fails when the trailing component is a symlink;
                 // the entire rest of the path can still contain symlinks.
                 if path.is_symlink() {
-                    let eloop = this.eval_libc("ELOOP");
-                    this.set_last_error(eloop)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("ELOOP"));
                 }
             }
             mirror |= o_nofollow;
@@ -565,8 +561,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let fd = options
@@ -584,8 +579,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
             if offset < 0 {
                 // Negative offsets return `EINVAL`.
-                this.set_last_error(LibcError("EINVAL"))?;
-                return interp_ok(Scalar::from_i64(-1));
+                return this.set_last_error_and_return_i64(LibcError("EINVAL"));
             } else {
                 SeekFrom::Start(u64::try_from(offset).unwrap())
             }
@@ -594,14 +588,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         } else if whence == this.eval_libc_i32("SEEK_END") {
             SeekFrom::End(i64::try_from(offset).unwrap())
         } else {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i64(-1));
+            return this.set_last_error_and_return_i64(LibcError("EINVAL"));
         };
 
         let communicate = this.machine.communicate();
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i64(this.fd_not_found()?));
+            return this.set_last_error_and_return_i64(LibcError("EBADF"));
         };
         let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
         drop(fd);
@@ -618,8 +611,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = remove_file(path).map(|_| 0);
@@ -649,8 +641,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = create_link(&target, &linkpath).map(|_| 0);
@@ -674,15 +665,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`stat`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         // `stat` always follows symlinks.
         let metadata = match FileMetadata::from_path(this, &path, true)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -706,14 +695,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`lstat`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         let metadata = match FileMetadata::from_path(this, &path, false)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -736,12 +723,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fstat`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let metadata = match FileMetadata::from_fd_num(this, fd)? {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)),
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
         interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
     }
@@ -766,9 +753,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`.
         if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
-            let efault = this.eval_libc("EFAULT");
-            this.set_last_error(efault)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EFAULT"));
         }
 
         let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
@@ -801,16 +786,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") {
                 // since `path` is provided, either absolute or
                 // relative to CWD, `EACCES` is the most relevant.
-                this.eval_libc("EACCES")
+                LibcError("EACCES")
             } else {
                 // `dirfd` is set to target file, and `path` is empty
                 // (or we would have hit the `throw_unsup_format`
                 // above). `EACCES` would violate the spec.
                 assert!(empty_path_flag);
-                this.eval_libc("EBADF")
+                LibcError("EBADF")
             };
-            this.set_last_error(ecode)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ecode);
         }
 
         // the `_mask_op` parameter specifies the file information that the caller requested.
@@ -831,8 +815,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             FileMetadata::from_path(this, &path, follow_symlink)?
         };
         let metadata = match metadata {
-            Some(metadata) => metadata,
-            None => return interp_ok(Scalar::from_i32(-1)),
+            Ok(metadata) => metadata,
+            Err(err) => return this.set_last_error_and_return_i32(err),
         };
 
         // The `mode` field specifies the type of the file and the permissions over the file for
@@ -939,9 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let newpath_ptr = this.read_pointer(newpath_op)?;
 
         if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
-            let efault = this.eval_libc("EFAULT");
-            this.set_last_error(efault)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EFAULT"));
         }
 
         let oldpath = this.read_path_from_c_str(oldpath_ptr)?;
@@ -950,8 +932,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = rename(oldpath, newpath).map(|_| 0);
@@ -974,8 +955,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         #[cfg_attr(not(unix), allow(unused_mut))]
@@ -1002,8 +982,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
-            this.set_last_error(ErrorKind::PermissionDenied)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(ErrorKind::PermissionDenied);
         }
 
         let result = remove_dir(path).map(|_| 0i32);
@@ -1019,8 +998,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`opendir`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(Scalar::null_ptr(this));
         }
 
@@ -1052,8 +1030,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readdir`", reject_with)?;
-            let eacc = this.eval_libc("EBADF");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EBADF"))?;
             return interp_ok(Scalar::null_ptr(this));
         }
 
@@ -1152,14 +1129,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readdir_r`", reject_with)?;
-            // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            // Return error code, do *not* set `errno`.
+            return interp_ok(this.eval_libc("EBADF"));
         }
 
         let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
             err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
         })?;
-        interp_ok(Scalar::from_i32(match open_dir.read_dir.next() {
+        interp_ok(match open_dir.read_dir.next() {
             Some(Ok(dir_entry)) => {
                 // Write into entry, write pointer to result, return 0 on success.
                 // The name is written with write_os_str_to_c_str, while the rest of the
@@ -1237,25 +1214,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let result_place = this.deref_pointer(result_op)?;
                 this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
 
-                0
+                Scalar::from_i32(0)
             }
             None => {
                 // end of stream: return 0, assign *result=NULL
                 this.write_null(&this.deref_pointer(result_op)?)?;
-                0
+                Scalar::from_i32(0)
             }
-            Some(Err(e)) =>
-                match e.raw_os_error() {
-                    // return positive error number on error
-                    Some(error) => error,
-                    None => {
-                        throw_unsup_format!(
-                            "the error {} couldn't be converted to a return value",
-                            e
-                        )
-                    }
-                },
-        }))
+            Some(Err(e)) => {
+                // return positive error number on error (do *not* set last error)
+                this.io_error_to_errnum(e)?
+            }
+        })
     }
 
     fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
@@ -1264,20 +1234,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let dirp = this.read_target_usize(dirp_op)?;
 
         // Reject if isolation is enabled.
-        interp_ok(Scalar::from_i32(
-            if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
-                this.reject_in_isolation("`closedir`", reject_with)?;
-                this.fd_not_found()?
-            } else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
-                if let Some(entry) = open_dir.entry {
-                    this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
-                }
-                drop(open_dir);
-                0
-            } else {
-                this.fd_not_found()?
-            },
-        ))
+        if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
+            this.reject_in_isolation("`closedir`", reject_with)?;
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
+        }
+
+        let Some(mut open_dir) = this.machine.dirs.streams.remove(&dirp) else {
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
+        };
+        if let Some(entry) = open_dir.entry.take() {
+            this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
+        }
+        // We drop the `open_dir`, which will close the host dir handle.
+        drop(open_dir);
+
+        interp_ok(Scalar::from_i32(0))
     }
 
     fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1287,11 +1258,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`ftruncate64`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
 
         // FIXME: Support ftruncate64 for all FDs
@@ -1307,14 +1278,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 interp_ok(Scalar::from_i32(result))
             } else {
                 drop(fd);
-                this.set_last_error(LibcError("EINVAL"))?;
-                interp_ok(Scalar::from_i32(-1))
+                this.set_last_error_and_return_i32(LibcError("EINVAL"))
             }
         } else {
             drop(fd);
             // The file is not writable
-            this.set_last_error(LibcError("EINVAL"))?;
-            interp_ok(Scalar::from_i32(-1))
+            this.set_last_error_and_return_i32(LibcError("EINVAL"))
         }
     }
 
@@ -1332,7 +1301,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fsync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         self.ffullsync_fd(fd)
@@ -1341,7 +1310,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
         let this = self.eval_context_mut();
         let Some(fd) = this.machine.fds.get(fd_num) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1361,11 +1330,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`fdatasync`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1391,26 +1360,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let flags = this.read_scalar(flags_op)?.to_i32()?;
 
         if offset < 0 || nbytes < 0 {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
         let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")
             | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER");
         if flags & allowed_flags != flags {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`sync_file_range`", reject_with)?;
             // Set error code as "EBADF" (bad fd)
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         }
 
         let Some(fd) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         // Only regular files support synchronization.
         let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1436,8 +1403,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`readlink`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(-1);
         }
 
@@ -1475,11 +1441,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if fd.is_tty(this.machine.communicate()) {
                 return interp_ok(Scalar::from_i32(1));
             } else {
-                this.eval_libc("ENOTTY")
+                LibcError("ENOTTY")
             }
         } else {
             // FD does not exist
-            this.eval_libc("EBADF")
+            LibcError("EBADF")
         };
         this.set_last_error(error)?;
         interp_ok(Scalar::from_i32(0))
@@ -1499,8 +1465,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`realpath`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
+            this.set_last_error(LibcError("EACCES"))?;
             return interp_ok(Scalar::from_target_usize(0, this));
         }
 
@@ -1530,8 +1495,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         // Note that we do not explicitly handle `FILENAME_MAX`
                         // (different from `PATH_MAX` above) as it is Linux-specific and
                         // seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
-                        let enametoolong = this.eval_libc("ENAMETOOLONG");
-                        this.set_last_error(enametoolong)?;
+                        this.set_last_error(LibcError("ENAMETOOLONG"))?;
                         return interp_ok(Scalar::from_target_usize(0, this));
                     }
                     processed_ptr
@@ -1574,9 +1538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkstemp`", reject_with)?;
-            let eacc = this.eval_libc("EACCES");
-            this.set_last_error(eacc)?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EACCES"));
         }
 
         // Get the bytes of the suffix we expect in _target_ encoding.
@@ -1592,8 +1554,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // If we don't find the suffix, it is an error.
         if last_six_char_bytes != suffix_bytes {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // At this point we know we have 6 ASCII 'X' characters as a suffix.
@@ -1658,17 +1619,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         _ => {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
-                            this.set_last_error(e)?;
-                            return interp_ok(Scalar::from_i32(-1));
+                            return this.set_last_error_and_return_i32(e);
                         }
                     },
             }
         }
 
         // We ran out of attempts to create the file, return an error.
-        let eexist = this.eval_libc("EEXIST");
-        this.set_last_error(eexist)?;
-        interp_ok(Scalar::from_i32(-1))
+        this.set_last_error_and_return_i32(LibcError("EEXIST"))
     }
 }
 
@@ -1702,7 +1660,7 @@ impl FileMetadata {
         ecx: &mut MiriInterpCx<'tcx>,
         path: &Path,
         follow_symlink: bool,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let metadata =
             if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) };
 
@@ -1712,9 +1670,9 @@ impl FileMetadata {
     fn from_fd_num<'tcx>(
         ecx: &mut MiriInterpCx<'tcx>,
         fd_num: i32,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let Some(fd) = ecx.machine.fds.get(fd_num) else {
-            return ecx.fd_not_found().map(|_: i32| None);
+            return interp_ok(Err(LibcError("EBADF")));
         };
 
         let file = &fd
@@ -1734,12 +1692,11 @@ impl FileMetadata {
     fn from_meta<'tcx>(
         ecx: &mut MiriInterpCx<'tcx>,
         metadata: Result<std::fs::Metadata, std::io::Error>,
-    ) -> InterpResult<'tcx, Option<FileMetadata>> {
+    ) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
         let metadata = match metadata {
             Ok(metadata) => metadata,
             Err(e) => {
-                ecx.set_last_error(e)?;
-                return interp_ok(None);
+                return interp_ok(Err(e.into()));
             }
         };
 
@@ -1762,6 +1719,6 @@ impl FileMetadata {
         let modified = extract_sec_and_nsec(metadata.modified())?;
 
         // FIXME: Provide more fields using platform specific methods.
-        interp_ok(Some(FileMetadata { mode, size, created, accessed, modified }))
+        interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified }))
     }
 }
diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs
index cafc7161d26..de108665e9f 100644
--- a/src/tools/miri/src/shims/unix/linux/epoll.rs
+++ b/src/tools/miri/src/shims/unix/linux/epoll.rs
@@ -256,23 +256,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let epollhup = this.eval_libc_u32("EPOLLHUP");
         let epollerr = this.eval_libc_u32("EPOLLERR");
 
-        // Fail on unsupported operations.
-        if op & epoll_ctl_add != epoll_ctl_add
-            && op & epoll_ctl_mod != epoll_ctl_mod
-            && op & epoll_ctl_del != epoll_ctl_del
-        {
-            throw_unsup_format!("epoll_ctl: encountered unknown unsupported operation {:#x}", op);
-        }
-
         // Throw EINVAL if epfd and fd have the same value.
         if epfd_value == fd {
-            this.set_last_error(LibcError("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         // Check if epfd is a valid epoll file descriptor.
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let epoll_file_description = epfd
             .downcast::<Epoll>()
@@ -282,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let ready_list = &epoll_file_description.ready_list;
 
         let Some(fd_ref) = this.machine.fds.get(fd) else {
-            return interp_ok(Scalar::from_i32(this.fd_not_found()?));
+            return this.set_last_error_and_return_i32(LibcError("EBADF"));
         };
         let id = fd_ref.get_id();
 
@@ -332,15 +323,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Check the existence of fd in the interest list.
             if op == epoll_ctl_add {
                 if interest_list.contains_key(&epoll_key) {
-                    let eexist = this.eval_libc("EEXIST");
-                    this.set_last_error(eexist)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("EEXIST"));
                 }
             } else {
                 if !interest_list.contains_key(&epoll_key) {
-                    let enoent = this.eval_libc("ENOENT");
-                    this.set_last_error(enoent)?;
-                    return interp_ok(Scalar::from_i32(-1));
+                    return this.set_last_error_and_return_i32(LibcError("ENOENT"));
                 }
             }
 
@@ -368,15 +355,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             // Notification will be returned for current epfd if there is event in the file
             // descriptor we registered.
             check_and_update_one_event_interest(&fd_ref, interest, id, this)?;
-            return interp_ok(Scalar::from_i32(0));
+            interp_ok(Scalar::from_i32(0))
         } else if op == epoll_ctl_del {
             let epoll_key = (id, fd);
 
             // Remove epoll_event_interest from interest_list.
             let Some(epoll_interest) = interest_list.remove(&epoll_key) else {
-                let enoent = this.eval_libc("ENOENT");
-                this.set_last_error(enoent)?;
-                return interp_ok(Scalar::from_i32(-1));
+                return this.set_last_error_and_return_i32(LibcError("ENOENT"));
             };
             // All related Weak<EpollEventInterest> will fail to upgrade after the drop.
             drop(epoll_interest);
@@ -394,9 +379,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 .unwrap()
                 .retain(|event| event.upgrade().is_some());
 
-            return interp_ok(Scalar::from_i32(0));
+            interp_ok(Scalar::from_i32(0))
+        } else {
+            throw_unsup_format!("unsupported epoll_ctl operation: {op}");
         }
-        interp_ok(Scalar::from_i32(-1))
     }
 
     /// The `epoll_wait()` system call waits for events on the `Epoll`
@@ -447,9 +433,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let timeout = this.read_scalar(timeout)?.to_i32()?;
 
         if epfd_value <= 0 || maxevents <= 0 {
-            this.set_last_error(LibcError("EINVAL"))?;
-            this.write_int(-1, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EINVAL"), dest);
         }
 
         // This needs to come after the maxevents value check, or else maxevents.try_into().unwrap()
@@ -460,9 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         )?;
 
         let Some(epfd) = this.machine.fds.get(epfd_value) else {
-            let result_value: i32 = this.fd_not_found()?;
-            this.write_int(result_value, dest)?;
-            return interp_ok(());
+            return this.set_last_error_and_return(LibcError("EBADF"), dest);
         };
         // Create a weak ref of epfd and pass it to callback so we will make sure that epfd
         // is not close after the thread unblocks.
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index e73bde1ddb6..6616a9845c0 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -84,6 +84,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     TASK_COMM_LEN,
+                    /* truncate */ false,
                 )?;
                 let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
                 this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 4f2e17d50c8..d5f9669b360 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // old_address must be a multiple of the page size
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if old_address.addr().bytes() % this.machine.page_size != 0 || new_size == 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         if flags & this.eval_libc_i32("MREMAP_MAYMOVE") == 0 {
             // We only support MREMAP_MAYMOVE, so not passing the flag is just a failure
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs
index 941011bfac6..c258be78f76 100644
--- a/src/tools/miri/src/shims/unix/linux/sync.rs
+++ b/src/tools/miri/src/shims/unix/linux/sync.rs
@@ -63,8 +63,7 @@ pub fn futex<'tcx>(
             };
 
             if bitset == 0 {
-                this.set_last_error(LibcError("EINVAL"))?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+                this.set_last_error_and_return(LibcError("EINVAL"), dest)?;
                 return interp_ok(());
             }
 
@@ -75,9 +74,7 @@ pub fn futex<'tcx>(
                 let duration = match this.read_timespec(&timeout)? {
                     Some(duration) => duration,
                     None => {
-                        this.set_last_error(LibcError("EINVAL"))?;
-                        this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                        return interp_ok(());
+                        return this.set_last_error_and_return(LibcError("EINVAL"), dest);
                     }
                 };
                 let timeout_clock = if op & futex_realtime == futex_realtime {
@@ -153,14 +150,12 @@ pub fn futex<'tcx>(
                     Scalar::from_target_isize(0, this), // retval_succ
                     Scalar::from_target_isize(-1, this), // retval_timeout
                     dest.clone(),
-                    this.eval_libc("ETIMEDOUT"),
+                    this.eval_libc("ETIMEDOUT"), // errno_timeout
                 );
             } else {
                 // The futex value doesn't match the expected value, so we return failure
                 // right away without sleeping: -1 and errno set to EAGAIN.
-                let eagain = this.eval_libc("EAGAIN");
-                this.set_last_error(eagain)?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
+                return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
             }
         }
         // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
@@ -180,9 +175,7 @@ pub fn futex<'tcx>(
                 u32::MAX
             };
             if bitset == 0 {
-                this.set_last_error(LibcError("EINVAL"))?;
-                this.write_scalar(Scalar::from_target_isize(-1, this), dest)?;
-                return interp_ok(());
+                return this.set_last_error_and_return(LibcError("EINVAL"), dest);
             }
             // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
             // will see the latest value on addr which could be changed by our caller
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index b199992245c..cd07bc9e013 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -181,6 +181,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     thread,
                     this.read_scalar(name)?,
                     this.eval_libc("MAXTHREADNAMESIZE").to_target_usize(this)?.try_into().unwrap(),
+                    /* truncate */ false,
                 )? {
                     Scalar::from_u32(0)
                 } else {
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 9273748ef3b..9371edfc83d 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -57,11 +57,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         // First, we do some basic argument validation as required by mmap
         if (flags & (map_private | map_shared)).count_ones() != 1 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
         if length == 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -103,11 +103,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
         let align = this.machine.page_align();
         let Some(map_length) = length.checked_next_multiple_of(this.machine.page_size) else {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         };
         if map_length > this.target_usize_max() {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
@@ -134,16 +134,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         // as a dealloc.
         #[allow(clippy::arithmetic_side_effects)] // PAGE_SIZE is nonzero
         if addr.addr().bytes() % this.machine.page_size != 0 {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         }
 
         let Some(length) = length.checked_next_multiple_of(this.machine.page_size) else {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
-            return interp_ok(Scalar::from_i32(-1));
+            return this.set_last_error_and_return_i32(LibcError("EINVAL"));
         };
         if length > this.target_usize_max() {
-            this.set_last_error(this.eval_libc("EINVAL"))?;
+            this.set_last_error(LibcError("EINVAL"))?;
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index 7f3d0f07bdc..c9c1b01b8b1 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -30,6 +30,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.read_scalar(thread)?,
                     this.read_scalar(name)?,
                     max_len,
+                    /* truncate */ false,
                 )?;
                 let res = if res { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") };
                 this.write_scalar(res, dest)?;
diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs
index 7f97afc8e4b..51256d800a4 100644
--- a/src/tools/miri/src/shims/unix/thread.rs
+++ b/src/tools/miri/src/shims/unix/thread.rs
@@ -64,23 +64,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     /// Set the name of the specified thread. If the name including the null terminator
-    /// is longer than `name_max_len`, then `false` is returned.
+    /// is longer or equals to `name_max_len`, then if `truncate` is set the truncated name
+    /// is used as the thread name, otherwise `false` is returned.
     fn pthread_setname_np(
         &mut self,
         thread: Scalar,
         name: Scalar,
         name_max_len: usize,
+        truncate: bool,
     ) -> InterpResult<'tcx, bool> {
         let this = self.eval_context_mut();
 
         let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?;
         let thread = ThreadId::try_from(thread).unwrap();
         let name = name.to_pointer(this)?;
-        let name = this.read_c_str(name)?.to_owned();
+        let mut name = this.read_c_str(name)?.to_owned();
 
         // Comparing with `>=` to account for null terminator.
         if name.len() >= name_max_len {
-            return interp_ok(false);
+            if truncate {
+                name.truncate(name_max_len.saturating_sub(1));
+            } else {
+                return interp_ok(false);
+            }
         }
 
         this.set_thread_name(thread, name);
diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs
index f8861085fe5..f7566a8112d 100644
--- a/src/tools/miri/src/shims/windows/sync.rs
+++ b/src/tools/miri/src/shims/windows/sync.rs
@@ -202,7 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 Scalar::from_i32(1), // retval_succ
                 Scalar::from_i32(0), // retval_timeout
                 dest.clone(),
-                this.eval_windows("c", "ERROR_TIMEOUT"),
+                this.eval_windows("c", "ERROR_TIMEOUT"), // errno_timeout
             );
         }
 
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 64bfc84ef20..0a5e9f62dd9 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -128,9 +128,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.158"
+version = "0.2.161"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
new file mode 100644
index 00000000000..4b731866aca
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.rs
@@ -0,0 +1,10 @@
+//! Ensure we report UB when the buffer is smaller than 16 bytes (even if the thread
+//! name would fit in the smaller buffer).
+//@only-target: android  # Miri supports prctl for Android only
+
+fn main() {
+    let mut buf = vec![0u8; 15];
+    unsafe {
+        libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>()); //~ ERROR: memory access failed: expected a pointer to 16 bytes of memory, but got alloc952 which is only 15 bytes from the end of the allocation
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
new file mode 100644
index 00000000000..275a38e593c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/prctl-get-name-buffer-too-small.stderr
@@ -0,0 +1,21 @@
+error: Undefined Behavior: memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+  --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   |
+LL |         libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr().cast::<libc::c_char>());
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 16 bytes of memory, but got ALLOC which is only 15 bytes from the end of the allocation
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   |
+LL |     let mut buf = vec![0u8; 15];
+   |                   ^^^^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at tests/fail-dep/libc/prctl-threadname.rs:LL:CC
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
index f4c009456d2..55491da9f60 100644
--- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs
@@ -1,7 +1,7 @@
 //! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some
 //! faulty logic around `release_clock` that led to this code not reporting a data race.
 //@ignore-target: windows # no libc socketpair on Windows
-//@compile-flags: -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0
 use std::thread;
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
index c2c6ce987e5..9b4890c7cc6 100644
--- a/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
+++ b/src/tools/miri/tests/fail/coroutine-pinned-moved.stderr
@@ -23,7 +23,7 @@ note: inside `<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-p
    |
 LL |         match me.resume(()) {
    |               ^^^^^^^^^^^^^
-   = note: inside `<std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC
+   = note: inside `std::boxed::iter::<impl std::iter::Iterator for std::boxed::Box<CoroutineIteratorAdapter<{static coroutine@tests/fail/coroutine-pinned-moved.rs:LL:CC}>>>::next` at RUSTLIB/alloc/src/boxed/iter.rs:LL:CC
 note: inside `main`
   --> tests/fail/coroutine-pinned-moved.rs:LL:CC
    |
diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
index d4479f32e56..c91f4ec158f 100644
--- a/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
+++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.rs
@@ -1,4 +1,3 @@
-
 // Ensure that a `ptr::without_provenance` ptr is truly invalid.
 fn main() {
     let x = 42;
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
new file mode 100644
index 00000000000..b69f7ee9dff
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.rs
@@ -0,0 +1,16 @@
+#![feature(explicit_tail_calls)]
+#![allow(incomplete_features)]
+
+fn g(x: *const i32) {
+    let _val = unsafe { *x }; //~ERROR: has been freed, so this pointer is dangling
+}
+
+fn f(_x: *const i32) {
+    let local = 0;
+    let ptr = &local as *const i32;
+    become g(ptr)
+}
+
+fn main() {
+    f(std::ptr::null());
+}
diff --git a/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
new file mode 100644
index 00000000000..6acd69ab3f8
--- /dev/null
+++ b/src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr
@@ -0,0 +1,30 @@
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     let _val = unsafe { *x };
+   |                         ^^ memory access failed: ALLOC has been freed, so this pointer is dangling
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     let local = 0;
+   |         ^^^^^
+help: ALLOC was deallocated here:
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL | }
+   | ^
+   = note: BACKTRACE (of the first span):
+   = note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+note: inside `main`
+  --> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
+   |
+LL |     f(std::ptr::null());
+   |     ^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
new file mode 100644
index 00000000000..87ae3753fea
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/prctl-threadname.rs
@@ -0,0 +1,74 @@
+//@only-target: android  # Miri supports prctl for Android only
+use std::ffi::{CStr, CString};
+use std::thread;
+
+// The Linux kernel all names 16 bytes long including the null terminator.
+const MAX_THREAD_NAME_LEN: usize = 16;
+
+fn main() {
+    // The short name should be shorter than 16 bytes which POSIX promises
+    // for thread names. The length includes a null terminator.
+    let short_name = "test_named".to_owned();
+    let long_name = std::iter::once("test_named_thread_truncation")
+        .chain(std::iter::repeat(" yada").take(100))
+        .collect::<String>();
+
+    fn set_thread_name(name: &CStr) -> i32 {
+        unsafe { libc::prctl(libc::PR_SET_NAME, name.as_ptr().cast::<libc::c_char>()) }
+    }
+
+    fn get_thread_name(name: &mut [u8]) -> i32 {
+        assert!(name.len() >= MAX_THREAD_NAME_LEN);
+        unsafe { libc::prctl(libc::PR_GET_NAME, name.as_mut_ptr().cast::<libc::c_char>()) }
+    }
+
+    // Set name via Rust API, get it via prctl.
+    let long_name2 = long_name.clone();
+    thread::Builder::new()
+        .name(long_name.clone())
+        .spawn(move || {
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+            assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via prctl and get it again (short name).
+    thread::Builder::new()
+        .spawn(move || {
+            // Set short thread name.
+            let cstr = CString::new(short_name.clone()).unwrap();
+            assert!(cstr.to_bytes_with_nul().len() <= MAX_THREAD_NAME_LEN); // this should fit
+            assert_eq!(set_thread_name(&cstr), 0);
+
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            assert_eq!(cstr.to_bytes(), short_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via prctl and get it again (long name).
+    thread::Builder::new()
+        .spawn(move || {
+            // Set full thread name.
+            let cstr = CString::new(long_name.clone()).unwrap();
+            assert!(cstr.to_bytes_with_nul().len() > MAX_THREAD_NAME_LEN);
+            // Names are truncated by the Linux kernel.
+            assert_eq!(set_thread_name(&cstr), 0);
+
+            let mut buf = vec![0u8; MAX_THREAD_NAME_LEN];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            assert_eq!(cstr.to_bytes(), &long_name.as_bytes()[..(MAX_THREAD_NAME_LEN - 1)]);
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index 404ef7cc42d..0e5b501bbcc 100644
--- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -1,4 +1,5 @@
 //@ignore-target: windows # No pthreads on Windows
+//@ignore-target: android # No pthread_{get,set}_name on Android
 use std::ffi::{CStr, CString};
 use std::thread;
 
@@ -65,6 +66,22 @@ fn main() {
         }
     }
 
+    // Set name via Rust API, get it via pthreads.
+    let long_name2 = long_name.clone();
+    thread::Builder::new()
+        .name(long_name.clone())
+        .spawn(move || {
+            let mut buf = vec![0u8; long_name2.len() + 1];
+            assert_eq!(get_thread_name(&mut buf), 0);
+            let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
+            let truncated_name = &long_name2[..long_name2.len().min(MAX_THREAD_NAME_LEN - 1)];
+            assert_eq!(cstr.to_bytes(), truncated_name.as_bytes());
+        })
+        .unwrap()
+        .join()
+        .unwrap();
+
+    // Set name via pthread and get it again (short name).
     thread::Builder::new()
         .spawn(move || {
             // Set short thread name.
@@ -130,6 +147,7 @@ fn main() {
         .join()
         .unwrap();
 
+    // Set name via pthread and get it again (long name).
     thread::Builder::new()
         .spawn(move || {
             // Set full thread name.
diff --git a/src/tools/miri/tests/pass/dyn-upcast.rs b/src/tools/miri/tests/pass/dyn-upcast.rs
index 306e9ab9c67..61410f7c4e0 100644
--- a/src/tools/miri/tests/pass/dyn-upcast.rs
+++ b/src/tools/miri/tests/pass/dyn-upcast.rs
@@ -433,7 +433,8 @@ fn replace_vptr() {
 }
 
 fn drop_principal() {
-    use std::{alloc::Layout, any::Any};
+    use std::alloc::Layout;
+    use std::any::Any;
 
     const fn yeet_principal(x: Box<dyn Any + Send>) -> Box<dyn Send> {
         x
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 853d3e80517..66843ca584b 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -157,13 +157,18 @@ fn basic() {
     assert_eq(-{ 5.0_f128 }, -5.0_f128);
 
     // infinities, NaN
-    // FIXME(f16_f128): add when constants and `is_infinite` are available
+    assert!((5.0_f16 / 0.0).is_infinite());
+    assert_ne!({ 5.0_f16 / 0.0 }, { -5.0_f16 / 0.0 });
     assert!((5.0_f32 / 0.0).is_infinite());
     assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 });
     assert!((5.0_f64 / 0.0).is_infinite());
     assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 });
+    assert!((5.0_f128 / 0.0).is_infinite());
+    assert_ne!({ 5.0_f128 / 0.0 }, { 5.0_f128 / -0.0 });
+    assert_ne!(f16::NAN, f16::NAN);
     assert_ne!(f32::NAN, f32::NAN);
     assert_ne!(f64::NAN, f64::NAN);
+    assert_ne!(f128::NAN, f128::NAN);
 
     // negative zero
     let posz = 0.0f16;
@@ -215,9 +220,14 @@ fn basic() {
     assert!((black_box(-1.0f128) % 1.0).is_sign_negative());
     assert!((black_box(-1.0f128) % -1.0).is_sign_negative());
 
-    // FIXME(f16_f128): add when `abs` is available
+    assert_eq!((-1.0f16).abs(), 1.0f16);
+    assert_eq!(34.2f16.abs(), 34.2f16);
     assert_eq!((-1.0f32).abs(), 1.0f32);
+    assert_eq!(34.2f32.abs(), 34.2f32);
+    assert_eq!((-1.0f64).abs(), 1.0f64);
     assert_eq!(34.2f64.abs(), 34.2f64);
+    assert_eq!((-1.0f128).abs(), 1.0f128);
+    assert_eq!(34.2f128.abs(), 34.2f128);
 }
 
 /// Test casts from floats to ints and back
@@ -654,6 +664,14 @@ fn casts() {
 }
 
 fn ops() {
+    // f16 min/max
+    assert_eq((1.0_f16).max(-1.0), 1.0);
+    assert_eq((1.0_f16).min(-1.0), -1.0);
+    assert_eq(f16::NAN.min(9.0), 9.0);
+    assert_eq(f16::NAN.max(-9.0), -9.0);
+    assert_eq((9.0_f16).min(f16::NAN), 9.0);
+    assert_eq((-9.0_f16).max(f16::NAN), -9.0);
+
     // f32 min/max
     assert_eq((1.0 as f32).max(-1.0), 1.0);
     assert_eq((1.0 as f32).min(-1.0), -1.0);
@@ -670,6 +688,21 @@ fn ops() {
     assert_eq((9.0 as f64).min(f64::NAN), 9.0);
     assert_eq((-9.0 as f64).max(f64::NAN), -9.0);
 
+    // f128 min/max
+    assert_eq((1.0_f128).max(-1.0), 1.0);
+    assert_eq((1.0_f128).min(-1.0), -1.0);
+    assert_eq(f128::NAN.min(9.0), 9.0);
+    assert_eq(f128::NAN.max(-9.0), -9.0);
+    assert_eq((9.0_f128).min(f128::NAN), 9.0);
+    assert_eq((-9.0_f128).max(f128::NAN), -9.0);
+
+    // f16 copysign
+    assert_eq(3.5_f16.copysign(0.42), 3.5_f16);
+    assert_eq(3.5_f16.copysign(-0.42), -3.5_f16);
+    assert_eq((-3.5_f16).copysign(0.42), 3.5_f16);
+    assert_eq((-3.5_f16).copysign(-0.42), -3.5_f16);
+    assert!(f16::NAN.copysign(1.0).is_nan());
+
     // f32 copysign
     assert_eq(3.5_f32.copysign(0.42), 3.5_f32);
     assert_eq(3.5_f32.copysign(-0.42), -3.5_f32);
@@ -683,6 +716,13 @@ fn ops() {
     assert_eq((-3.5_f64).copysign(0.42), 3.5_f64);
     assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64);
     assert!(f64::NAN.copysign(1.0).is_nan());
+
+    // f128 copysign
+    assert_eq(3.5_f128.copysign(0.42), 3.5_f128);
+    assert_eq(3.5_f128.copysign(-0.42), -3.5_f128);
+    assert_eq((-3.5_f128).copysign(0.42), 3.5_f128);
+    assert_eq((-3.5_f128).copysign(-0.42), -3.5_f128);
+    assert!(f128::NAN.copysign(1.0).is_nan());
 }
 
 /// Tests taken from rustc test suite.
@@ -807,6 +847,18 @@ fn nan_casts() {
 
 fn rounding() {
     // Test cases taken from the library's tests for this feature
+    // f16
+    assert_eq(2.5f16.round_ties_even(), 2.0f16);
+    assert_eq(1.0f16.round_ties_even(), 1.0f16);
+    assert_eq(1.3f16.round_ties_even(), 1.0f16);
+    assert_eq(1.5f16.round_ties_even(), 2.0f16);
+    assert_eq(1.7f16.round_ties_even(), 2.0f16);
+    assert_eq(0.0f16.round_ties_even(), 0.0f16);
+    assert_eq((-0.0f16).round_ties_even(), -0.0f16);
+    assert_eq((-1.0f16).round_ties_even(), -1.0f16);
+    assert_eq((-1.3f16).round_ties_even(), -1.0f16);
+    assert_eq((-1.5f16).round_ties_even(), -2.0f16);
+    assert_eq((-1.7f16).round_ties_even(), -2.0f16);
     // f32
     assert_eq(2.5f32.round_ties_even(), 2.0f32);
     assert_eq(1.0f32.round_ties_even(), 1.0f32);
@@ -831,23 +883,59 @@ fn rounding() {
     assert_eq((-1.3f64).round_ties_even(), -1.0f64);
     assert_eq((-1.5f64).round_ties_even(), -2.0f64);
     assert_eq((-1.7f64).round_ties_even(), -2.0f64);
-
+    // f128
+    assert_eq(2.5f128.round_ties_even(), 2.0f128);
+    assert_eq(1.0f128.round_ties_even(), 1.0f128);
+    assert_eq(1.3f128.round_ties_even(), 1.0f128);
+    assert_eq(1.5f128.round_ties_even(), 2.0f128);
+    assert_eq(1.7f128.round_ties_even(), 2.0f128);
+    assert_eq(0.0f128.round_ties_even(), 0.0f128);
+    assert_eq((-0.0f128).round_ties_even(), -0.0f128);
+    assert_eq((-1.0f128).round_ties_even(), -1.0f128);
+    assert_eq((-1.3f128).round_ties_even(), -1.0f128);
+    assert_eq((-1.5f128).round_ties_even(), -2.0f128);
+    assert_eq((-1.7f128).round_ties_even(), -2.0f128);
+
+    assert_eq!(3.8f16.floor(), 3.0f16);
+    assert_eq!((-1.1f16).floor(), -2.0f16);
     assert_eq!(3.8f32.floor(), 3.0f32);
+    assert_eq!((-1.1f32).floor(), -2.0f32);
+    assert_eq!(3.8f64.floor(), 3.0f64);
     assert_eq!((-1.1f64).floor(), -2.0f64);
+    assert_eq!(3.8f128.floor(), 3.0f128);
+    assert_eq!((-1.1f128).floor(), -2.0f128);
 
+    assert_eq!(3.8f16.ceil(), 4.0f16);
+    assert_eq!((-2.3f16).ceil(), -2.0f16);
+    assert_eq!(3.8f32.ceil(), 4.0f32);
     assert_eq!((-2.3f32).ceil(), -2.0f32);
     assert_eq!(3.8f64.ceil(), 4.0f64);
+    assert_eq!((-2.3f64).ceil(), -2.0f64);
+    assert_eq!(3.8f128.ceil(), 4.0f128);
+    assert_eq!((-2.3f128).ceil(), -2.0f128);
 
+    assert_eq!(0.1f16.trunc(), 0.0f16);
+    assert_eq!((-0.1f16).trunc(), 0.0f16);
     assert_eq!(0.1f32.trunc(), 0.0f32);
+    assert_eq!((-0.1f32).trunc(), 0.0f32);
+    assert_eq!(0.1f64.trunc(), 0.0f64);
     assert_eq!((-0.1f64).trunc(), 0.0f64);
+    assert_eq!(0.1f128.trunc(), 0.0f128);
+    assert_eq!((-0.1f128).trunc(), 0.0f128);
 
+    assert_eq!(3.3_f16.round(), 3.0);
+    assert_eq!(2.5_f16.round(), 3.0);
     assert_eq!(3.3_f32.round(), 3.0);
     assert_eq!(2.5_f32.round(), 3.0);
     assert_eq!(3.9_f64.round(), 4.0);
     assert_eq!(2.5_f64.round(), 3.0);
+    assert_eq!(3.9_f128.round(), 4.0);
+    assert_eq!(2.5_f128.round(), 3.0);
 }
 
 fn mul_add() {
+    // FIXME(f16_f128): add when supported
+
     assert_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0);
     assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E);
     assert_eq!(3.0f64.mul_add(2.0, 5.0), 11.0);
@@ -983,7 +1071,7 @@ fn test_fast() {
     use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast};
 
     #[inline(never)]
-    pub fn test_operations_f64(a: f64, b: f64) {
+    pub fn test_operations_f16(a: f16, b: f16) {
         // make sure they all map to the correct operation
         unsafe {
             assert_eq!(fadd_fast(a, b), a + b);
@@ -1006,10 +1094,38 @@ fn test_fast() {
         }
     }
 
-    test_operations_f64(1., 2.);
-    test_operations_f64(10., 5.);
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f128(a: f128, b: f128) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    test_operations_f16(11., 2.);
+    test_operations_f16(10., 15.);
     test_operations_f32(11., 2.);
     test_operations_f32(10., 15.);
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f128(1., 2.);
+    test_operations_f128(10., 5.);
 }
 
 fn test_algebraic() {
@@ -1018,7 +1134,7 @@ fn test_algebraic() {
     };
 
     #[inline(never)]
-    pub fn test_operations_f64(a: f64, b: f64) {
+    pub fn test_operations_f16(a: f16, b: f16) {
         // make sure they all map to the correct operation
         assert_eq!(fadd_algebraic(a, b), a + b);
         assert_eq!(fsub_algebraic(a, b), a - b);
@@ -1037,15 +1153,41 @@ fn test_algebraic() {
         assert_eq!(frem_algebraic(a, b), a % b);
     }
 
-    test_operations_f64(1., 2.);
-    test_operations_f64(10., 5.);
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f128(a: f128, b: f128) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    test_operations_f16(11., 2.);
+    test_operations_f16(10., 15.);
     test_operations_f32(11., 2.);
     test_operations_f32(10., 15.);
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f128(1., 2.);
+    test_operations_f128(10., 5.);
 }
 
 fn test_fmuladd() {
     use std::intrinsics::{fmuladdf32, fmuladdf64};
 
+    // FIXME(f16_f128): add when supported
+
     #[inline(never)]
     pub fn test_operations_f32(a: f32, b: f32, c: f32) {
         assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c);
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index d3605cd3dce..3affa199fa5 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -13,3 +13,6 @@ gimli = "0.31.0"
 build_helper = { path = "../build_helper" }
 serde_json = "1.0"
 libc = "0.2"
+
+[lib]
+crate-type = ["lib", "dylib"]
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 5cf4a8fd439..d82e46016dc 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -1,14 +1,10 @@
-# Please make sure that the `needs` fields for both `end-success` and `end-failure`
+# Please make sure that the `needs` field for the `conclusion` job
 # are updated when adding new jobs!
 
 name: CI
 on:
   pull_request:
-  push:
-    branches:
-      - auto
-      - try
-      - automation/bors/try
+  merge_group:
 
 env:
   CARGO_INCREMENTAL: 0
@@ -237,20 +233,21 @@ jobs:
       - name: check for typos
         run: typos
 
-  end-success:
-    name: bors build finished
-    if: github.event.pusher.name == 'bors' && success()
-    runs-on: ubuntu-latest
+  conclusion:
     needs: [rust, rust-cross, typescript, typo-check]
-    steps:
-      - name: Mark the job as successful
-        run: exit 0
-
-  end-failure:
-    name: bors build finished
-    if: github.event.pusher.name == 'bors' && !success()
+    # We need to ensure this job does *not* get skipped if its dependencies fail,
+    # because a skipped job is considered a success by GitHub. So we have to
+    # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+    # when the workflow is canceled manually.
+    #
+    # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+    if: ${{ !cancelled() }}
     runs-on: ubuntu-latest
-    needs: [rust, rust-cross, typescript, typo-check]
     steps:
-      - name: Mark the job as a failure
-        run: exit 1
+      # Manually check the status of all dependencies. `if: failure()` does not work.
+      - name: Conclusion
+        run: |
+          # Print the dependent jobs to see them in the CI log
+          jq -C <<< '${{ toJson(needs) }}'
+          # Check if all jobs that we depend on (in the needs array) were successful.
+          jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore
index 68c87a6b1ed..c4470a45078 100644
--- a/src/tools/rust-analyzer/.gitignore
+++ b/src/tools/rust-analyzer/.gitignore
@@ -1,6 +1,5 @@
-/target/
+target/
 /dist/
-crates/*/target
 **/*.rs.bk
 **/*.rs.pending-snap
 .idea/*
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index fd569571b38..695c37f6d7b 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -164,6 +164,7 @@ dependencies = [
  "rustc-hash 2.0.0",
  "syntax",
  "syntax-bridge",
+ "tracing",
  "tt",
 ]
 
@@ -556,6 +557,7 @@ dependencies = [
  "syntax-bridge",
  "test-fixture",
  "test-utils",
+ "text-size",
  "tracing",
  "triomphe",
  "tt",
@@ -670,7 +672,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "toolchain",
  "tracing",
  "triomphe",
@@ -692,7 +693,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -711,7 +711,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -743,7 +742,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
  "triomphe",
 ]
@@ -765,7 +763,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "tracing",
 ]
 
@@ -784,7 +781,6 @@ dependencies = [
  "syntax",
  "test-fixture",
  "test-utils",
- "text-edit",
  "triomphe",
 ]
 
@@ -1497,9 +1493,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "879ece0781e3c1cb670b9f29775c81a43a16db789d1296fad6bc5c74065b2fac"
+checksum = "d5bc2cfc7264d84215a08875ef90a1d35f76b5c9ad1993515d2da7e4e40b2b4b"
 dependencies = [
  "bitflags 2.6.0",
  "ra-ap-rustc_index",
@@ -1508,9 +1504,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6910087ff89bb9f3db114bfcd86b5139042731fe7278d3ff4ceaa69a140154a7"
+checksum = "e8929140697812e5dd09e19cf446d85146332363f0dbc125d4214834c34ead96"
 dependencies = [
  "arrayvec",
  "ra-ap-rustc_index_macros",
@@ -1519,9 +1515,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b6f7bd12b678fbb37444ba77f3b0cfc13b7394a6dc7b0c799491fc9df0a9997"
+checksum = "514a3f5d04c8b4a2750f29746cc9abb1f78deb7e72e4ad1dc95bbc608f3db157"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1530,9 +1526,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "119bc05b5b6bc3e7f5b67ce8b8080e185da94bd83c447f91b6b3f3ecf60cbab1"
+checksum = "276fcb1205da071a0cd64416f3f0e198043c11f176c5b501a45dbf0cb33979f2"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1540,9 +1536,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70ed6150ae71d905c064dc88d7824ebb0fa81083f45d7477cba7b57176f2f635"
+checksum = "961b30b22cfac296b14b72e9f95e79c16cebc8c926872755fb1568a6c4243a62"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1550,9 +1546,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.73.0"
+version = "0.75.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e830862a0ec85fce211d34735315686bb8d6a12d418d6d735fb534aa1cd3293"
+checksum = "614232513814a4b714fea7f11345d31c0c277bca3089bb6ca1ec20870bfc022a"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
@@ -1884,9 +1880,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "smol_str"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66eaf762c5af19db3108300515c8aa7a50efc90ff745f4c62288052ebf9fdd25"
+checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d"
 dependencies = [
  "borsh",
  "serde",
@@ -1978,7 +1974,6 @@ dependencies = [
  "smol_str",
  "stdx",
  "test-utils",
- "text-edit",
  "tracing",
  "triomphe",
 ]
@@ -2027,14 +2022,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "text-edit"
-version = "0.0.0"
-dependencies = [
- "itertools",
- "text-size",
-]
-
-[[package]]
 name = "text-size"
 version = "1.1.1"
 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 9db62de9abf..3aa93b7b7b4 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.81"
+rust-version = "1.82"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
@@ -79,17 +79,16 @@ span = { path = "./crates/span", version = "0.0.0" }
 stdx = { path = "./crates/stdx", version = "0.0.0" }
 syntax = { path = "./crates/syntax", version = "0.0.0" }
 syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" }
-text-edit = { path = "./crates/text-edit", version = "0.0.0" }
 toolchain = { path = "./crates/toolchain", version = "0.0.0" }
 tt = { path = "./crates/tt", version = "0.0.0" }
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.73", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.73", default-features = false }
-ra-ap-rustc_index = { version = "0.73", default-features = false }
-ra-ap-rustc_abi = { version = "0.73", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.73", default-features = false }
+ra-ap-rustc_lexer = { version = "0.75", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.75", default-features = false }
+ra-ap-rustc_index = { version = "0.75", default-features = false }
+ra-ap-rustc_abi = { version = "0.75", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.75", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 test-fixture = { path = "./crates/test-fixture" }
@@ -145,7 +144,7 @@ smallvec = { version = "1.10.0", features = [
   "union",
   "const_generics",
 ] }
-smol_str = "0.3.1"
+smol_str = "0.3.2"
 snap = "1.1.0"
 text-size = "1.1.1"
 tracing = "0.1.40"
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index 29b7ad6f8fe..040bddbd7fd 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -14,6 +14,7 @@ doctest = false
 
 [dependencies]
 rustc-hash.workspace = true
+tracing.workspace = true
 
 # locals deps
 tt = { workspace = true, optional = true }
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index c2d40086056..6a6213a871f 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -9,7 +9,7 @@ use std::fmt;
 
 use rustc_hash::FxHashSet;
 
-use intern::Symbol;
+use intern::{sym, Symbol};
 
 pub use cfg_expr::{CfgAtom, CfgExpr};
 pub use dnf::DnfExpr;
@@ -24,11 +24,17 @@ pub use dnf::DnfExpr;
 /// of key and value in `key_values`.
 ///
 /// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options>
-#[derive(Clone, PartialEq, Eq, Default)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct CfgOptions {
     enabled: FxHashSet<CfgAtom>,
 }
 
+impl Default for CfgOptions {
+    fn default() -> Self {
+        Self { enabled: FxHashSet::from_iter([CfgAtom::Flag(sym::true_.clone())]) }
+    }
+}
+
 impl fmt::Debug for CfgOptions {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut items = self
@@ -54,23 +60,37 @@ impl CfgOptions {
     }
 
     pub fn insert_atom(&mut self, key: Symbol) {
-        self.enabled.insert(CfgAtom::Flag(key));
+        self.insert_any_atom(CfgAtom::Flag(key));
     }
 
     pub fn insert_key_value(&mut self, key: Symbol, value: Symbol) {
-        self.enabled.insert(CfgAtom::KeyValue { key, value });
+        self.insert_any_atom(CfgAtom::KeyValue { key, value });
     }
 
     pub fn apply_diff(&mut self, diff: CfgDiff) {
         for atom in diff.enable {
-            self.enabled.insert(atom);
+            self.insert_any_atom(atom);
         }
 
         for atom in diff.disable {
+            let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+            if *sym == sym::true_ || *sym == sym::false_ {
+                tracing::error!("cannot remove `true` or `false` from cfg");
+                continue;
+            }
             self.enabled.remove(&atom);
         }
     }
 
+    fn insert_any_atom(&mut self, atom: CfgAtom) {
+        let (CfgAtom::Flag(sym) | CfgAtom::KeyValue { key: sym, .. }) = &atom;
+        if *sym == sym::true_ || *sym == sym::false_ {
+            tracing::error!("cannot insert `true` or `false` to cfg");
+            return;
+        }
+        self.enabled.insert(atom);
+    }
+
     pub fn get_cfg_keys(&self) -> impl Iterator<Item = &Symbol> {
         self.enabled.iter().map(|it| match it {
             CfgAtom::Flag(key) => key,
@@ -88,7 +108,7 @@ impl CfgOptions {
 
 impl Extend<CfgAtom> for CfgOptions {
     fn extend<T: IntoIterator<Item = CfgAtom>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|cfg_flag| _ = self.enabled.insert(cfg_flag));
+        iter.into_iter().for_each(|cfg_flag| self.insert_any_atom(cfg_flag));
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index c8ba5da449e..375f18d9fe1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -29,6 +29,7 @@ smallvec.workspace = true
 hashbrown.workspace = true
 triomphe.workspace = true
 rustc_apfloat = "0.2.0"
+text-size.workspace = true
 
 ra-ap-rustc_parse_format.workspace = true
 ra-ap-rustc_abi.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index 9535b5aea7c..5a386f6cf8d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -10,6 +10,7 @@ use std::ops::{Deref, Index};
 
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
+use either::Either;
 use hir_expand::{name::Name, ExpandError, InFile};
 use la_arena::{Arena, ArenaMap, Idx, RawIdx};
 use rustc_hash::FxHashMap;
@@ -22,15 +23,33 @@ use crate::{
     db::DefDatabase,
     expander::Expander,
     hir::{
-        dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
+        dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
+        LabelId, Pat, PatId, RecordFieldPat, Statement,
     },
     item_tree::AttrOwner,
     nameres::DefMap,
     path::{ModPath, Path},
     src::HasSource,
+    type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
     BlockId, DefWithBodyId, HasModule, Lookup,
 };
 
+/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct HygieneId(pub(crate) span::SyntaxContextId);
+
+impl HygieneId {
+    pub const ROOT: Self = Self(span::SyntaxContextId::ROOT);
+
+    pub fn new(ctx: span::SyntaxContextId) -> Self {
+        Self(ctx)
+    }
+
+    pub(crate) fn is_root(self) -> bool {
+        self.0.is_root()
+    }
+}
+
 /// The body of an item (function, const etc.).
 #[derive(Debug, Eq, PartialEq)]
 pub struct Body {
@@ -51,8 +70,25 @@ pub struct Body {
     pub self_param: Option<BindingId>,
     /// The `ExprId` of the actual body expression.
     pub body_expr: ExprId,
+    pub types: TypesMap,
     /// Block expressions in this body that may contain inner items.
     block_scopes: Vec<BlockId>,
+
+    /// A map from binding to its hygiene ID.
+    ///
+    /// Bindings that don't come from macro expansion are not allocated to save space, so not all bindings appear here.
+    /// If a binding does not appear here it has `SyntaxContextId::ROOT`.
+    ///
+    /// Note that this may not be the direct `SyntaxContextId` of the binding's expansion, because transparent
+    /// expansions are attributed to their parent expansion (recursively).
+    binding_hygiene: FxHashMap<BindingId, HygieneId>,
+    /// A map from an variable usages to their hygiene ID.
+    ///
+    /// Expressions that can be recorded here are single segment path, although not all single segments path refer
+    /// to variables and have hygiene (some refer to items, we don't know at this stage).
+    expr_hygiene: FxHashMap<ExprId, HygieneId>,
+    /// A map from a destructuring assignment possible variable usages to their hygiene ID.
+    pat_hygiene: FxHashMap<PatId, HygieneId>,
 }
 
 pub type ExprPtr = AstPtr<ast::Expr>;
@@ -67,9 +103,12 @@ pub type LabelSource = InFile<LabelPtr>;
 pub type FieldPtr = AstPtr<ast::RecordExprField>;
 pub type FieldSource = InFile<FieldPtr>;
 
-pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
+pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
 pub type PatFieldSource = InFile<PatFieldPtr>;
 
+pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
+pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
+
 /// An item body together with the mapping from syntax nodes to HIR expression
 /// IDs. This is needed to go from e.g. a position in a file to the HIR
 /// expression containing it; but for type inference etc., we want to operate on
@@ -83,11 +122,13 @@ pub type PatFieldSource = InFile<PatFieldPtr>;
 /// this properly for macros.
 #[derive(Default, Debug, Eq, PartialEq)]
 pub struct BodySourceMap {
-    expr_map: FxHashMap<ExprSource, ExprId>,
+    // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
+    // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
+    expr_map: FxHashMap<ExprSource, ExprOrPatId>,
     expr_map_back: ArenaMap<ExprId, ExprSource>,
 
     pat_map: FxHashMap<PatSource, PatId>,
-    pat_map_back: ArenaMap<PatId, PatSource>,
+    pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
 
     label_map: FxHashMap<LabelSource, LabelId>,
     label_map_back: ArenaMap<LabelId, LabelSource>,
@@ -100,10 +141,13 @@ pub struct BodySourceMap {
     field_map_back: FxHashMap<ExprId, FieldSource>,
     pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
 
+    types: TypesSourceMap,
+
+    // FIXME: Make this a sane struct.
     template_map: Option<
         Box<(
             // format_args!
-            FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
+            FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
             // asm!
             FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
         )>,
@@ -261,6 +305,10 @@ impl Body {
             pats,
             bindings,
             binding_owners,
+            binding_hygiene,
+            expr_hygiene,
+            pat_hygiene,
+            types,
         } = self;
         block_scopes.shrink_to_fit();
         exprs.shrink_to_fit();
@@ -268,6 +316,10 @@ impl Body {
         pats.shrink_to_fit();
         bindings.shrink_to_fit();
         binding_owners.shrink_to_fit();
+        binding_hygiene.shrink_to_fit();
+        expr_hygiene.shrink_to_fit();
+        pat_hygiene.shrink_to_fit();
+        types.shrink_to_fit();
     }
 
     pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -286,7 +338,8 @@ impl Body {
             | Pat::Path(..)
             | Pat::ConstBlock(..)
             | Pat::Wild
-            | Pat::Missing => {}
+            | Pat::Missing
+            | Pat::Expr(_) => {}
             &Pat::Bind { subpat, .. } => {
                 if let Some(subpat) = subpat {
                     f(subpat);
@@ -322,6 +375,162 @@ impl Body {
             None => true,
         }
     }
+
+    pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
+        let expr = &self[expr_id];
+        match expr {
+            Expr::Continue { .. }
+            | Expr::Const(_)
+            | Expr::Missing
+            | Expr::Path(_)
+            | Expr::OffsetOf(_)
+            | Expr::Literal(_)
+            | Expr::Underscore => {}
+            Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
+                AsmOperand::In { expr, .. }
+                | AsmOperand::Out { expr: Some(expr), .. }
+                | AsmOperand::InOut { expr, .. } => f(*expr),
+                AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+                    f(*in_expr);
+                    if let Some(out_expr) = out_expr {
+                        f(*out_expr);
+                    }
+                }
+                AsmOperand::Out { expr: None, .. }
+                | AsmOperand::Const(_)
+                | AsmOperand::Label(_)
+                | AsmOperand::Sym(_) => (),
+            }),
+            Expr::If { condition, then_branch, else_branch } => {
+                f(*condition);
+                f(*then_branch);
+                if let &Some(else_branch) = else_branch {
+                    f(else_branch);
+                }
+            }
+            Expr::Let { expr, .. } => {
+                f(*expr);
+            }
+            Expr::Block { statements, tail, .. }
+            | Expr::Unsafe { statements, tail, .. }
+            | Expr::Async { statements, tail, .. } => {
+                for stmt in statements.iter() {
+                    match stmt {
+                        Statement::Let { initializer, else_branch, pat, .. } => {
+                            if let &Some(expr) = initializer {
+                                f(expr);
+                            }
+                            if let &Some(expr) = else_branch {
+                                f(expr);
+                            }
+                            self.walk_exprs_in_pat(*pat, &mut f);
+                        }
+                        Statement::Expr { expr: expression, .. } => f(*expression),
+                        Statement::Item(_) => (),
+                    }
+                }
+                if let &Some(expr) = tail {
+                    f(expr);
+                }
+            }
+            Expr::Loop { body, .. } => f(*body),
+            Expr::Call { callee, args, .. } => {
+                f(*callee);
+                args.iter().copied().for_each(f);
+            }
+            Expr::MethodCall { receiver, args, .. } => {
+                f(*receiver);
+                args.iter().copied().for_each(f);
+            }
+            Expr::Match { expr, arms } => {
+                f(*expr);
+                arms.iter().map(|arm| arm.expr).for_each(f);
+            }
+            Expr::Break { expr, .. }
+            | Expr::Return { expr }
+            | Expr::Yield { expr }
+            | Expr::Yeet { expr } => {
+                if let &Some(expr) = expr {
+                    f(expr);
+                }
+            }
+            Expr::Become { expr } => f(*expr),
+            Expr::RecordLit { fields, spread, .. } => {
+                for field in fields.iter() {
+                    f(field.expr);
+                }
+                if let &Some(expr) = spread {
+                    f(expr);
+                }
+            }
+            Expr::Closure { body, .. } => {
+                f(*body);
+            }
+            Expr::BinaryOp { lhs, rhs, .. } => {
+                f(*lhs);
+                f(*rhs);
+            }
+            Expr::Range { lhs, rhs, .. } => {
+                if let &Some(lhs) = rhs {
+                    f(lhs);
+                }
+                if let &Some(rhs) = lhs {
+                    f(rhs);
+                }
+            }
+            Expr::Index { base, index, .. } => {
+                f(*base);
+                f(*index);
+            }
+            Expr::Field { expr, .. }
+            | Expr::Await { expr }
+            | Expr::Cast { expr, .. }
+            | Expr::Ref { expr, .. }
+            | Expr::UnaryOp { expr, .. }
+            | Expr::Box { expr } => {
+                f(*expr);
+            }
+            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
+            Expr::Array(a) => match a {
+                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
+                Array::Repeat { initializer, repeat } => {
+                    f(*initializer);
+                    f(*repeat)
+                }
+            },
+            &Expr::Assignment { target, value } => {
+                self.walk_exprs_in_pat(target, &mut f);
+                f(value);
+            }
+        }
+    }
+
+    pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
+        self.walk_pats(pat_id, &mut |pat| {
+            if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
+                f(expr);
+            }
+        });
+    }
+
+    fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
+        self.binding_hygiene.get(&binding).copied().unwrap_or(HygieneId::ROOT)
+    }
+
+    pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
+        self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
+    }
+
+    pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
+        self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
+    }
+
+    pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
+        match id {
+            ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
+            ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
+        }
+    }
 }
 
 impl Default for Body {
@@ -336,6 +545,10 @@ impl Default for Body {
             block_scopes: Default::default(),
             binding_owners: Default::default(),
             self_param: Default::default(),
+            binding_hygiene: Default::default(),
+            expr_hygiene: Default::default(),
+            pat_hygiene: Default::default(),
+            types: Default::default(),
         }
     }
 }
@@ -372,14 +585,29 @@ impl Index<BindingId> for Body {
     }
 }
 
+impl Index<TypeRefId> for Body {
+    type Output = TypeRef;
+
+    fn index(&self, b: TypeRefId) -> &TypeRef {
+        &self.types[b]
+    }
+}
+
 // FIXME: Change `node_` prefix to something more reasonable.
 // Perhaps `expr_syntax` and `expr_id`?
 impl BodySourceMap {
+    pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
+        match id {
+            ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
+            ExprOrPatId::PatId(id) => self.pat_syntax(id),
+        }
+    }
+
     pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
         self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
     }
 
-    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
+    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
         let src = node.map(AstPtr::new);
         self.expr_map.get(&src).cloned()
     }
@@ -395,7 +623,7 @@ impl BodySourceMap {
         self.expansions.iter().map(|(&a, &b)| (a, b))
     }
 
-    pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
+    pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
         self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
 
@@ -428,7 +656,7 @@ impl BodySourceMap {
         self.pat_field_map_back[&pat]
     }
 
-    pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprId> {
+    pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
         self.expr_map.get(&src).copied()
     }
@@ -442,9 +670,11 @@ impl BodySourceMap {
     pub fn implicit_format_args(
         &self,
         node: InFile<&ast::FormatArgsExpr>,
-    ) -> Option<&[(syntax::TextRange, Name)]> {
+    ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
-        self.template_map.as_ref()?.0.get(self.expr_map.get(&src)?).map(std::ops::Deref::deref)
+        let (hygiene, names) =
+            self.template_map.as_ref()?.0.get(&self.expr_map.get(&src)?.as_expr()?)?;
+        Some((*hygiene, &**names))
     }
 
     pub fn asm_template_args(
@@ -452,8 +682,8 @@ impl BodySourceMap {
         node: InFile<&ast::AsmExpr>,
     ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
         let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
-        let expr = self.expr_map.get(&src)?;
-        Some(*expr).zip(self.template_map.as_ref()?.1.get(expr).map(std::ops::Deref::deref))
+        let expr = self.expr_map.get(&src)?.as_expr()?;
+        Some(expr).zip(self.template_map.as_ref()?.1.get(&expr).map(std::ops::Deref::deref))
     }
 
     /// Get a reference to the body source map's diagnostics.
@@ -476,6 +706,7 @@ impl BodySourceMap {
             template_map,
             diagnostics,
             binding_definitions,
+            types,
         } = self;
         if let Some(template_map) = template_map {
             template_map.0.shrink_to_fit();
@@ -492,14 +723,6 @@ impl BodySourceMap {
         expansions.shrink_to_fit();
         diagnostics.shrink_to_fit();
         binding_definitions.shrink_to_fit();
-    }
-
-    pub fn template_map(
-        &self,
-    ) -> Option<&(
-        FxHashMap<Idx<Expr>, Vec<(tt::TextRange, Name)>>,
-        FxHashMap<Idx<Expr>, Vec<Vec<(tt::TextRange, usize)>>>,
-    )> {
-        self.template_map.as_deref()
+        types.shrink_to_fit();
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 9c547574ecb..0b108b54e67 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -9,9 +9,10 @@ use base_db::CrateId;
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
-    InFile,
+    span_map::{ExpansionSpanMap, SpanMap},
+    InFile, MacroDefId,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
 use rustc_hash::FxHashMap;
 use span::AstIdMap;
 use stdx::never;
@@ -22,10 +23,11 @@ use syntax::{
     },
     AstNode, AstPtr, AstToken as _, SyntaxNodePtr,
 };
+use text_size::TextSize;
 use triomphe::Arc;
 
 use crate::{
-    body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
+    body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
     builtin_type::BuiltinUint,
     data::adt::StructKind,
     db::DefDatabase,
@@ -37,8 +39,8 @@ use crate::{
             FormatPlaceholder, FormatSign, FormatTrait,
         },
         Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
-        Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability, OffsetOf, Pat,
-        PatId, RecordFieldPat, RecordLitField, Statement,
+        Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
+        OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
     },
     item_scope::BuiltinShadowMode,
     lang_item::LangItem,
@@ -46,7 +48,7 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     path::{GenericArgs, Path},
     type_ref::{Mutability, Rawness, TypeRef},
-    AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
+    AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, MacroId, ModuleDefId, UnresolvedMacro,
 };
 
 type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
@@ -60,6 +62,17 @@ pub(super) fn lower(
     krate: CrateId,
     is_async_fn: bool,
 ) -> (Body, BodySourceMap) {
+    // We cannot leave the root span map empty and let any identifier from it be treated as root,
+    // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
+    // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
+    // even though they should be the same. Also, when the body comes from multiple expansions, their
+    // hygiene is different.
+    let span_map = expander.current_file_id().macro_file().map(|_| {
+        let SpanMap::ExpansionSpanMap(span_map) = expander.span_map(db) else {
+            panic!("in a macro file there should be `ExpansionSpanMap`");
+        };
+        Arc::clone(span_map)
+    });
     ExprCollector {
         db,
         owner,
@@ -70,11 +83,12 @@ pub(super) fn lower(
         body: Body::default(),
         expander,
         current_try_block_label: None,
-        is_lowering_assignee_expr: false,
         is_lowering_coroutine: false,
         label_ribs: Vec::new(),
         current_binding_owner: None,
         awaitable_context: None,
+        current_span_map: span_map,
+        current_block_legacy_macro_defs_count: FxHashMap::default(),
     }
     .collect(params, body, is_async_fn)
 }
@@ -89,9 +103,14 @@ struct ExprCollector<'a> {
     body: Body,
     source_map: BodySourceMap,
 
-    is_lowering_assignee_expr: bool,
     is_lowering_coroutine: bool,
 
+    /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
+    /// and we need to find the current definition. So we track the number of definitions we saw.
+    current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
+
+    current_span_map: Option<Arc<ExpansionSpanMap>>,
+
     current_try_block_label: Option<LabelId>,
     // points to the expression that a try expression will target (replaces current_try_block_label)
     // catch_scope: Option<ExprId>,
@@ -110,31 +129,27 @@ struct ExprCollector<'a> {
 #[derive(Clone, Debug)]
 struct LabelRib {
     kind: RibKind,
-    // Once we handle macro hygiene this will need to be a map
-    label: Option<(Name, LabelId)>,
 }
 
 impl LabelRib {
     fn new(kind: RibKind) -> Self {
-        LabelRib { kind, label: None }
-    }
-    fn new_normal(label: (Name, LabelId)) -> Self {
-        LabelRib { kind: RibKind::Normal, label: Some(label) }
+        LabelRib { kind }
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 enum RibKind {
-    Normal,
+    Normal(Name, LabelId, HygieneId),
     Closure,
     Constant,
+    MacroDef(Box<MacroDefId>),
 }
 
 impl RibKind {
     /// This rib forbids referring to labels defined in upwards ribs.
-    fn is_label_barrier(self) -> bool {
+    fn is_label_barrier(&self) -> bool {
         match self {
-            RibKind::Normal => false,
+            RibKind::Normal(..) | RibKind::MacroDef(_) => false,
             RibKind::Closure | RibKind::Constant => true,
         }
     }
@@ -147,7 +162,7 @@ enum Awaitable {
 
 #[derive(Debug, Default)]
 struct BindingList {
-    map: FxHashMap<Name, BindingId>,
+    map: FxHashMap<(Name, HygieneId), BindingId>,
     is_used: FxHashMap<BindingId, bool>,
     reject_new: bool,
 }
@@ -157,9 +172,16 @@ impl BindingList {
         &mut self,
         ec: &mut ExprCollector<'_>,
         name: Name,
+        hygiene: HygieneId,
         mode: BindingAnnotation,
     ) -> BindingId {
-        let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode));
+        let id = *self.map.entry((name, hygiene)).or_insert_with_key(|(name, _)| {
+            let id = ec.alloc_binding(name.clone(), mode);
+            if !hygiene.is_root() {
+                ec.body.binding_hygiene.insert(id, hygiene);
+            }
+            id
+        });
         if ec.body.bindings[id].mode != mode {
             ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
         }
@@ -213,6 +235,13 @@ impl ExprCollector<'_> {
                     Name::new_symbol_root(sym::self_.clone()),
                     BindingAnnotation::new(is_mutable, false),
                 );
+                let hygiene = self_param
+                    .name()
+                    .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+                    .unwrap_or(HygieneId::ROOT);
+                if !hygiene.is_root() {
+                    self.body.binding_hygiene.insert(binding_id, hygiene);
+                }
                 self.body.self_param = Some(binding_id);
                 self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
             }
@@ -245,8 +274,8 @@ impl ExprCollector<'_> {
         (self.body, self.source_map)
     }
 
-    fn ctx(&self) -> LowerCtx<'_> {
-        self.expander.ctx(self.db)
+    fn ctx(&mut self) -> LowerCtx<'_> {
+        self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
     }
 
     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -290,13 +319,14 @@ impl ExprCollector<'_> {
                     })
                 }
                 Some(ast::BlockModifier::Label(label)) => {
-                    let label = self.collect_label(label);
-                    self.with_labeled_rib(label, |this| {
+                    let label_hygiene = self.hygiene_id_for(label.syntax().text_range().start());
+                    let label_id = self.collect_label(label);
+                    self.with_labeled_rib(label_id, label_hygiene, |this| {
                         this.collect_block_(e, |id, statements, tail| Expr::Block {
                             id,
                             statements,
                             tail,
-                            label: Some(label),
+                            label: Some(label_id),
                         })
                     })
                 }
@@ -338,9 +368,14 @@ impl ExprCollector<'_> {
                 None => self.collect_block(e),
             },
             ast::Expr::LoopExpr(e) => {
-                let label = e.label().map(|label| self.collect_label(label));
+                let label = e.label().map(|label| {
+                    (
+                        self.hygiene_id_for(label.syntax().text_range().start()),
+                        self.collect_label(label),
+                    )
+                });
                 let body = self.collect_labelled_block_opt(label, e.loop_body());
-                self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
+                self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)
             }
             ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
             ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
@@ -359,14 +394,7 @@ impl ExprCollector<'_> {
                     } else {
                         Box::default()
                     };
-                    self.alloc_expr(
-                        Expr::Call {
-                            callee,
-                            args,
-                            is_assignee_expr: self.is_lowering_assignee_expr,
-                        },
-                        syntax_ptr,
-                    )
+                    self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
                 }
             }
             ast::Expr::MethodCallExpr(e) => {
@@ -407,12 +435,15 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
             }
             ast::Expr::PathExpr(e) => {
-                let path = e
-                    .path()
-                    .and_then(|path| self.expander.parse_path(self.db, path))
-                    .map(Expr::Path)
-                    .unwrap_or(Expr::Missing);
-                self.alloc_expr(path, syntax_ptr)
+                let (path, hygiene) = self
+                    .collect_expr_path(e)
+                    .map(|(path, hygiene)| (Expr::Path(path), hygiene))
+                    .unwrap_or((Expr::Missing, HygieneId::ROOT));
+                let expr_id = self.alloc_expr(path, syntax_ptr);
+                if !hygiene.is_root() {
+                    self.body.expr_hygiene.insert(expr_id, hygiene);
+                }
+                expr_id
             }
             ast::Expr::ContinueExpr(e) => {
                 let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
@@ -433,7 +464,7 @@ impl ExprCollector<'_> {
                 let inner = self.collect_expr_opt(e.expr());
                 // make the paren expr point to the inner expression as well for IDE resolution
                 let src = self.expander.in_file(syntax_ptr);
-                self.source_map.expr_map.insert(src, inner);
+                self.source_map.expr_map.insert(src, inner.into());
                 inner
             }
             ast::Expr::ReturnExpr(e) => {
@@ -455,9 +486,7 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
             }
             ast::Expr::RecordExpr(e) => {
-                let path =
-                    e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
-                let is_assignee_expr = self.is_lowering_assignee_expr;
+                let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
                     let fields = nfl
                         .fields()
@@ -476,16 +505,9 @@ impl ExprCollector<'_> {
                         })
                         .collect();
                     let spread = nfl.spread().map(|s| self.collect_expr(s));
-                    let ellipsis = nfl.dotdot_token().is_some();
-                    Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
+                    Expr::RecordLit { path, fields, spread }
                 } else {
-                    Expr::RecordLit {
-                        path,
-                        fields: Box::default(),
-                        spread: None,
-                        ellipsis: false,
-                        is_assignee_expr,
-                    }
+                    Expr::RecordLit { path, fields: Box::default(), spread: None }
                 };
 
                 self.alloc_expr(record_lit, syntax_ptr)
@@ -511,7 +533,7 @@ impl ExprCollector<'_> {
             ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
             ast::Expr::CastExpr(e) => {
                 let expr = self.collect_expr_opt(e.expr());
-                let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty());
                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
             }
             ast::Expr::RefExpr(e) => {
@@ -550,16 +572,13 @@ impl ExprCollector<'_> {
                     arg_types.reserve_exact(num_params);
                     for param in pl.params() {
                         let pat = this.collect_pat_top(param.pat());
-                        let type_ref =
-                            param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+                        let type_ref = param.ty().map(|it| TypeRef::from_ast(&this.ctx(), it));
                         args.push(pat);
                         arg_types.push(type_ref);
                     }
                 }
-                let ret_type = e
-                    .ret_type()
-                    .and_then(|r| r.ty())
-                    .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
+                let ret_type =
+                    e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&this.ctx(), it));
 
                 let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
                 let prev_try_block_label = this.current_try_block_label.take();
@@ -602,12 +621,14 @@ impl ExprCollector<'_> {
             ast::Expr::BinExpr(e) => {
                 let op = e.op_kind();
                 if let Some(ast::BinaryOp::Assignment { op: None }) = op {
-                    self.is_lowering_assignee_expr = true;
+                    let target = self.collect_expr_as_pat_opt(e.lhs());
+                    let value = self.collect_expr_opt(e.rhs());
+                    self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)
+                } else {
+                    let lhs = self.collect_expr_opt(e.lhs());
+                    let rhs = self.collect_expr_opt(e.rhs());
+                    self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
                 }
-                let lhs = self.collect_expr_opt(e.lhs());
-                self.is_lowering_assignee_expr = false;
-                let rhs = self.collect_expr_opt(e.rhs());
-                self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
             }
             ast::Expr::TupleExpr(e) => {
                 let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
@@ -617,13 +638,7 @@ impl ExprCollector<'_> {
                     exprs.insert(0, self.missing_expr());
                 }
 
-                self.alloc_expr(
-                    Expr::Tuple {
-                        exprs: exprs.into_boxed_slice(),
-                        is_assignee_expr: self.is_lowering_assignee_expr,
-                    },
-                    syntax_ptr,
-                )
+                self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)
             }
             ast::Expr::ArrayExpr(e) => {
                 let kind = e.kind();
@@ -631,13 +646,7 @@ impl ExprCollector<'_> {
                 match kind {
                     ArrayExprKind::ElementList(e) => {
                         let elements = e.map(|expr| self.collect_expr(expr)).collect();
-                        self.alloc_expr(
-                            Expr::Array(Array::ElementList {
-                                elements,
-                                is_assignee_expr: self.is_lowering_assignee_expr,
-                            }),
-                            syntax_ptr,
-                        )
+                        self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
                     }
                     ArrayExprKind::Repeat { initializer, repeat } => {
                         let initializer = self.collect_expr_opt(initializer);
@@ -664,8 +673,7 @@ impl ExprCollector<'_> {
             ast::Expr::IndexExpr(e) => {
                 let base = self.collect_expr_opt(e.base());
                 let index = self.collect_expr_opt(e.index());
-                let is_assignee_expr = self.is_lowering_assignee_expr;
-                self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr)
+                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
             }
             ast::Expr::RangeExpr(e) => {
                 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
@@ -688,7 +696,7 @@ impl ExprCollector<'_> {
                         // Make the macro-call point to its expanded expression so we can query
                         // semantics on syntax pointers to the macro
                         let src = self.expander.in_file(syntax_ptr);
-                        self.source_map.expr_map.insert(src, id);
+                        self.source_map.expr_map.insert(src, id.into());
                         id
                     }
                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
@@ -697,7 +705,7 @@ impl ExprCollector<'_> {
             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
             ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
             ast::Expr::OffsetOfExpr(e) => {
-                let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
+                let container = TypeRef::from_ast_opt(&self.ctx(), e.ty());
                 let fields = e.fields().map(|it| it.as_name()).collect();
                 self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
             }
@@ -705,6 +713,200 @@ impl ExprCollector<'_> {
         })
     }
 
+    fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
+        self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
+    }
+
+    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
+        e.path().and_then(|path| {
+            let path = self.parse_path(path)?;
+            // Need to enable `mod_path.len() < 1` for `self`.
+            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
+            let hygiene = if may_be_variable {
+                self.hygiene_id_for(e.syntax().text_range().start())
+            } else {
+                HygieneId::ROOT
+            };
+            Some((path, hygiene))
+        })
+    }
+
+    fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {
+        match expr {
+            Some(expr) => self.collect_expr_as_pat(expr),
+            _ => self.missing_pat(),
+        }
+    }
+
+    fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
+        self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
+            let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
+            let expr = self.collect_expr(expr);
+            // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
+            let id = self.body.pats.alloc(Pat::Expr(expr));
+            self.source_map.pat_map_back.insert(id, src);
+            id
+        })
+    }
+
+    fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {
+        self.check_cfg(expr)?;
+        let syntax_ptr = AstPtr::new(expr);
+
+        let result = match expr {
+            ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
+            ast::Expr::ParenExpr(e) => {
+                // We special-case `(..)` for consistency with patterns.
+                if let Some(ast::Expr::RangeExpr(range)) = e.expr() {
+                    if range.is_range_full() {
+                        return Some(self.alloc_pat_from_expr(
+                            Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
+                            syntax_ptr,
+                        ));
+                    }
+                }
+                return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
+            }
+            ast::Expr::TupleExpr(e) => {
+                let (ellipsis, args) = collect_tuple(self, e.fields());
+                self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)
+            }
+            ast::Expr::ArrayExpr(e) => {
+                if e.semicolon_token().is_some() {
+                    return None;
+                }
+
+                let mut elements = e.exprs();
+                let prefix = elements
+                    .by_ref()
+                    .map_while(|elem| collect_possibly_rest(self, elem).left())
+                    .collect();
+                let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();
+                self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)
+            }
+            ast::Expr::CallExpr(e) => {
+                let path = collect_path(self, e.expr()?)?;
+                let path = path.path().and_then(|path| self.parse_path(path)).map(Box::new);
+                let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
+                self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
+            }
+            ast::Expr::PathExpr(e) => {
+                let (path, hygiene) = self
+                    .collect_expr_path(e.clone())
+                    .map(|(path, hygiene)| (Pat::Path(path), hygiene))
+                    .unwrap_or((Pat::Missing, HygieneId::ROOT));
+                let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
+                if !hygiene.is_root() {
+                    self.body.pat_hygiene.insert(pat_id, hygiene);
+                }
+                pat_id
+            }
+            ast::Expr::MacroExpr(e) => {
+                let e = e.macro_call()?;
+                let macro_ptr = AstPtr::new(&e);
+                let src = self.expander.in_file(AstPtr::new(expr));
+                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
+                    this.collect_expr_as_pat_opt(expansion)
+                });
+                self.source_map.expr_map.insert(src, id.into());
+                id
+            }
+            ast::Expr::RecordExpr(e) => {
+                let path = e.path().and_then(|path| self.parse_path(path)).map(Box::new);
+                let record_field_list = e.record_expr_field_list()?;
+                let ellipsis = record_field_list.dotdot_token().is_some();
+                // FIXME: Report an error here if `record_field_list.spread().is_some()`.
+                let args = record_field_list
+                    .fields()
+                    .filter_map(|f| {
+                        self.check_cfg(&f)?;
+                        let field_expr = f.expr()?;
+                        let pat = self.collect_expr_as_pat(field_expr);
+                        let name = f.field_name()?.as_name();
+                        let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
+                        self.source_map.pat_field_map_back.insert(pat, src);
+                        Some(RecordFieldPat { name, pat })
+                    })
+                    .collect();
+                self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)
+            }
+            _ => return None,
+        };
+        return Some(result);
+
+        fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {
+            match expr {
+                ast::Expr::PathExpr(e) => Some(e),
+                ast::Expr::MacroExpr(mac) => {
+                    let call = mac.macro_call()?;
+                    {
+                        let macro_ptr = AstPtr::new(&call);
+                        this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {
+                            collect_path(this, expanded_path?)
+                        })
+                    }
+                }
+                _ => None,
+            }
+        }
+
+        fn collect_possibly_rest(
+            this: &mut ExprCollector<'_>,
+            expr: ast::Expr,
+        ) -> Either<PatId, ()> {
+            match &expr {
+                ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),
+                ast::Expr::MacroExpr(mac) => match mac.macro_call() {
+                    Some(call) => {
+                        let macro_ptr = AstPtr::new(&call);
+                        let pat = this.collect_macro_call(
+                            call,
+                            macro_ptr,
+                            true,
+                            |this, expanded_expr| match expanded_expr {
+                                Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),
+                                None => Either::Left(this.missing_pat()),
+                            },
+                        );
+                        if let Either::Left(pat) = pat {
+                            let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
+                            this.source_map.pat_map_back.insert(pat, src);
+                        }
+                        pat
+                    }
+                    None => {
+                        let ptr = AstPtr::new(&expr);
+                        Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))
+                    }
+                },
+                _ => Either::Left(this.collect_expr_as_pat(expr)),
+            }
+        }
+
+        fn collect_tuple(
+            this: &mut ExprCollector<'_>,
+            fields: ast::AstChildren<ast::Expr>,
+        ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {
+            let mut ellipsis = None;
+            let args = fields
+                .enumerate()
+                .filter_map(|(idx, elem)| {
+                    match collect_possibly_rest(this, elem) {
+                        Either::Left(pat) => Some(pat),
+                        Either::Right(()) => {
+                            if ellipsis.is_none() {
+                                ellipsis = Some(idx as u32);
+                            }
+                            // FIXME: Report an error here otherwise.
+                            None
+                        }
+                    }
+                })
+                .collect();
+            (ellipsis, args)
+        }
+    }
+
     fn initialize_binding_owner(
         &mut self,
         syntax_ptr: AstPtr<ast::Expr>,
@@ -744,7 +946,7 @@ impl ExprCollector<'_> {
         let old_label = self.current_try_block_label.replace(label);
 
         let ptr = AstPtr::new(&e).upcast();
-        let (btail, expr_id) = self.with_labeled_rib(label, |this| {
+        let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
             let mut btail = None;
             let block = this.collect_block_(e, |id, statements, tail| {
                 btail = tail;
@@ -755,17 +957,13 @@ impl ExprCollector<'_> {
 
         let callee = self.alloc_expr_desugared_with_ptr(Expr::Path(try_from_output), ptr);
         let next_tail = match btail {
-            Some(tail) => self.alloc_expr_desugared_with_ptr(
-                Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false },
-                ptr,
-            ),
+            Some(tail) => self
+                .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),
             None => {
-                let unit = self.alloc_expr_desugared_with_ptr(
-                    Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false },
-                    ptr,
-                );
+                let unit =
+                    self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);
                 self.alloc_expr_desugared_with_ptr(
-                    Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false },
+                    Expr::Call { callee, args: Box::new([unit]) },
                     ptr,
                 )
             }
@@ -792,7 +990,9 @@ impl ExprCollector<'_> {
     /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
     /// to preserve drop semantics. We should probably do the same in future.
     fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
-        let label = e.label().map(|label| self.collect_label(label));
+        let label = e.label().map(|label| {
+            (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+        });
         let body = self.collect_labelled_block_opt(label, e.loop_body());
 
         // Labels can also be used in the condition expression, like this:
@@ -809,9 +1009,9 @@ impl ExprCollector<'_> {
         // }
         // ```
         let condition = match label {
-            Some(label) => {
-                self.with_labeled_rib(label, |this| this.collect_expr_opt(e.condition()))
-            }
+            Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {
+                this.collect_expr_opt(e.condition())
+            }),
             None => self.collect_expr_opt(e.condition()),
         };
 
@@ -820,7 +1020,7 @@ impl ExprCollector<'_> {
             Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
             syntax_ptr,
         );
-        self.alloc_expr(Expr::Loop { body: if_expr, label }, syntax_ptr)
+        self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)
     }
 
     /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
@@ -851,15 +1051,11 @@ impl ExprCollector<'_> {
         let head = self.collect_expr_opt(e.iterable());
         let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr);
         let iterator = self.alloc_expr(
-            Expr::Call {
-                callee: into_iter_fn_expr,
-                args: Box::new([head]),
-                is_assignee_expr: false,
-            },
+            Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },
             syntax_ptr,
         );
         let none_arm = MatchArm {
-            pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
+            pat: self.alloc_pat_desugared(Pat::Path(option_none)),
             guard: None,
             expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
         };
@@ -868,7 +1064,9 @@ impl ExprCollector<'_> {
             args: Box::new([self.collect_pat_top(e.pat())]),
             ellipsis: None,
         };
-        let label = e.label().map(|label| self.collect_label(label));
+        let label = e.label().map(|label| {
+            (self.hygiene_id_for(label.syntax().text_range().start()), self.collect_label(label))
+        });
         let some_arm = MatchArm {
             pat: self.alloc_pat_desugared(some_pat),
             guard: None,
@@ -884,11 +1082,7 @@ impl ExprCollector<'_> {
         );
         let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr);
         let iter_next_expr = self.alloc_expr(
-            Expr::Call {
-                callee: iter_next_fn_expr,
-                args: Box::new([iter_expr_mut]),
-                is_assignee_expr: false,
-            },
+            Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },
             syntax_ptr,
         );
         let loop_inner = self.alloc_expr(
@@ -904,7 +1098,8 @@ impl ExprCollector<'_> {
             },
             syntax_ptr,
         );
-        let loop_outer = self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr);
+        let loop_outer = self
+            .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr);
         let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable);
         let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
         self.add_definition_to_binding(iter_binding, iter_pat);
@@ -942,10 +1137,8 @@ impl ExprCollector<'_> {
         };
         let operand = self.collect_expr_opt(e.expr());
         let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr);
-        let expr = self.alloc_expr(
-            Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
-            syntax_ptr,
-        );
+        let expr = self
+            .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
         let continue_name = Name::generate_new_name(self.body.bindings.len());
         let continue_binding =
             self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
@@ -975,10 +1168,8 @@ impl ExprCollector<'_> {
             expr: {
                 let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
                 let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr);
-                let result = self.alloc_expr(
-                    Expr::Call { callee, args: Box::new([it]), is_assignee_expr: false },
-                    syntax_ptr,
-                );
+                let result =
+                    self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
                 self.alloc_expr(
                     match self.current_try_block_label {
                         Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
@@ -1065,7 +1256,14 @@ impl ExprCollector<'_> {
                     // FIXME: Report parse errors here
                 }
 
+                let SpanMap::ExpansionSpanMap(new_span_map) = self.expander.span_map(self.db)
+                else {
+                    panic!("just expanded a macro, ExpansionSpanMap should be available");
+                };
+                let old_span_map =
+                    mem::replace(&mut self.current_span_map, Some(new_span_map.clone()));
                 let id = collector(self, Some(expansion.tree()));
+                self.current_span_map = old_span_map;
                 self.ast_id_map = prev_ast_id_map;
                 self.expander.exit(mark);
                 id
@@ -1108,7 +1306,7 @@ impl ExprCollector<'_> {
             // Make the macro-call point to its expanded expression so we can query
             // semantics on syntax pointers to the macro
             let src = self.expander.in_file(syntax_ptr);
-            self.source_map.expr_map.insert(src, tail);
+            self.source_map.expr_map.insert(src, tail.into());
         })
     }
 
@@ -1119,8 +1317,7 @@ impl ExprCollector<'_> {
                     return;
                 }
                 let pat = self.collect_pat_top(stmt.pat());
-                let type_ref =
-                    stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+                let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it));
                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
                 let else_branch = stmt
                     .let_else()
@@ -1145,10 +1342,46 @@ impl ExprCollector<'_> {
                     statements.push(Statement::Expr { expr, has_semi });
                 }
             }
-            ast::Stmt::Item(_item) => statements.push(Statement::Item),
+            ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+                let Some(name) = macro_.name() else {
+                    statements.push(Statement::Item(Item::Other));
+                    return;
+                };
+                let name = name.as_name();
+                let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros();
+                self.collect_macro_def(statements, macro_id);
+            }
+            ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+                let Some(name) = macro_.name() else {
+                    statements.push(Statement::Item(Item::Other));
+                    return;
+                };
+                let name = name.as_name();
+                let macro_defs_count =
+                    self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
+                let macro_id = self.def_map.modules[DefMap::ROOT]
+                    .scope
+                    .get_legacy_macro(&name)
+                    .and_then(|it| it.get(*macro_defs_count))
+                    .copied();
+                *macro_defs_count += 1;
+                self.collect_macro_def(statements, macro_id);
+            }
+            ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)),
         }
     }
 
+    fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) {
+        let Some(macro_id) = macro_id else {
+            never!("def map should have macro definition, but it doesn't");
+            statements.push(Statement::Item(Item::Other));
+            return;
+        };
+        let macro_id = self.db.macro_def(macro_id);
+        statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id))));
+        self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id))));
+    }
+
     fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
         self.collect_block_(block, |id, statements, tail| Expr::Block {
             id,
@@ -1194,6 +1427,7 @@ impl ExprCollector<'_> {
             };
         let prev_def_map = mem::replace(&mut self.def_map, def_map);
         let prev_local_module = mem::replace(&mut self.expander.module, module);
+        let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count);
 
         let mut statements = Vec::new();
         block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
@@ -1216,6 +1450,7 @@ impl ExprCollector<'_> {
 
         self.def_map = prev_def_map;
         self.expander.module = prev_local_module;
+        self.current_block_legacy_macro_defs_count = prev_legacy_macros_count;
         expr_id
     }
 
@@ -1228,11 +1463,13 @@ impl ExprCollector<'_> {
 
     fn collect_labelled_block_opt(
         &mut self,
-        label: Option<LabelId>,
+        label: Option<(HygieneId, LabelId)>,
         expr: Option<ast::BlockExpr>,
     ) -> ExprId {
         match label {
-            Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)),
+            Some((hygiene, label)) => {
+                self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr))
+            }
             None => self.collect_block_opt(expr),
         }
     }
@@ -1250,6 +1487,10 @@ impl ExprCollector<'_> {
         let pattern = match &pat {
             ast::Pat::IdentPat(bp) => {
                 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
+                let hygiene = bp
+                    .name()
+                    .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
+                    .unwrap_or(HygieneId::ROOT);
 
                 let annotation =
                     BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
@@ -1285,12 +1526,12 @@ impl ExprCollector<'_> {
                         }
                         // shadowing statics is an error as well, so we just ignore that case here
                         _ => {
-                            let id = binding_list.find(self, name, annotation);
+                            let id = binding_list.find(self, name, hygiene, annotation);
                             (Some(id), Pat::Bind { id, subpat })
                         }
                     }
                 } else {
-                    let id = binding_list.find(self, name, annotation);
+                    let id = binding_list.find(self, name, hygiene, annotation);
                     (Some(id), Pat::Bind { id, subpat })
                 };
 
@@ -1302,8 +1543,7 @@ impl ExprCollector<'_> {
                 return pat;
             }
             ast::Pat::TupleStructPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let (args, ellipsis) = self.collect_tuple_pat(
                     p.fields(),
                     comma_follows_token(p.l_paren_token()),
@@ -1317,8 +1557,7 @@ impl ExprCollector<'_> {
                 Pat::Ref { pat, mutability }
             }
             ast::Pat::PathPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path));
                 path.map(Pat::Path).unwrap_or(Pat::Missing)
             }
             ast::Pat::OrPat(p) => 'b: {
@@ -1348,6 +1587,10 @@ impl ExprCollector<'_> {
                 for (id, _) in current_is_used.into_iter() {
                     binding_list.check_is_used(self, id);
                 }
+                if let &[pat] = &*pats {
+                    // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages.
+                    return pat;
+                }
                 Pat::Or(pats.into())
             }
             ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
@@ -1361,8 +1604,7 @@ impl ExprCollector<'_> {
             }
             ast::Pat::WildcardPat(_) => Pat::Wild,
             ast::Pat::RecordPat(p) => {
-                let path =
-                    p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
+                let path = p.path().and_then(|path| self.parse_path(path)).map(Box::new);
                 let record_pat_field_list =
                     &p.record_pat_field_list().expect("every struct should have a field list");
                 let args = record_pat_field_list
@@ -1372,7 +1614,7 @@ impl ExprCollector<'_> {
                         let ast_pat = f.pat()?;
                         let pat = self.collect_pat(ast_pat, binding_list);
                         let name = f.field_name()?.as_name();
-                        let src = self.expander.in_file(AstPtr::new(&f));
+                        let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
                         self.source_map.pat_field_map_back.insert(pat, src);
                         Some(RecordFieldPat { name, pat })
                     })
@@ -1569,20 +1811,51 @@ impl ExprCollector<'_> {
         lifetime: Option<ast::Lifetime>,
     ) -> Result<Option<LabelId>, BodyDiagnostic> {
         let Some(lifetime) = lifetime else { return Ok(None) };
+        let (mut hygiene_id, mut hygiene_info) = match &self.current_span_map {
+            None => (HygieneId::ROOT, None),
+            Some(span_map) => {
+                let span = span_map.span_at(lifetime.syntax().text_range().start());
+                let ctx = self.db.lookup_intern_syntax_context(span.ctx);
+                let hygiene_id = HygieneId::new(ctx.opaque_and_semitransparent);
+                let hygiene_info = ctx.outer_expn.map(|expansion| {
+                    let expansion = self.db.lookup_intern_macro_call(expansion);
+                    (ctx.parent, expansion.def)
+                });
+                (hygiene_id, hygiene_info)
+            }
+        };
         let name = Name::new_lifetime(&lifetime);
 
         for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
-            if let Some((label_name, id)) = &rib.label {
-                if *label_name == name {
-                    return if self.is_label_valid_from_rib(rib_idx) {
-                        Ok(Some(*id))
-                    } else {
-                        Err(BodyDiagnostic::UnreachableLabel {
-                            name,
-                            node: self.expander.in_file(AstPtr::new(&lifetime)),
-                        })
-                    };
+            match &rib.kind {
+                RibKind::Normal(label_name, id, label_hygiene) => {
+                    if *label_name == name && *label_hygiene == hygiene_id {
+                        return if self.is_label_valid_from_rib(rib_idx) {
+                            Ok(Some(*id))
+                        } else {
+                            Err(BodyDiagnostic::UnreachableLabel {
+                                name,
+                                node: self.expander.in_file(AstPtr::new(&lifetime)),
+                            })
+                        };
+                    }
                 }
+                RibKind::MacroDef(macro_id) => {
+                    if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+                        if label_macro_id == **macro_id {
+                            // A macro is allowed to refer to labels from before its declaration.
+                            // Therefore, if we got to the rib of its declaration, give up its hygiene
+                            // and use its parent expansion.
+                            let parent_ctx = self.db.lookup_intern_syntax_context(parent_ctx);
+                            hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+                            hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+                                let expansion = self.db.lookup_intern_macro_call(expansion);
+                                (parent_ctx.parent, expansion.def)
+                            });
+                        }
+                    }
+                }
+                _ => {}
             }
         }
 
@@ -1596,28 +1869,44 @@ impl ExprCollector<'_> {
         !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
     }
 
+    fn pop_label_rib(&mut self) {
+        // We need to pop all macro defs, plus one rib.
+        while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() {
+            // Do nothing.
+        }
+    }
+
     fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
         self.label_ribs.push(LabelRib::new(kind));
         let res = f(self);
-        self.label_ribs.pop();
+        self.pop_label_rib();
         res
     }
 
-    fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T {
-        self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label)));
+    fn with_labeled_rib<T>(
+        &mut self,
+        label: LabelId,
+        hygiene: HygieneId,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> T {
+        self.label_ribs.push(LabelRib::new(RibKind::Normal(
+            self.body[label].name.clone(),
+            label,
+            hygiene,
+        )));
         let res = f(self);
-        self.label_ribs.pop();
+        self.pop_label_rib();
         res
     }
 
     fn with_opt_labeled_rib<T>(
         &mut self,
-        label: Option<LabelId>,
+        label: Option<(HygieneId, LabelId)>,
         f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         match label {
             None => f(self),
-            Some(label) => self.with_labeled_rib(label, f),
+            Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f),
         }
     }
     // endregion: labels
@@ -1666,28 +1955,39 @@ impl ExprCollector<'_> {
             _ => None,
         });
         let mut mappings = vec![];
-        let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
+        let (fmt, hygiene) = match template.and_then(|it| self.expand_macros_to_string(it)) {
             Some((s, is_direct_literal)) => {
                 let call_ctx = self.expander.syntax_context();
-                format_args::parse(
+                let hygiene = self.hygiene_id_for(s.syntax().text_range().start());
+                let fmt = format_args::parse(
                     &s,
                     fmt_snippet,
                     args,
                     is_direct_literal,
-                    |name| self.alloc_expr_desugared(Expr::Path(Path::from(name))),
+                    |name| {
+                        let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
+                        if !hygiene.is_root() {
+                            self.body.expr_hygiene.insert(expr_id, hygiene);
+                        }
+                        expr_id
+                    },
                     |name, span| {
                         if let Some(span) = span {
                             mappings.push((span, name))
                         }
                     },
                     call_ctx,
-                )
+                );
+                (fmt, hygiene)
             }
-            None => FormatArgs {
-                template: Default::default(),
-                arguments: args.finish(),
-                orphans: Default::default(),
-            },
+            None => (
+                FormatArgs {
+                    template: Default::default(),
+                    arguments: args.finish(),
+                    orphans: Default::default(),
+                },
+                HygieneId::ROOT,
+            ),
         };
 
         // Create a list of all _unique_ (argument, format trait) combinations.
@@ -1723,10 +2023,8 @@ impl ExprCollector<'_> {
                 }
             })
             .collect();
-        let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
-            elements: lit_pieces,
-            is_assignee_expr: false,
-        }));
+        let lit_pieces =
+            self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
         let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
             expr: lit_pieces,
             rawness: Rawness::Ref,
@@ -1743,10 +2041,7 @@ impl ExprCollector<'_> {
                     Some(self.make_format_spec(placeholder, &mut argmap))
                 })
                 .collect();
-            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
-                elements,
-                is_assignee_expr: false,
-            }));
+            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
             self.alloc_expr_desugared(Expr::Ref {
                 expr: array,
                 rawness: Rawness::Ref,
@@ -1756,10 +2051,8 @@ impl ExprCollector<'_> {
         let arguments = &*fmt.arguments.arguments;
 
         let args = if arguments.is_empty() {
-            let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
-                elements: Box::default(),
-                is_assignee_expr: false,
-            }));
+            let expr = self
+                .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
             self.alloc_expr_desugared(Expr::Ref {
                 expr,
                 rawness: Rawness::Ref,
@@ -1786,10 +2079,8 @@ impl ExprCollector<'_> {
                     self.make_argument(arg, ty)
                 })
                 .collect();
-            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
-                elements: args,
-                is_assignee_expr: false,
-            }));
+            let array =
+                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
             self.alloc_expr_desugared(Expr::Ref {
                 expr: array,
                 rawness: Rawness::Ref,
@@ -1822,11 +2113,8 @@ impl ExprCollector<'_> {
         let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
 
         let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
-        let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
-            callee: unsafe_arg_new,
-            args: Box::default(),
-            is_assignee_expr: false,
-        });
+        let unsafe_arg_new =
+            self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
         let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
             id: None,
             // We collect the unused expressions here so that we still infer them instead of
@@ -1843,11 +2131,14 @@ impl ExprCollector<'_> {
             Expr::Call {
                 callee: new_v1_formatted,
                 args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
-                is_assignee_expr: false,
             },
             syntax_ptr,
         );
-        self.source_map.template_map.get_or_insert_with(Default::default).0.insert(idx, mappings);
+        self.source_map
+            .template_map
+            .get_or_insert_with(Default::default)
+            .0
+            .insert(idx, (hygiene, mappings));
         idx
     }
 
@@ -1938,7 +2229,6 @@ impl ExprCollector<'_> {
         self.alloc_expr_desugared(Expr::Call {
             callee: format_placeholder_new,
             args: Box::new([position, fill, align, flags, precision, width]),
-            is_assignee_expr: false,
         })
     }
 
@@ -1980,11 +2270,7 @@ impl ExprCollector<'_> {
                     Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
                     None => self.missing_expr(),
                 };
-                self.alloc_expr_desugared(Expr::Call {
-                    callee: count_is,
-                    args: Box::new([args]),
-                    is_assignee_expr: false,
-                })
+                self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
             }
             Some(FormatCount::Argument(arg)) => {
                 if let Ok(arg_index) = arg.index {
@@ -2005,7 +2291,6 @@ impl ExprCollector<'_> {
                     self.alloc_expr_desugared(Expr::Call {
                         callee: count_param,
                         args: Box::new([args]),
-                        is_assignee_expr: false,
                     })
                 } else {
                     // FIXME: This drops arg causing it to potentially not be resolved/type checked
@@ -2054,11 +2339,7 @@ impl ExprCollector<'_> {
             Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
             None => self.missing_expr(),
         };
-        self.alloc_expr_desugared(Expr::Call {
-            callee: new_fn,
-            args: Box::new([arg]),
-            is_assignee_expr: false,
-        })
+        self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
     }
 
     // endregion: format
@@ -2082,7 +2363,7 @@ impl ExprCollector<'_> {
         let src = self.expander.in_file(ptr);
         let id = self.body.exprs.alloc(expr);
         self.source_map.expr_map_back.insert(id, src);
-        self.source_map.expr_map.insert(src, id);
+        self.source_map.expr_map.insert(src, id.into());
         id
     }
     // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
@@ -2110,10 +2391,17 @@ impl ExprCollector<'_> {
         binding
     }
 
+    fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
+        let src = self.expander.in_file(ptr);
+        let id = self.body.pats.alloc(pat);
+        self.source_map.expr_map.insert(src, id.into());
+        self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
+        id
+    }
     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
         let src = self.expander.in_file(ptr);
         let id = self.body.pats.alloc(pat);
-        self.source_map.pat_map_back.insert(id, src);
+        self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
         self.source_map.pat_map.insert(src, id);
         id
     }
@@ -2151,6 +2439,17 @@ impl ExprCollector<'_> {
         self.awaitable_context = orig;
         res
     }
+
+    /// If this returns `HygieneId::ROOT`, do not allocate to save space.
+    fn hygiene_id_for(&self, span_start: TextSize) -> HygieneId {
+        match &self.current_span_map {
+            None => HygieneId::ROOT,
+            Some(span_map) => {
+                let ctx = span_map.span_at(span_start).ctx;
+                HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent)
+            }
+        }
+    }
 }
 
 fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
index 4213370ac19..c1b58dbdd0c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
@@ -158,9 +158,7 @@ impl ExprCollector<'_> {
                                 AsmOperand::Const(self.collect_expr_opt(c.expr()))
                             }
                             ast::AsmOperand::AsmSym(s) => {
-                                let Some(path) =
-                                    s.path().and_then(|p| self.expander.parse_path(self.db, p))
-                                else {
+                                let Some(path) = s.path().and_then(|p| self.parse_path(p)) else {
                                     continue;
                                 };
                                 AsmOperand::Sym(path)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index 37167fcb815..f8b6eef3422 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -11,7 +11,6 @@ use crate::{
         Statement,
     },
     pretty::{print_generic_args, print_path, print_type_ref},
-    type_ref::TypeRef,
 };
 
 use super::*;
@@ -69,20 +68,20 @@ pub(super) fn print_body_hir(
     };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
-        let function_data = &db.function_data(it);
+        let function_data = db.function_data(it);
         let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
         if let Some(self_param) = body.self_param {
             p.print_binding(self_param);
             p.buf.push_str(": ");
             if let Some(ty) = params.next() {
-                p.print_type_ref(ty);
+                p.print_type_ref(*ty, &function_data.types_map);
                 p.buf.push_str(", ");
             }
         }
         body.params.iter().zip(params).for_each(|(&param, ty)| {
             p.print_pat(param);
             p.buf.push_str(": ");
-            p.print_type_ref(ty);
+            p.print_type_ref(*ty, &function_data.types_map);
             p.buf.push_str(", ");
         });
         // remove the last ", " in param list
@@ -92,7 +91,7 @@ pub(super) fn print_body_hir(
         p.buf.push(')');
         // return type
         p.buf.push_str(" -> ");
-        p.print_type_ref(ret_type);
+        p.print_type_ref(*ret_type, &function_data.types_map);
         p.buf.push(' ');
     }
     p.print_expr(body.body_expr);
@@ -242,7 +241,7 @@ impl Printer<'_> {
             Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
             Expr::OffsetOf(offset_of) => {
                 w!(self, "builtin#offset_of(");
-                self.print_type_ref(&offset_of.container);
+                self.print_type_ref(offset_of.container, &self.body.types);
                 let edition = self.edition;
                 w!(
                     self,
@@ -277,7 +276,7 @@ impl Printer<'_> {
                 w!(self, "loop ");
                 self.print_expr(*body);
             }
-            Expr::Call { callee, args, is_assignee_expr: _ } => {
+            Expr::Call { callee, args } => {
                 self.print_expr(*callee);
                 w!(self, "(");
                 if !args.is_empty() {
@@ -296,7 +295,7 @@ impl Printer<'_> {
                 if let Some(args) = generic_args {
                     w!(self, "::<");
                     let edition = self.edition;
-                    print_generic_args(self.db, args, self, edition).unwrap();
+                    print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
                     w!(self, ">");
                 }
                 w!(self, "(");
@@ -372,7 +371,7 @@ impl Printer<'_> {
                     self.print_expr(*expr);
                 }
             }
-            Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
+            Expr::RecordLit { path, fields, spread } => {
                 match path {
                     Some(path) => self.print_path(path),
                     None => w!(self, "�"),
@@ -391,9 +390,6 @@ impl Printer<'_> {
                         p.print_expr(*spread);
                         wln!(p);
                     }
-                    if *ellipsis {
-                        wln!(p, "..");
-                    }
                 });
                 w!(self, "}}");
             }
@@ -408,7 +404,7 @@ impl Printer<'_> {
             Expr::Cast { expr, type_ref } => {
                 self.print_expr(*expr);
                 w!(self, " as ");
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, &self.body.types);
             }
             Expr::Ref { expr, rawness, mutability } => {
                 w!(self, "&");
@@ -466,7 +462,7 @@ impl Printer<'_> {
                     w!(self, ") ");
                 }
             }
-            Expr::Index { base, index, is_assignee_expr: _ } => {
+            Expr::Index { base, index } => {
                 self.print_expr(*base);
                 w!(self, "[");
                 self.print_expr(*index);
@@ -496,18 +492,18 @@ impl Printer<'_> {
                     self.print_pat(*pat);
                     if let Some(ty) = ty {
                         w!(self, ": ");
-                        self.print_type_ref(ty);
+                        self.print_type_ref(*ty, &self.body.types);
                     }
                 }
                 w!(self, "|");
                 if let Some(ret_ty) = ret_type {
                     w!(self, " -> ");
-                    self.print_type_ref(ret_ty);
+                    self.print_type_ref(*ret_ty, &self.body.types);
                 }
                 self.whitespace();
                 self.print_expr(*body);
             }
-            Expr::Tuple { exprs, is_assignee_expr: _ } => {
+            Expr::Tuple { exprs } => {
                 w!(self, "(");
                 for expr in exprs.iter() {
                     self.print_expr(*expr);
@@ -519,7 +515,7 @@ impl Printer<'_> {
                 w!(self, "[");
                 if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
                     self.indented(|p| match arr {
-                        Array::ElementList { elements, is_assignee_expr: _ } => {
+                        Array::ElementList { elements } => {
                             for elem in elements.iter() {
                                 p.print_expr(*elem);
                                 w!(p, ", ");
@@ -551,6 +547,11 @@ impl Printer<'_> {
             Expr::Const(id) => {
                 w!(self, "const {{ /* {id:?} */ }}");
             }
+            &Expr::Assignment { target, value } => {
+                self.print_pat(target);
+                w!(self, " = ");
+                self.print_expr(value);
+            }
         }
     }
 
@@ -719,6 +720,9 @@ impl Printer<'_> {
                 w!(self, "const ");
                 self.print_expr(*c);
             }
+            Pat::Expr(expr) => {
+                self.print_expr(*expr);
+            }
         }
     }
 
@@ -729,7 +733,7 @@ impl Printer<'_> {
                 self.print_pat(*pat);
                 if let Some(ty) = type_ref {
                     w!(self, ": ");
-                    self.print_type_ref(ty);
+                    self.print_type_ref(*ty, &self.body.types);
                 }
                 if let Some(init) = initializer {
                     w!(self, " = ");
@@ -748,7 +752,7 @@ impl Printer<'_> {
                 }
                 wln!(self);
             }
-            Statement::Item => (),
+            Statement::Item(_) => (),
         }
     }
 
@@ -787,14 +791,14 @@ impl Printer<'_> {
         }
     }
 
-    fn print_type_ref(&mut self, ty: &TypeRef) {
+    fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) {
         let edition = self.edition;
-        print_type_ref(self.db, ty, self, edition).unwrap();
+        print_type_ref(self.db, ty, map, self, edition).unwrap();
     }
 
     fn print_path(&mut self, path: &Path) {
         let edition = self.edition;
-        print_path(self.db, path, self, edition).unwrap();
+        print_path(self.db, path, &self.body.types, self, edition).unwrap();
     }
 
     fn print_binding(&mut self, id: BindingId) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index bf201ca8347..63a7a9af201 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -1,12 +1,12 @@
 //! Name resolution for expressions.
-use hir_expand::name::Name;
+use hir_expand::{name::Name, MacroDefId};
 use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
 use triomphe::Arc;
 
 use crate::{
-    body::Body,
+    body::{Body, HygieneId},
     db::DefDatabase,
-    hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
+    hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
     BlockId, ConstBlockId, DefWithBodyId,
 };
 
@@ -22,6 +22,7 @@ pub struct ExprScopes {
 #[derive(Debug, PartialEq, Eq)]
 pub struct ScopeEntry {
     name: Name,
+    hygiene: HygieneId,
     binding: BindingId,
 }
 
@@ -30,6 +31,10 @@ impl ScopeEntry {
         &self.name
     }
 
+    pub(crate) fn hygiene(&self) -> HygieneId {
+        self.hygiene
+    }
+
     pub fn binding(&self) -> BindingId {
         self.binding
     }
@@ -40,6 +45,8 @@ pub struct ScopeData {
     parent: Option<ScopeId>,
     block: Option<BlockId>,
     label: Option<(LabelId, Name)>,
+    // FIXME: We can compress this with an enum for this and `label`/`block` if memory usage matters.
+    macro_def: Option<Box<MacroDefId>>,
     entries: IdxRange<ScopeEntry>,
 }
 
@@ -62,6 +69,12 @@ impl ExprScopes {
         self.scopes[scope].block
     }
 
+    /// If `scope` refers to a macro def scope, returns the corresponding `MacroId`.
+    #[allow(clippy::borrowed_box)] // If we return `&MacroDefId` we need to move it, this way we just clone the `Box`.
+    pub fn macro_def(&self, scope: ScopeId) -> Option<&Box<MacroDefId>> {
+        self.scopes[scope].macro_def.as_ref()
+    }
+
     /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`.
     pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> {
         self.scopes[scope].label.clone()
@@ -102,7 +115,7 @@ impl ExprScopes {
         };
         let mut root = scopes.root_scope();
         if let Some(self_param) = body.self_param {
-            scopes.add_bindings(body, root, self_param);
+            scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param));
         }
         scopes.add_params_bindings(body, root, &body.params);
         compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
@@ -114,6 +127,7 @@ impl ExprScopes {
             parent: None,
             block: None,
             label: None,
+            macro_def: None,
             entries: empty_entries(self.scope_entries.len()),
         })
     }
@@ -123,6 +137,7 @@ impl ExprScopes {
             parent: Some(parent),
             block: None,
             label: None,
+            macro_def: None,
             entries: empty_entries(self.scope_entries.len()),
         })
     }
@@ -132,6 +147,7 @@ impl ExprScopes {
             parent: Some(parent),
             block: None,
             label,
+            macro_def: None,
             entries: empty_entries(self.scope_entries.len()),
         })
     }
@@ -146,21 +162,38 @@ impl ExprScopes {
             parent: Some(parent),
             block,
             label,
+            macro_def: None,
             entries: empty_entries(self.scope_entries.len()),
         })
     }
 
-    fn add_bindings(&mut self, body: &Body, scope: ScopeId, binding: BindingId) {
+    fn new_macro_def_scope(&mut self, parent: ScopeId, macro_id: Box<MacroDefId>) -> ScopeId {
+        self.scopes.alloc(ScopeData {
+            parent: Some(parent),
+            block: None,
+            label: None,
+            macro_def: Some(macro_id),
+            entries: empty_entries(self.scope_entries.len()),
+        })
+    }
+
+    fn add_bindings(
+        &mut self,
+        body: &Body,
+        scope: ScopeId,
+        binding: BindingId,
+        hygiene: HygieneId,
+    ) {
         let Binding { name, .. } = &body.bindings[binding];
-        let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding });
+        let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
         self.scopes[scope].entries =
             IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
     }
 
     fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
         let pattern = &body[pat];
-        if let Pat::Bind { id, .. } = pattern {
-            self.add_bindings(body, scope, *id);
+        if let Pat::Bind { id, .. } = *pattern {
+            self.add_bindings(body, scope, id, body.binding_hygiene(id));
         }
 
         pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat));
@@ -206,7 +239,10 @@ fn compute_block_scopes(
             Statement::Expr { expr, .. } => {
                 compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
             }
-            Statement::Item => (),
+            Statement::Item(Item::MacroDef(macro_id)) => {
+                *scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
+            }
+            Statement::Item(Item::Other) => (),
         }
     }
     if let Some(expr) = tail {
@@ -282,7 +318,7 @@ fn compute_expr_scopes(
             *scope = scopes.new_scope(*scope);
             scopes.add_pat_bindings(body, *scope, pat);
         }
-        e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
+        _ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
     };
 }
 
@@ -333,6 +369,8 @@ mod tests {
 
         let expr_id = source_map
             .node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
+            .unwrap()
+            .as_expr()
             .unwrap();
         let scope = scopes.scope_for(expr_id);
 
@@ -488,8 +526,11 @@ fn foo() {
 
         let expr_scope = {
             let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
-            let expr_id =
-                source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
+            let expr_id = source_map
+                .node_expr(InFile { file_id: file_id.into(), value: &expr_ast })
+                .unwrap()
+                .as_expr()
+                .unwrap();
             scopes.scope_for(expr_id).unwrap()
         };
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index dd3e79c874d..3b29d98d198 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -370,3 +370,37 @@ fn f(a: i32, b: u32) -> String {
         }"#]]
     .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
 }
+
+#[test]
+fn destructuring_assignment_tuple_macro() {
+    // This is a funny one. `let m!()() = Bar()` is an error in rustc, because `m!()()` isn't a valid pattern,
+    // but in destructuring assignment it is valid, because `m!()()` is a valid expression, and destructuring
+    // assignments start their lives as expressions. So we have to do the same.
+
+    let (db, body, def) = lower(
+        r#"
+struct Bar();
+
+macro_rules! m {
+    () => { Bar };
+}
+
+fn foo() {
+    m!()() = Bar();
+}
+"#,
+    );
+
+    let (_, source_map) = db.body_with_source_map(def);
+    assert_eq!(source_map.diagnostics(), &[]);
+
+    for (_, def_map) in body.blocks(&db) {
+        assert_eq!(def_map.diagnostics(), &[]);
+    }
+
+    expect![[r#"
+        fn foo() -> () {
+            Bar() = Bar();
+        }"#]]
+    .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT))
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 263fad51d78..f49018eaf38 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -6,7 +6,7 @@ use base_db::CrateId;
 use hir_expand::{
     name::Name, AstId, ExpandResult, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefKind,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
 use la_arena::{Idx, RawIdx};
 use smallvec::SmallVec;
 use syntax::{ast, Parse};
@@ -25,7 +25,7 @@ use crate::{
         DefMap, MacroSubNs,
     },
     path::ImportAlias,
-    type_ref::{TraitRef, TypeBound, TypeRef},
+    type_ref::{TraitRef, TypeBound, TypeRefId, TypesMap},
     visibility::RawVisibility,
     AssocItemId, AstIdWithPath, ConstId, ConstLoc, ExternCrateId, FunctionId, FunctionLoc,
     HasModule, ImplId, Intern, ItemContainerId, ItemLoc, Lookup, Macro2Id, MacroRulesId, ModuleId,
@@ -35,13 +35,14 @@ use crate::{
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FunctionData {
     pub name: Name,
-    pub params: Box<[Interned<TypeRef>]>,
-    pub ret_type: Interned<TypeRef>,
+    pub params: Box<[TypeRefId]>,
+    pub ret_type: TypeRefId,
     pub attrs: Attrs,
     pub visibility: RawVisibility,
     pub abi: Option<Symbol>,
     pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
     pub rustc_allow_incoherent_impl: bool,
+    pub types_map: Arc<TypesMap>,
     flags: FnFlags,
 }
 
@@ -110,13 +111,14 @@ impl FunctionData {
                 .filter(|&(idx, _)| {
                     item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
                 })
-                .filter_map(|(_, param)| param.type_ref.clone())
+                .filter_map(|(_, param)| param.type_ref)
                 .collect(),
-            ret_type: func.ret_type.clone(),
+            ret_type: func.ret_type,
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             visibility,
             abi: func.abi.clone(),
             legacy_const_generics_indices,
+            types_map: func.types_map.clone(),
             flags,
             rustc_allow_incoherent_impl,
         })
@@ -182,13 +184,14 @@ fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TypeAliasData {
     pub name: Name,
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub type_ref: Option<TypeRefId>,
     pub visibility: RawVisibility,
     pub is_extern: bool,
     pub rustc_has_incoherent_inherent_impls: bool,
     pub rustc_allow_incoherent_impl: bool,
     /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
-    pub bounds: Box<[Interned<TypeBound>]>,
+    pub bounds: Box<[TypeBound]>,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl TypeAliasData {
@@ -216,12 +219,13 @@ impl TypeAliasData {
 
         Arc::new(TypeAliasData {
             name: typ.name.clone(),
-            type_ref: typ.type_ref.clone(),
+            type_ref: typ.type_ref,
             visibility,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             rustc_has_incoherent_inherent_impls,
             rustc_allow_incoherent_impl,
             bounds: typ.bounds.clone(),
+            types_map: typ.types_map.clone(),
         })
     }
 }
@@ -343,13 +347,14 @@ impl TraitAliasData {
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct ImplData {
-    pub target_trait: Option<Interned<TraitRef>>,
-    pub self_ty: Interned<TypeRef>,
+    pub target_trait: Option<TraitRef>,
+    pub self_ty: TypeRefId,
     pub items: Box<[AssocItemId]>,
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
     pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl ImplData {
@@ -368,7 +373,7 @@ impl ImplData {
         let item_tree = tree_id.item_tree(db);
         let impl_def = &item_tree[tree_id.value];
         let target_trait = impl_def.target_trait.clone();
-        let self_ty = impl_def.self_ty.clone();
+        let self_ty = impl_def.self_ty;
         let is_negative = impl_def.is_negative;
         let is_unsafe = impl_def.is_unsafe;
 
@@ -387,6 +392,7 @@ impl ImplData {
                 is_negative,
                 is_unsafe,
                 macro_calls,
+                types_map: impl_def.types_map.clone(),
             }),
             DefDiagnostics::new(diagnostics),
         )
@@ -532,10 +538,11 @@ impl ExternCrateDeclData {
 pub struct ConstData {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
     pub rustc_allow_incoherent_impl: bool,
     pub has_body: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl ConstData {
@@ -556,10 +563,11 @@ impl ConstData {
 
         Arc::new(ConstData {
             name: konst.name.clone(),
-            type_ref: konst.type_ref.clone(),
+            type_ref: konst.type_ref,
             visibility,
             rustc_allow_incoherent_impl,
             has_body: konst.has_body,
+            types_map: konst.types_map.clone(),
         })
     }
 }
@@ -567,12 +575,13 @@ impl ConstData {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct StaticData {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
     pub mutable: bool,
     pub is_extern: bool,
     pub has_safe_kw: bool,
     pub has_unsafe_kw: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 impl StaticData {
@@ -583,12 +592,13 @@ impl StaticData {
 
         Arc::new(StaticData {
             name: statik.name.clone(),
-            type_ref: statik.type_ref.clone(),
+            type_ref: statik.type_ref,
             visibility: item_tree[statik.visibility].clone(),
             mutable: statik.mutable,
             is_extern: matches!(loc.container, ItemContainerId::ExternBlockId(_)),
             has_safe_kw: statik.has_safe_kw,
             has_unsafe_kw: statik.has_unsafe_kw,
+            types_map: statik.types_map.clone(),
         })
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index ba54451e594..068ebb3b7e9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -6,7 +6,7 @@ use cfg::CfgOptions;
 use either::Either;
 
 use hir_expand::name::Name;
-use intern::{sym, Interned};
+use intern::sym;
 use la_arena::Arena;
 use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
 use triomphe::Arc;
@@ -21,7 +21,7 @@ use crate::{
     lang_item::LangItem,
     nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
     tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
-    type_ref::TypeRef,
+    type_ref::{TypeRefId, TypesMap},
     visibility::RawVisibility,
     EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
 };
@@ -73,8 +73,8 @@ pub struct EnumVariantData {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum VariantData {
-    Record(Arena<FieldData>),
-    Tuple(Arena<FieldData>),
+    Record { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
+    Tuple { fields: Arena<FieldData>, types_map: Arc<TypesMap> },
     Unit,
 }
 
@@ -82,7 +82,7 @@ pub enum VariantData {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct FieldData {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibility,
 }
 
@@ -208,7 +208,7 @@ impl StructData {
         }
 
         let strukt = &item_tree[loc.id.value];
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             loc.container.local_id,
@@ -219,12 +219,13 @@ impl StructData {
             &strukt.fields,
             None,
         );
+        let types_map = strukt.types_map.clone();
         (
             Arc::new(StructData {
                 name: strukt.name.clone(),
                 variant_data: Arc::new(match strukt.shape {
-                    FieldsShape::Record => VariantData::Record(data),
-                    FieldsShape::Tuple => VariantData::Tuple(data),
+                    FieldsShape::Record => VariantData::Record { fields, types_map },
+                    FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
                     FieldsShape::Unit => VariantData::Unit,
                 }),
                 repr,
@@ -258,7 +259,7 @@ impl StructData {
         }
 
         let union = &item_tree[loc.id.value];
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             loc.container.local_id,
@@ -269,10 +270,11 @@ impl StructData {
             &union.fields,
             None,
         );
+        let types_map = union.types_map.clone();
         (
             Arc::new(StructData {
                 name: union.name.clone(),
-                variant_data: Arc::new(VariantData::Record(data)),
+                variant_data: Arc::new(VariantData::Record { fields, types_map }),
                 repr,
                 visibility: item_tree[union.visibility].clone(),
                 flags,
@@ -360,7 +362,7 @@ impl EnumVariantData {
         let item_tree = loc.id.item_tree(db);
         let variant = &item_tree[loc.id.value];
 
-        let (data, diagnostics) = lower_fields(
+        let (fields, diagnostics) = lower_fields(
             db,
             krate,
             container.local_id,
@@ -371,13 +373,14 @@ impl EnumVariantData {
             &variant.fields,
             Some(item_tree[loc.parent.lookup(db).id.value].visibility),
         );
+        let types_map = variant.types_map.clone();
 
         (
             Arc::new(EnumVariantData {
                 name: variant.name.clone(),
                 variant_data: Arc::new(match variant.shape {
-                    FieldsShape::Record => VariantData::Record(data),
-                    FieldsShape::Tuple => VariantData::Tuple(data),
+                    FieldsShape::Record => VariantData::Record { fields, types_map },
+                    FieldsShape::Tuple => VariantData::Tuple { fields, types_map },
                     FieldsShape::Unit => VariantData::Unit,
                 }),
             }),
@@ -390,11 +393,20 @@ impl VariantData {
     pub fn fields(&self) -> &Arena<FieldData> {
         const EMPTY: &Arena<FieldData> = &Arena::new();
         match &self {
-            VariantData::Record(fields) | VariantData::Tuple(fields) => fields,
+            VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => fields,
             _ => EMPTY,
         }
     }
 
+    pub fn types_map(&self) -> &TypesMap {
+        match &self {
+            VariantData::Record { types_map, .. } | VariantData::Tuple { types_map, .. } => {
+                types_map
+            }
+            VariantData::Unit => TypesMap::EMPTY,
+        }
+    }
+
     // FIXME: Linear lookup
     pub fn field(&self, name: &Name) -> Option<LocalFieldId> {
         self.fields().iter().find_map(|(id, data)| if &data.name == name { Some(id) } else { None })
@@ -402,8 +414,8 @@ impl VariantData {
 
     pub fn kind(&self) -> StructKind {
         match self {
-            VariantData::Record(_) => StructKind::Record,
-            VariantData::Tuple(_) => StructKind::Tuple,
+            VariantData::Record { .. } => StructKind::Record,
+            VariantData::Tuple { .. } => StructKind::Tuple,
             VariantData::Unit => StructKind::Unit,
         }
     }
@@ -463,7 +475,7 @@ fn lower_field(
 ) -> FieldData {
     FieldData {
         name: field.name.clone(),
-        type_ref: field.type_ref.clone(),
+        type_ref: field.type_ref,
         visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index aeda302f35c..d7e83ce33e8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -2,7 +2,7 @@
 use base_db::{ra_salsa, CrateId, SourceDatabase, Upcast};
 use either::Either;
 use hir_expand::{db::ExpandDatabase, HirFileId, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
 use la_arena::ArenaMap;
 use span::{EditionedFileId, MacroCallId};
 use syntax::{ast, AstPtr};
@@ -18,9 +18,10 @@ use crate::{
     },
     generics::GenericParams,
     import_map::ImportMap,
-    item_tree::{AttrOwner, ItemTree},
+    item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
     lang_item::{self, LangItem, LangItemTarget, LangItems},
     nameres::{diagnostics::DefDiagnostics, DefMap},
+    type_ref::TypesSourceMap,
     visibility::{self, Visibility},
     AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId,
     EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
@@ -91,6 +92,18 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     #[ra_salsa::invoke(ItemTree::block_item_tree_query)]
     fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
 
+    #[ra_salsa::invoke(ItemTree::file_item_tree_with_source_map_query)]
+    fn file_item_tree_with_source_map(
+        &self,
+        file_id: HirFileId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
+    #[ra_salsa::invoke(ItemTree::block_item_tree_with_source_map_query)]
+    fn block_item_tree_with_source_map(
+        &self,
+        block_id: BlockId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>);
+
     #[ra_salsa::invoke(DefMap::crate_def_map_query)]
     fn crate_def_map(&self, krate: CrateId) -> Arc<DefMap>;
 
@@ -187,7 +200,14 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
     fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
 
     #[ra_salsa::invoke(GenericParams::generic_params_query)]
-    fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
+    fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
+
+    /// If this returns `None` for the source map, that means it is the same as with the item tree.
+    #[ra_salsa::invoke(GenericParams::generic_params_with_source_map_query)]
+    fn generic_params_with_source_map(
+        &self,
+        def: GenericDefId,
+    ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>);
 
     // region:attrs
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 6d8b4445f75..d430733fcad 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -14,6 +14,7 @@ use span::SyntaxContextId;
 use syntax::{ast, Parse};
 use triomphe::Arc;
 
+use crate::type_ref::{TypesMap, TypesSourceMap};
 use crate::{
     attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
     UnresolvedMacro,
@@ -49,6 +50,10 @@ impl Expander {
         }
     }
 
+    pub(crate) fn span_map(&self, db: &dyn DefDatabase) -> &SpanMap {
+        self.span_map.get_or_init(|| db.span_map(self.current_file_id))
+    }
+
     pub fn krate(&self) -> CrateId {
         self.module.krate
     }
@@ -110,8 +115,19 @@ impl Expander {
         mark.bomb.defuse();
     }
 
-    pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
-        LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone())
+    pub fn ctx<'a>(
+        &self,
+        db: &'a dyn DefDatabase,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
+    ) -> LowerCtx<'a> {
+        LowerCtx::with_span_map_cell(
+            db,
+            self.current_file_id,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        )
     }
 
     pub(crate) fn in_file<T>(&self, value: T) -> InFile<T> {
@@ -138,8 +154,20 @@ impl Expander {
         self.current_file_id
     }
 
-    pub(crate) fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
-        let ctx = LowerCtx::with_span_map_cell(db, self.current_file_id, self.span_map.clone());
+    pub(crate) fn parse_path(
+        &mut self,
+        db: &dyn DefDatabase,
+        path: ast::Path,
+        types_map: &mut TypesMap,
+        types_source_map: &mut TypesSourceMap,
+    ) -> Option<Path> {
+        let ctx = LowerCtx::with_span_map_cell(
+            db,
+            self.current_file_id,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        );
         Path::from_src(&ctx, path)
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index f5e03e5281e..a615abd1bbe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1025,7 +1025,7 @@ pub mod ast {
         check_found_path(
             r#"
 mod bar {
-    mod foo { pub(super) struct S; }
+    mod foo { pub(crate) struct S; }
     pub(crate) use foo::*;
 }
 $0
@@ -1047,7 +1047,7 @@ $0
         check_found_path(
             r#"
 mod bar {
-    mod foo { pub(super) struct S; }
+    mod foo { pub(crate) struct S; }
     pub(crate) use foo::S as U;
 }
 $0
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 6c34ee086aa..6b79850e9c4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -3,16 +3,18 @@
 //! generic parameters. See also the `Generics` type and the `generics_of` query
 //! in rustc.
 
-use std::ops;
+use std::{ops, sync::LazyLock};
 
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
     ExpandResult,
 };
-use intern::Interned;
 use la_arena::{Arena, RawIdx};
-use stdx::impl_from;
+use stdx::{
+    impl_from,
+    thin_vec::{EmptyOptimizedThinVec, ThinVec},
+};
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
 use triomphe::Arc;
 
@@ -22,7 +24,11 @@ use crate::{
     item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
-    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+    path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path},
+    type_ref::{
+        ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap,
+        TypesSourceMap,
+    },
     AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
@@ -37,7 +43,7 @@ pub struct TypeParamData {
     /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
     /// make it always be a value, giving impl trait a special name.
     pub name: Option<Name>,
-    pub default: Option<Interned<TypeRef>>,
+    pub default: Option<TypeRefId>,
     pub provenance: TypeParamProvenance,
 }
 
@@ -51,7 +57,7 @@ pub struct LifetimeParamData {
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct ConstParamData {
     pub name: Name,
-    pub ty: Interned<TypeRef>,
+    pub ty: TypeRefId,
     pub default: Option<ConstRef>,
 }
 
@@ -161,6 +167,7 @@ pub struct GenericParams {
     type_or_consts: Arena<TypeOrConstParamData>,
     lifetimes: Arena<LifetimeParamData>,
     where_predicates: Box<[WherePredicate]>,
+    pub types_map: TypesMap,
 }
 
 impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
@@ -183,24 +190,14 @@ impl ops::Index<LocalLifetimeParamId> for GenericParams {
 /// associated type bindings like `Iterator<Item = u32>`.
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum WherePredicate {
-    TypeBound {
-        target: WherePredicateTypeTarget,
-        bound: Interned<TypeBound>,
-    },
-    Lifetime {
-        target: LifetimeRef,
-        bound: LifetimeRef,
-    },
-    ForLifetime {
-        lifetimes: Box<[Name]>,
-        target: WherePredicateTypeTarget,
-        bound: Interned<TypeBound>,
-    },
+    TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
+    Lifetime { target: LifetimeRef, bound: LifetimeRef },
+    ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub enum WherePredicateTypeTarget {
-    TypeRef(Interned<TypeRef>),
+    TypeRef(TypeRefId),
     /// For desugared where predicates that can directly refer to a type param.
     TypeOrConstParam(LocalTypeOrConstParamId),
 }
@@ -300,7 +297,14 @@ impl GenericParams {
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
         def: GenericDefId,
-    ) -> Interned<GenericParams> {
+    ) -> Arc<GenericParams> {
+        db.generic_params_with_source_map(def).0
+    }
+
+    pub(crate) fn generic_params_with_source_map_query(
+        db: &dyn DefDatabase,
+        def: GenericDefId,
+    ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>) {
         let _p = tracing::info_span!("generic_params_query").entered();
 
         let krate = def.krate(db);
@@ -309,7 +313,7 @@ impl GenericParams {
 
         // Returns the generic parameters that are enabled under the current `#[cfg]` options
         let enabled_params =
-            |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+            |params: &Arc<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
                 let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
                 let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
                 let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
@@ -325,7 +329,7 @@ impl GenericParams {
                 if all_type_or_consts_enabled && all_lifetimes_enabled {
                     params.clone()
                 } else {
-                    Interned::new(GenericParams {
+                    Arc::new(GenericParams {
                         type_or_consts: all_type_or_consts_enabled
                             .then(|| params.type_or_consts.clone())
                             .unwrap_or_else(|| {
@@ -347,6 +351,7 @@ impl GenericParams {
                                     .collect()
                             }),
                         where_predicates: params.where_predicates.clone(),
+                        types_map: params.types_map.clone(),
                     })
                 }
             };
@@ -357,18 +362,18 @@ impl GenericParams {
                 Data = impl ItemTreeLoc<Id = Id>,
             >,
             enabled_params: impl Fn(
-                &Interned<GenericParams>,
+                &Arc<GenericParams>,
                 &ItemTree,
                 GenericModItem,
-            ) -> Interned<GenericParams>,
-        ) -> Interned<GenericParams>
+            ) -> Arc<GenericParams>,
+        ) -> (Arc<GenericParams>, Option<Arc<TypesSourceMap>>)
         where
             FileItemTreeId<Id>: Into<GenericModItem>,
         {
             let id = id.lookup(db).item_tree_id();
             let tree = id.item_tree(db);
             let item = &tree[id.value];
-            enabled_params(item.generic_params(), &tree, id.value.into())
+            (enabled_params(item.generic_params(), &tree, id.value.into()), None)
         }
 
         match def {
@@ -383,28 +388,37 @@ impl GenericParams {
                 let module = loc.container.module(db);
                 let func_data = db.function_data(id);
                 if func_data.params.is_empty() {
-                    enabled_params
+                    (enabled_params, None)
                 } else {
+                    let source_maps = loc.id.item_tree_with_source_map(db).1;
+                    let item_source_maps = source_maps.function(loc.id.value);
                     let mut generic_params = GenericParamsCollector {
                         type_or_consts: enabled_params.type_or_consts.clone(),
                         lifetimes: enabled_params.lifetimes.clone(),
                         where_predicates: enabled_params.where_predicates.clone().into(),
                     };
 
+                    let (mut types_map, mut types_source_maps) =
+                        (enabled_params.types_map.clone(), item_source_maps.generics().clone());
                     // Don't create an `Expander` if not needed since this
                     // could cause a reparse after the `ItemTree` has been created due to the spanmap.
                     let mut expander = None;
-                    for param in func_data.params.iter() {
+                    for &param in func_data.params.iter() {
                         generic_params.fill_implicit_impl_trait_args(
                             db,
+                            &mut types_map,
+                            &mut types_source_maps,
                             &mut expander,
                             &mut || {
                                 (module.def_map(db), Expander::new(db, loc.id.file_id(), module))
                             },
                             param,
+                            &item.types_map,
+                            item_source_maps.item(),
                         );
                     }
-                    Interned::new(generic_params.finish())
+                    let generics = generic_params.finish(types_map, &mut types_source_maps);
+                    (generics, Some(Arc::new(types_source_maps)))
                 }
             }
             GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
@@ -414,11 +428,15 @@ impl GenericParams {
             GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
-            GenericDefId::ConstId(_) => Interned::new(GenericParams {
-                type_or_consts: Default::default(),
-                lifetimes: Default::default(),
-                where_predicates: Default::default(),
-            }),
+            GenericDefId::ConstId(_) => (
+                Arc::new(GenericParams {
+                    type_or_consts: Default::default(),
+                    lifetimes: Default::default(),
+                    where_predicates: Default::default(),
+                    types_map: Default::default(),
+                }),
+                None,
+            ),
         }
     }
 }
@@ -452,7 +470,7 @@ impl GenericParamsCollector {
         &mut self,
         lower_ctx: &LowerCtx<'_>,
         type_bounds: Option<ast::TypeBoundList>,
-        target: Either<TypeRef, LifetimeRef>,
+        target: Either<TypeRefId, LifetimeRef>,
     ) {
         for bound in type_bounds.iter().flat_map(|type_bound_list| type_bound_list.bounds()) {
             self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
@@ -473,16 +491,15 @@ impl GenericParamsCollector {
                 ast::TypeOrConstParam::Type(type_param) => {
                     let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
                     // FIXME: Use `Path::from_src`
-                    let default = type_param
-                        .default_type()
-                        .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
+                    let default =
+                        type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
                     let param = TypeParamData {
                         name: Some(name.clone()),
                         default,
                         provenance: TypeParamProvenance::TypeParamList,
                     };
                     let idx = self.type_or_consts.alloc(param.into());
-                    let type_ref = TypeRef::Path(name.into());
+                    let type_ref = lower_ctx.alloc_type_ref_desugared(TypeRef::Path(name.into()));
                     self.fill_bounds(
                         lower_ctx,
                         type_param.type_bound_list(),
@@ -492,12 +509,10 @@ impl GenericParamsCollector {
                 }
                 ast::TypeOrConstParam::Const(const_param) => {
                     let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
-                    let ty = const_param
-                        .ty()
-                        .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+                    let ty = TypeRef::from_ast_opt(lower_ctx, const_param.ty());
                     let param = ConstParamData {
                         name,
-                        ty: Interned::new(ty),
+                        ty,
                         default: ConstRef::from_const_param(lower_ctx, &const_param),
                     };
                     let idx = self.type_or_consts.alloc(param.into());
@@ -557,7 +572,7 @@ impl GenericParamsCollector {
         lower_ctx: &LowerCtx<'_>,
         bound: ast::TypeBound,
         hrtb_lifetimes: Option<&[Name]>,
-        target: Either<TypeRef, LifetimeRef>,
+        target: Either<TypeRefId, LifetimeRef>,
     ) {
         let bound = TypeBound::from_ast(lower_ctx, bound);
         self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
@@ -565,12 +580,12 @@ impl GenericParamsCollector {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
                 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
                     lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
-                    target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
-                    bound: Interned::new(bound),
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
                 },
                 None => WherePredicate::TypeBound {
-                    target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
-                    bound: Interned::new(bound),
+                    target: WherePredicateTypeTarget::TypeRef(type_ref),
+                    bound,
                 },
             },
             (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
@@ -581,7 +596,7 @@ impl GenericParamsCollector {
         self.where_predicates.push(predicate);
     }
 
-    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<ThinVec<TypeBound>>) {
         for bounds in impl_bounds {
             let param = TypeParamData {
                 name: None,
@@ -589,10 +604,10 @@ impl GenericParamsCollector {
                 provenance: TypeParamProvenance::ArgumentImplTrait,
             };
             let param_id = self.type_or_consts.alloc(param.into());
-            for bound in bounds {
+            for bound in &bounds {
                 self.where_predicates.push(WherePredicate::TypeBound {
                     target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
-                    bound,
+                    bound: bound.clone(),
                 });
             }
         }
@@ -601,12 +616,16 @@ impl GenericParamsCollector {
     fn fill_implicit_impl_trait_args(
         &mut self,
         db: &dyn DefDatabase,
+        generics_types_map: &mut TypesMap,
+        generics_types_source_map: &mut TypesSourceMap,
         // FIXME: Change this back to `LazyCell` if https://github.com/rust-lang/libs-team/issues/429 is accepted.
         exp: &mut Option<(Arc<DefMap>, Expander)>,
         exp_fill: &mut dyn FnMut() -> (Arc<DefMap>, Expander),
-        type_ref: &TypeRef,
+        type_ref: TypeRefId,
+        types_map: &TypesMap,
+        types_source_map: &TypesSourceMap,
     ) {
-        type_ref.walk(&mut |type_ref| {
+        TypeRef::walk(type_ref, types_map, &mut |type_ref| {
             if let TypeRef::ImplTrait(bounds) = type_ref {
                 let param = TypeParamData {
                     name: None,
@@ -615,12 +634,20 @@ impl GenericParamsCollector {
                 };
                 let param_id = self.type_or_consts.alloc(param.into());
                 for bound in bounds {
+                    let bound = copy_type_bound(
+                        bound,
+                        types_map,
+                        types_source_map,
+                        generics_types_map,
+                        generics_types_source_map,
+                    );
                     self.where_predicates.push(WherePredicate::TypeBound {
                         target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
-                        bound: bound.clone(),
+                        bound,
                     });
                 }
             }
+
             if let TypeRef::Macro(mc) = type_ref {
                 let macro_call = mc.to_node(db.upcast());
                 let (def_map, expander) = exp.get_or_insert_with(&mut *exp_fill);
@@ -641,23 +668,217 @@ impl GenericParamsCollector {
                 if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
                     expander.enter_expand(db, macro_call, resolver)
                 {
-                    let ctx = expander.ctx(db);
+                    let (mut macro_types_map, mut macro_types_source_map) =
+                        (TypesMap::default(), TypesSourceMap::default());
+                    let ctx = expander.ctx(db, &mut macro_types_map, &mut macro_types_source_map);
                     let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
-                    self.fill_implicit_impl_trait_args(db, &mut *exp, exp_fill, &type_ref);
+                    self.fill_implicit_impl_trait_args(
+                        db,
+                        generics_types_map,
+                        generics_types_source_map,
+                        &mut *exp,
+                        exp_fill,
+                        type_ref,
+                        &macro_types_map,
+                        &macro_types_source_map,
+                    );
                     exp.get_or_insert_with(&mut *exp_fill).1.exit(mark);
                 }
             }
         });
     }
 
-    pub(crate) fn finish(self) -> GenericParams {
-        let Self { mut lifetimes, mut type_or_consts, where_predicates } = self;
+    pub(crate) fn finish(
+        self,
+        mut generics_types_map: TypesMap,
+        generics_types_source_map: &mut TypesSourceMap,
+    ) -> Arc<GenericParams> {
+        let Self { mut lifetimes, mut type_or_consts, mut where_predicates } = self;
+
+        if lifetimes.is_empty() && type_or_consts.is_empty() && where_predicates.is_empty() {
+            static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
+                Arc::new(GenericParams {
+                    lifetimes: Arena::new(),
+                    type_or_consts: Arena::new(),
+                    where_predicates: Box::default(),
+                    types_map: TypesMap::default(),
+                })
+            });
+            return Arc::clone(&EMPTY);
+        }
+
         lifetimes.shrink_to_fit();
         type_or_consts.shrink_to_fit();
-        GenericParams {
+        where_predicates.shrink_to_fit();
+        generics_types_map.shrink_to_fit();
+        generics_types_source_map.shrink_to_fit();
+        Arc::new(GenericParams {
             type_or_consts,
             lifetimes,
             where_predicates: where_predicates.into_boxed_slice(),
+            types_map: generics_types_map,
+        })
+    }
+}
+
+/// Copies a `TypeRef` from a `TypesMap` (accompanied with `TypesSourceMap`) into another `TypesMap`
+/// (and `TypesSourceMap`).
+fn copy_type_ref(
+    type_ref: TypeRefId,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> TypeRefId {
+    let result = match &from[type_ref] {
+        TypeRef::Fn(fn_) => {
+            let params = fn_.params().iter().map(|(name, param_type)| {
+                (name.clone(), copy_type_ref(*param_type, from, from_source_map, to, to_source_map))
+            });
+            TypeRef::Fn(FnType::new(fn_.is_varargs(), fn_.is_unsafe(), fn_.abi().clone(), params))
         }
+        TypeRef::Tuple(types) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+            types.iter().map(|&t| copy_type_ref(t, from, from_source_map, to, to_source_map)),
+        )),
+        &TypeRef::RawPtr(type_ref, mutbl) => TypeRef::RawPtr(
+            copy_type_ref(type_ref, from, from_source_map, to, to_source_map),
+            mutbl,
+        ),
+        TypeRef::Reference(ref_) => TypeRef::Reference(Box::new(RefType {
+            ty: copy_type_ref(ref_.ty, from, from_source_map, to, to_source_map),
+            lifetime: ref_.lifetime.clone(),
+            mutability: ref_.mutability,
+        })),
+        TypeRef::Array(array) => TypeRef::Array(Box::new(ArrayType {
+            ty: copy_type_ref(array.ty, from, from_source_map, to, to_source_map),
+            len: array.len.clone(),
+        })),
+        &TypeRef::Slice(type_ref) => {
+            TypeRef::Slice(copy_type_ref(type_ref, from, from_source_map, to, to_source_map))
+        }
+        TypeRef::ImplTrait(bounds) => TypeRef::ImplTrait(ThinVec::from_iter(copy_type_bounds(
+            bounds,
+            from,
+            from_source_map,
+            to,
+            to_source_map,
+        ))),
+        TypeRef::DynTrait(bounds) => TypeRef::DynTrait(ThinVec::from_iter(copy_type_bounds(
+            bounds,
+            from,
+            from_source_map,
+            to,
+            to_source_map,
+        ))),
+        TypeRef::Path(path) => {
+            TypeRef::Path(copy_path(path, from, from_source_map, to, to_source_map))
+        }
+        TypeRef::Never => TypeRef::Never,
+        TypeRef::Placeholder => TypeRef::Placeholder,
+        TypeRef::Macro(macro_call) => TypeRef::Macro(*macro_call),
+        TypeRef::Error => TypeRef::Error,
+    };
+    let id = to.types.alloc(result);
+    if let Some(&ptr) = from_source_map.types_map_back.get(id) {
+        to_source_map.types_map_back.insert(id, ptr);
+    }
+    id
+}
+
+fn copy_path(
+    path: &Path,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> Path {
+    match path {
+        Path::BarePath(mod_path) => Path::BarePath(mod_path.clone()),
+        Path::Normal(path) => {
+            let type_anchor = path
+                .type_anchor()
+                .map(|type_ref| copy_type_ref(type_ref, from, from_source_map, to, to_source_map));
+            let mod_path = path.mod_path().clone();
+            let generic_args = path.generic_args().iter().map(|generic_args| {
+                copy_generic_args(generic_args, from, from_source_map, to, to_source_map)
+            });
+            Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args))
+        }
+        Path::LangItem(lang_item, name) => Path::LangItem(*lang_item, name.clone()),
+    }
+}
+
+fn copy_generic_args(
+    generic_args: &Option<GenericArgs>,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> Option<GenericArgs> {
+    generic_args.as_ref().map(|generic_args| {
+        let args = generic_args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                &GenericArg::Type(ty) => {
+                    GenericArg::Type(copy_type_ref(ty, from, from_source_map, to, to_source_map))
+                }
+                GenericArg::Lifetime(lifetime) => GenericArg::Lifetime(lifetime.clone()),
+                GenericArg::Const(konst) => GenericArg::Const(konst.clone()),
+            })
+            .collect();
+        let bindings = generic_args
+            .bindings
+            .iter()
+            .map(|binding| {
+                let name = binding.name.clone();
+                let args =
+                    copy_generic_args(&binding.args, from, from_source_map, to, to_source_map);
+                let type_ref = binding.type_ref.map(|type_ref| {
+                    copy_type_ref(type_ref, from, from_source_map, to, to_source_map)
+                });
+                let bounds =
+                    copy_type_bounds(&binding.bounds, from, from_source_map, to, to_source_map)
+                        .collect();
+                AssociatedTypeBinding { name, args, type_ref, bounds }
+            })
+            .collect();
+        GenericArgs {
+            args,
+            has_self_type: generic_args.has_self_type,
+            bindings,
+            desugared_from_fn: generic_args.desugared_from_fn,
+        }
+    })
+}
+
+fn copy_type_bounds<'a>(
+    bounds: &'a [TypeBound],
+    from: &'a TypesMap,
+    from_source_map: &'a TypesSourceMap,
+    to: &'a mut TypesMap,
+    to_source_map: &'a mut TypesSourceMap,
+) -> impl stdx::thin_vec::TrustedLen<Item = TypeBound> + 'a {
+    bounds.iter().map(|bound| copy_type_bound(bound, from, from_source_map, to, to_source_map))
+}
+
+fn copy_type_bound(
+    bound: &TypeBound,
+    from: &TypesMap,
+    from_source_map: &TypesSourceMap,
+    to: &mut TypesMap,
+    to_source_map: &mut TypesSourceMap,
+) -> TypeBound {
+    match bound {
+        TypeBound::Path(path, modifier) => {
+            TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier)
+        }
+        TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime(
+            lifetimes.clone(),
+            copy_path(path, from, from_source_map, to, to_source_map),
+        ),
+        TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()),
+        TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()),
+        TypeBound::Error => TypeBound::Error,
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index d9358a28822..85963469430 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -17,16 +17,17 @@ pub mod type_ref;
 
 use std::fmt;
 
-use hir_expand::name::Name;
-use intern::{Interned, Symbol};
+use hir_expand::{name::Name, MacroDefId};
+use intern::Symbol;
 use la_arena::{Idx, RawIdx};
 use rustc_apfloat::ieee::{Half as f16, Quad as f128};
 use syntax::ast;
+use type_ref::TypeRefId;
 
 use crate::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     path::{GenericArgs, Path},
-    type_ref::{Mutability, Rawness, TypeRef},
+    type_ref::{Mutability, Rawness},
     BlockId, ConstBlockId,
 };
 
@@ -48,6 +49,22 @@ pub enum ExprOrPatId {
     ExprId(ExprId),
     PatId(PatId),
 }
+
+impl ExprOrPatId {
+    pub fn as_expr(self) -> Option<ExprId> {
+        match self {
+            Self::ExprId(v) => Some(v),
+            _ => None,
+        }
+    }
+
+    pub fn as_pat(self) -> Option<PatId> {
+        match self {
+            Self::PatId(v) => Some(v),
+            _ => None,
+        }
+    }
+}
 stdx::impl_from!(ExprId, PatId for ExprOrPatId);
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -204,7 +221,6 @@ pub enum Expr {
     Call {
         callee: ExprId,
         args: Box<[ExprId]>,
-        is_assignee_expr: bool,
     },
     MethodCall {
         receiver: ExprId,
@@ -239,8 +255,6 @@ pub enum Expr {
         path: Option<Box<Path>>,
         fields: Box<[RecordLitField]>,
         spread: Option<ExprId>,
-        ellipsis: bool,
-        is_assignee_expr: bool,
     },
     Field {
         expr: ExprId,
@@ -251,7 +265,7 @@ pub enum Expr {
     },
     Cast {
         expr: ExprId,
-        type_ref: Interned<TypeRef>,
+        type_ref: TypeRefId,
     },
     Ref {
         expr: ExprId,
@@ -265,11 +279,17 @@ pub enum Expr {
         expr: ExprId,
         op: UnaryOp,
     },
+    /// `op` cannot be bare `=` (but can be `op=`), these are lowered to `Assignment` instead.
     BinaryOp {
         lhs: ExprId,
         rhs: ExprId,
         op: Option<BinaryOp>,
     },
+    // Assignments need a special treatment because of destructuring assignment.
+    Assignment {
+        target: PatId,
+        value: ExprId,
+    },
     Range {
         lhs: Option<ExprId>,
         rhs: Option<ExprId>,
@@ -278,19 +298,17 @@ pub enum Expr {
     Index {
         base: ExprId,
         index: ExprId,
-        is_assignee_expr: bool,
     },
     Closure {
         args: Box<[PatId]>,
-        arg_types: Box<[Option<Interned<TypeRef>>]>,
-        ret_type: Option<Interned<TypeRef>>,
+        arg_types: Box<[Option<TypeRefId>]>,
+        ret_type: Option<TypeRefId>,
         body: ExprId,
         closure_kind: ClosureKind,
         capture_by: CaptureBy,
     },
     Tuple {
         exprs: Box<[ExprId]>,
-        is_assignee_expr: bool,
     },
     Array(Array),
     Literal(Literal),
@@ -301,7 +319,7 @@ pub enum Expr {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct OffsetOf {
-    pub container: Interned<TypeRef>,
+    pub container: TypeRefId,
     pub fields: Box<[Name]>,
 }
 
@@ -446,7 +464,7 @@ pub enum Movability {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum Array {
-    ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
+    ElementList { elements: Box<[ExprId]> },
     Repeat { initializer: ExprId, repeat: ExprId },
 }
 
@@ -467,7 +485,7 @@ pub struct RecordLitField {
 pub enum Statement {
     Let {
         pat: PatId,
-        type_ref: Option<Interned<TypeRef>>,
+        type_ref: Option<TypeRefId>,
         initializer: Option<ExprId>,
         else_branch: Option<ExprId>,
     },
@@ -475,133 +493,13 @@ pub enum Statement {
         expr: ExprId,
         has_semi: bool,
     },
-    // At the moment, we only use this to figure out if a return expression
-    // is really the last statement of a block. See #16566
-    Item,
+    Item(Item),
 }
 
-impl Expr {
-    pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
-        match self {
-            Expr::Missing => {}
-            Expr::Path(_) | Expr::OffsetOf(_) => {}
-            Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
-                AsmOperand::In { expr, .. }
-                | AsmOperand::Out { expr: Some(expr), .. }
-                | AsmOperand::InOut { expr, .. } => f(*expr),
-                AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                    f(*in_expr);
-                    if let Some(out_expr) = out_expr {
-                        f(*out_expr);
-                    }
-                }
-                AsmOperand::Out { expr: None, .. }
-                | AsmOperand::Const(_)
-                | AsmOperand::Label(_)
-                | AsmOperand::Sym(_) => (),
-            }),
-            Expr::If { condition, then_branch, else_branch } => {
-                f(*condition);
-                f(*then_branch);
-                if let &Some(else_branch) = else_branch {
-                    f(else_branch);
-                }
-            }
-            Expr::Let { expr, .. } => {
-                f(*expr);
-            }
-            Expr::Const(_) => (),
-            Expr::Block { statements, tail, .. }
-            | Expr::Unsafe { statements, tail, .. }
-            | Expr::Async { statements, tail, .. } => {
-                for stmt in statements.iter() {
-                    match stmt {
-                        Statement::Let { initializer, else_branch, .. } => {
-                            if let &Some(expr) = initializer {
-                                f(expr);
-                            }
-                            if let &Some(expr) = else_branch {
-                                f(expr);
-                            }
-                        }
-                        Statement::Expr { expr: expression, .. } => f(*expression),
-                        Statement::Item => (),
-                    }
-                }
-                if let &Some(expr) = tail {
-                    f(expr);
-                }
-            }
-            Expr::Loop { body, .. } => f(*body),
-            Expr::Call { callee, args, .. } => {
-                f(*callee);
-                args.iter().copied().for_each(f);
-            }
-            Expr::MethodCall { receiver, args, .. } => {
-                f(*receiver);
-                args.iter().copied().for_each(f);
-            }
-            Expr::Match { expr, arms } => {
-                f(*expr);
-                arms.iter().map(|arm| arm.expr).for_each(f);
-            }
-            Expr::Continue { .. } => {}
-            Expr::Break { expr, .. }
-            | Expr::Return { expr }
-            | Expr::Yield { expr }
-            | Expr::Yeet { expr } => {
-                if let &Some(expr) = expr {
-                    f(expr);
-                }
-            }
-            Expr::Become { expr } => f(*expr),
-            Expr::RecordLit { fields, spread, .. } => {
-                for field in fields.iter() {
-                    f(field.expr);
-                }
-                if let &Some(expr) = spread {
-                    f(expr);
-                }
-            }
-            Expr::Closure { body, .. } => {
-                f(*body);
-            }
-            Expr::BinaryOp { lhs, rhs, .. } => {
-                f(*lhs);
-                f(*rhs);
-            }
-            Expr::Range { lhs, rhs, .. } => {
-                if let &Some(lhs) = rhs {
-                    f(lhs);
-                }
-                if let &Some(rhs) = lhs {
-                    f(rhs);
-                }
-            }
-            Expr::Index { base, index, .. } => {
-                f(*base);
-                f(*index);
-            }
-            Expr::Field { expr, .. }
-            | Expr::Await { expr }
-            | Expr::Cast { expr, .. }
-            | Expr::Ref { expr, .. }
-            | Expr::UnaryOp { expr, .. }
-            | Expr::Box { expr } => {
-                f(*expr);
-            }
-            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
-            Expr::Array(a) => match a {
-                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
-                Array::Repeat { initializer, repeat } => {
-                    f(*initializer);
-                    f(*repeat)
-                }
-            },
-            Expr::Literal(_) => {}
-            Expr::Underscore => {}
-        }
-    }
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Item {
+    MacroDef(Box<MacroDefId>),
+    Other,
 }
 
 /// Explicit binding annotations given in the HIR for a binding. Note
@@ -665,18 +563,49 @@ pub struct RecordFieldPat {
 pub enum Pat {
     Missing,
     Wild,
-    Tuple { args: Box<[PatId]>, ellipsis: Option<u32> },
+    Tuple {
+        args: Box<[PatId]>,
+        ellipsis: Option<u32>,
+    },
     Or(Box<[PatId]>),
-    Record { path: Option<Box<Path>>, args: Box<[RecordFieldPat]>, ellipsis: bool },
-    Range { start: Option<Box<LiteralOrConst>>, end: Option<Box<LiteralOrConst>> },
-    Slice { prefix: Box<[PatId]>, slice: Option<PatId>, suffix: Box<[PatId]> },
-    Path(Box<Path>),
+    Record {
+        path: Option<Box<Path>>,
+        args: Box<[RecordFieldPat]>,
+        ellipsis: bool,
+    },
+    Range {
+        start: Option<Box<LiteralOrConst>>,
+        end: Option<Box<LiteralOrConst>>,
+    },
+    Slice {
+        prefix: Box<[PatId]>,
+        slice: Option<PatId>,
+        suffix: Box<[PatId]>,
+    },
+    /// This might refer to a variable if a single segment path (specifically, on destructuring assignment).
+    Path(Path),
     Lit(ExprId),
-    Bind { id: BindingId, subpat: Option<PatId> },
-    TupleStruct { path: Option<Box<Path>>, args: Box<[PatId]>, ellipsis: Option<u32> },
-    Ref { pat: PatId, mutability: Mutability },
-    Box { inner: PatId },
+    Bind {
+        id: BindingId,
+        subpat: Option<PatId>,
+    },
+    TupleStruct {
+        path: Option<Box<Path>>,
+        args: Box<[PatId]>,
+        ellipsis: Option<u32>,
+    },
+    Ref {
+        pat: PatId,
+        mutability: Mutability,
+    },
+    Box {
+        inner: PatId,
+    },
     ConstBlock(ExprId),
+    /// An expression inside a pattern. That can only occur inside assignments.
+    ///
+    /// E.g. in `(a, *b) = (1, &mut 2)`, `*b` is an expression.
+    Expr(ExprId),
 }
 
 impl Pat {
@@ -687,7 +616,8 @@ impl Pat {
             | Pat::Path(..)
             | Pat::ConstBlock(..)
             | Pat::Wild
-            | Pat::Missing => {}
+            | Pat::Missing
+            | Pat::Expr(_) => {}
             Pat::Bind { subpat, .. } => {
                 subpat.iter().copied().for_each(f);
             }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
index b74cd90f693..2582340c0f8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs
@@ -2,22 +2,27 @@
 //! be directly created from an ast::TypeRef, without further queries.
 
 use core::fmt;
-use std::fmt::Write;
+use std::{fmt::Write, ops::Index};
 
 use hir_expand::{
     db::ExpandDatabase,
     name::{AsName, Name},
-    AstId,
+    AstId, InFile,
 };
-use intern::{sym, Interned, Symbol};
+use intern::{sym, Symbol};
+use la_arena::{Arena, ArenaMap, Idx};
 use span::Edition;
-use syntax::ast::{self, HasGenericArgs, HasName, IsString};
+use stdx::thin_vec::{thin_vec_with_header_struct, EmptyOptimizedThinVec, ThinVec};
+use syntax::{
+    ast::{self, HasGenericArgs, HasName, IsString},
+    AstPtr,
+};
 
 use crate::{
     builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
     hir::Literal,
     lower::LowerCtx,
-    path::Path,
+    path::{GenericArg, Path},
 };
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
@@ -104,35 +109,90 @@ impl TraitRef {
     }
 }
 
+thin_vec_with_header_struct! {
+    pub new(pub(crate)) struct FnType, FnTypeHeader {
+        pub params: [(Option<Name>, TypeRefId)],
+        pub is_varargs: bool,
+        pub is_unsafe: bool,
+        pub abi: Option<Symbol>; ref,
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct ArrayType {
+    pub ty: TypeRefId,
+    // FIXME: This should be Ast<ConstArg>
+    pub len: ConstRef,
+}
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct RefType {
+    pub ty: TypeRefId,
+    pub lifetime: Option<LifetimeRef>,
+    pub mutability: Mutability,
+}
+
 /// Compare ty::Ty
-///
-/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
-/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
-/// does not seem to save any noticeable amount of memory.
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum TypeRef {
     Never,
     Placeholder,
-    Tuple(Vec<TypeRef>),
+    Tuple(EmptyOptimizedThinVec<TypeRefId>),
     Path(Path),
-    RawPtr(Box<TypeRef>, Mutability),
-    Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
-    // FIXME: This should be Array(Box<TypeRef>, Ast<ConstArg>),
-    Array(Box<TypeRef>, ConstRef),
-    Slice(Box<TypeRef>),
+    RawPtr(TypeRefId, Mutability),
+    Reference(Box<RefType>),
+    Array(Box<ArrayType>),
+    Slice(TypeRefId),
     /// A fn pointer. Last element of the vector is the return type.
-    Fn(
-        Box<[(Option<Name>, TypeRef)]>,
-        bool,           /*varargs*/
-        bool,           /*is_unsafe*/
-        Option<Symbol>, /* abi */
-    ),
-    ImplTrait(Vec<Interned<TypeBound>>),
-    DynTrait(Vec<Interned<TypeBound>>),
+    Fn(FnType),
+    ImplTrait(ThinVec<TypeBound>),
+    DynTrait(ThinVec<TypeBound>),
     Macro(AstId<ast::MacroCall>),
     Error,
 }
 
+#[cfg(target_arch = "x86_64")]
+const _: () = assert!(size_of::<TypeRef>() == 16);
+
+pub type TypeRefId = Idx<TypeRef>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesMap {
+    pub(crate) types: Arena<TypeRef>,
+}
+
+impl TypesMap {
+    pub const EMPTY: &TypesMap = &TypesMap { types: Arena::new() };
+
+    pub(crate) fn shrink_to_fit(&mut self) {
+        let TypesMap { types } = self;
+        types.shrink_to_fit();
+    }
+}
+
+impl Index<TypeRefId> for TypesMap {
+    type Output = TypeRef;
+
+    fn index(&self, index: TypeRefId) -> &Self::Output {
+        &self.types[index]
+    }
+}
+
+pub type TypePtr = AstPtr<ast::Type>;
+pub type TypeSource = InFile<TypePtr>;
+
+#[derive(Default, Clone, PartialEq, Eq, Debug, Hash)]
+pub struct TypesSourceMap {
+    pub(crate) types_map_back: ArenaMap<TypeRefId, TypeSource>,
+}
+
+impl TypesSourceMap {
+    pub(crate) fn shrink_to_fit(&mut self) {
+        let TypesSourceMap { types_map_back } = self;
+        types_map_back.shrink_to_fit();
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub struct LifetimeRef {
     pub name: Name,
@@ -157,12 +217,22 @@ pub enum TypeBound {
     Path(Path, TraitBoundModifier),
     ForLifetime(Box<[Name]>, Path),
     Lifetime(LifetimeRef),
+    Use(Box<[UseArgRef]>),
     Error,
 }
 
+#[cfg(target_pointer_width = "64")]
+const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()];
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub enum UseArgRef {
+    Name(Name),
+    Lifetime(LifetimeRef),
+}
+
 /// A modifier on a bound, currently this is only used for `?Sized`, where the
 /// modifier is `Maybe`.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub enum TraitBoundModifier {
     None,
     Maybe,
@@ -170,12 +240,12 @@ pub enum TraitBoundModifier {
 
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
-    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> Self {
-        match node {
-            ast::Type::ParenType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
-            ast::Type::TupleType(inner) => {
-                TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect())
-            }
+    pub fn from_ast(ctx: &LowerCtx<'_>, node: ast::Type) -> TypeRefId {
+        let ty = match &node {
+            ast::Type::ParenType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
+            ast::Type::TupleType(inner) => TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(
+                Vec::from_iter(inner.fields().map(|it| TypeRef::from_ast(ctx, it))),
+            )),
             ast::Type::NeverType(..) => TypeRef::Never,
             ast::Type::PathType(inner) => {
                 // FIXME: Use `Path::from_src`
@@ -188,20 +258,21 @@ impl TypeRef {
             ast::Type::PtrType(inner) => {
                 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
-                TypeRef::RawPtr(Box::new(inner_ty), mutability)
+                TypeRef::RawPtr(inner_ty, mutability)
             }
             ast::Type::ArrayType(inner) => {
                 let len = ConstRef::from_const_arg(ctx, inner.const_arg());
-                TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
-            }
-            ast::Type::SliceType(inner) => {
-                TypeRef::Slice(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())))
+                TypeRef::Array(Box::new(ArrayType {
+                    ty: TypeRef::from_ast_opt(ctx, inner.ty()),
+                    len,
+                }))
             }
+            ast::Type::SliceType(inner) => TypeRef::Slice(TypeRef::from_ast_opt(ctx, inner.ty())),
             ast::Type::RefType(inner) => {
                 let inner_ty = TypeRef::from_ast_opt(ctx, inner.ty());
                 let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
-                TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
+                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
             }
             ast::Type::InferType(_inner) => TypeRef::Placeholder,
             ast::Type::FnPtrType(inner) => {
@@ -209,7 +280,7 @@ impl TypeRef {
                     .ret_type()
                     .and_then(|rt| rt.ty())
                     .map(|it| TypeRef::from_ast(ctx, it))
-                    .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
+                    .unwrap_or_else(|| ctx.alloc_type_ref_desugared(TypeRef::unit()));
                 let mut is_varargs = false;
                 let mut params = if let Some(pl) = inner.param_list() {
                     if let Some(param) = pl.params().last() {
@@ -241,10 +312,10 @@ impl TypeRef {
 
                 let abi = inner.abi().map(lower_abi);
                 params.push((None, ret_ty));
-                TypeRef::Fn(params.into(), is_varargs, inner.unsafe_token().is_some(), abi)
+                TypeRef::Fn(FnType::new(is_varargs, inner.unsafe_token().is_some(), abi, params))
             }
             // for types are close enough for our purposes to the inner type for now...
-            ast::Type::ForType(inner) => TypeRef::from_ast_opt(ctx, inner.ty()),
+            ast::Type::ForType(inner) => return TypeRef::from_ast_opt(ctx, inner.ty()),
             ast::Type::ImplTraitType(inner) => {
                 if ctx.outer_impl_trait() {
                     // Disallow nested impl traits
@@ -261,74 +332,74 @@ impl TypeRef {
                 Some(mc) => TypeRef::Macro(ctx.ast_id(&mc)),
                 None => TypeRef::Error,
             },
-        }
+        };
+        ctx.alloc_type_ref(ty, AstPtr::new(&node))
     }
 
-    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> Self {
+    pub(crate) fn from_ast_opt(ctx: &LowerCtx<'_>, node: Option<ast::Type>) -> TypeRefId {
         match node {
             Some(node) => TypeRef::from_ast(ctx, node),
-            None => TypeRef::Error,
+            None => ctx.alloc_error_type(),
         }
     }
 
     pub(crate) fn unit() -> TypeRef {
-        TypeRef::Tuple(Vec::new())
+        TypeRef::Tuple(EmptyOptimizedThinVec::empty())
     }
 
-    pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
-        go(self, f);
+    pub fn walk(this: TypeRefId, map: &TypesMap, f: &mut impl FnMut(&TypeRef)) {
+        go(this, f, map);
 
-        fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
+        fn go(type_ref: TypeRefId, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
+            let type_ref = &map[type_ref];
             f(type_ref);
             match type_ref {
-                TypeRef::Fn(params, _, _, _) => {
-                    params.iter().for_each(|(_, param_type)| go(param_type, f))
+                TypeRef::Fn(fn_) => {
+                    fn_.params().iter().for_each(|&(_, param_type)| go(param_type, f, map))
                 }
-                TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
-                TypeRef::RawPtr(type_ref, _)
-                | TypeRef::Reference(type_ref, ..)
-                | TypeRef::Array(type_ref, _)
-                | TypeRef::Slice(type_ref) => go(type_ref, f),
+                TypeRef::Tuple(types) => types.iter().for_each(|&t| go(t, f, map)),
+                TypeRef::RawPtr(type_ref, _) | TypeRef::Slice(type_ref) => go(*type_ref, f, map),
+                TypeRef::Reference(it) => go(it.ty, f, map),
+                TypeRef::Array(it) => go(it.ty, f, map),
                 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
                     for bound in bounds {
-                        match bound.as_ref() {
+                        match bound {
                             TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                go_path(path, f)
+                                go_path(path, f, map)
                             }
-                            TypeBound::Lifetime(_) | TypeBound::Error => (),
+                            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                         }
                     }
                 }
-                TypeRef::Path(path) => go_path(path, f),
+                TypeRef::Path(path) => go_path(path, f, map),
                 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
             };
         }
 
-        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
+        fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef), map: &TypesMap) {
             if let Some(type_ref) = path.type_anchor() {
-                go(type_ref, f);
+                go(type_ref, f, map);
             }
             for segment in path.segments().iter() {
                 if let Some(args_and_bindings) = segment.args_and_bindings {
                     for arg in args_and_bindings.args.iter() {
                         match arg {
-                            crate::path::GenericArg::Type(type_ref) => {
-                                go(type_ref, f);
+                            GenericArg::Type(type_ref) => {
+                                go(*type_ref, f, map);
                             }
-                            crate::path::GenericArg::Const(_)
-                            | crate::path::GenericArg::Lifetime(_) => {}
+                            GenericArg::Const(_) | GenericArg::Lifetime(_) => {}
                         }
                     }
                     for binding in args_and_bindings.bindings.iter() {
-                        if let Some(type_ref) = &binding.type_ref {
-                            go(type_ref, f);
+                        if let Some(type_ref) = binding.type_ref {
+                            go(type_ref, f, map);
                         }
                         for bound in binding.bounds.iter() {
-                            match bound.as_ref() {
+                            match bound {
                                 TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => {
-                                    go_path(path, f)
+                                    go_path(path, f, map)
                                 }
-                                TypeBound::Lifetime(_) | TypeBound::Error => (),
+                                TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (),
                             }
                         }
                     }
@@ -341,11 +412,13 @@ impl TypeRef {
 pub(crate) fn type_bounds_from_ast(
     lower_ctx: &LowerCtx<'_>,
     type_bounds_opt: Option<ast::TypeBoundList>,
-) -> Vec<Interned<TypeBound>> {
+) -> ThinVec<TypeBound> {
     if let Some(type_bounds) = type_bounds_opt {
-        type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
+        ThinVec::from_iter(Vec::from_iter(
+            type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)),
+        ))
     } else {
-        vec![]
+        ThinVec::from_iter([])
     }
 }
 
@@ -380,7 +453,16 @@ impl TypeBound {
                     None => TypeBound::Error,
                 }
             }
-            ast::TypeBoundKind::Use(_) => TypeBound::Error,
+            ast::TypeBoundKind::Use(gal) => TypeBound::Use(
+                gal.use_bound_generic_args()
+                    .map(|p| match p {
+                        ast::UseBoundGenericArg::Lifetime(l) => {
+                            UseArgRef::Lifetime(LifetimeRef::new(&l))
+                        }
+                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
+                    })
+                    .collect(),
+            ),
             ast::TypeBoundKind::Lifetime(lifetime) => {
                 TypeBound::Lifetime(LifetimeRef::new(&lifetime))
             }
@@ -391,7 +473,7 @@ impl TypeBound {
         match self {
             TypeBound::Path(p, m) => Some((p, m)),
             TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)),
-            TypeBound::Lifetime(_) | TypeBound::Error => None,
+            TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None,
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 7cb833fdce7..b5bf2feb82a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -61,7 +61,7 @@ use crate::{
     db::DefDatabase,
     generics::GenericParams,
     path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
-    type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
+    type_ref::{Mutability, TraitRef, TypeBound, TypeRefId, TypesMap, TypesSourceMap},
     visibility::{RawVisibility, VisibilityExplicitness},
     BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
 };
@@ -100,14 +100,20 @@ pub struct ItemTree {
 
 impl ItemTree {
     pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
-        let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+        db.file_item_tree_with_source_map(file_id).0
+    }
 
-        let syntax = db.parse_or_expand(file_id);
+    pub(crate) fn file_item_tree_with_source_map_query(
+        db: &dyn DefDatabase,
+        file_id: HirFileId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+        let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
+        static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
 
         let ctx = lower::Ctx::new(db, file_id);
+        let syntax = db.parse_or_expand(file_id);
         let mut top_attrs = None;
-        let mut item_tree = match_ast! {
+        let (mut item_tree, source_maps) = match_ast! {
             match syntax {
                 ast::SourceFile(file) => {
                     top_attrs = Some(RawAttrs::new(db.upcast(), &file, ctx.span_map()));
@@ -137,42 +143,55 @@ impl ItemTree {
         {
             EMPTY
                 .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+                    (
+                        Arc::new(ItemTree {
+                            top_level: SmallVec::new_const(),
+                            attrs: FxHashMap::default(),
+                            data: None,
+                        }),
+                        Arc::default(),
+                    )
                 })
                 .clone()
         } else {
             item_tree.shrink_to_fit();
-            Arc::new(item_tree)
+            (Arc::new(item_tree), Arc::new(source_maps))
         }
     }
 
     pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+        db.block_item_tree_with_source_map(block).0
+    }
+
+    pub(crate) fn block_item_tree_with_source_map_query(
+        db: &dyn DefDatabase,
+        block: BlockId,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
         let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+        static EMPTY: OnceLock<(Arc<ItemTree>, Arc<ItemTreeSourceMaps>)> = OnceLock::new();
 
         let loc = block.lookup(db);
         let block = loc.ast_id.to_node(db.upcast());
 
         let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
-        let mut item_tree = ctx.lower_block(&block);
+        let (mut item_tree, source_maps) = ctx.lower_block(&block);
         if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
         {
             EMPTY
                 .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+                    (
+                        Arc::new(ItemTree {
+                            top_level: SmallVec::new_const(),
+                            attrs: FxHashMap::default(),
+                            data: None,
+                        }),
+                        Arc::default(),
+                    )
                 })
                 .clone()
         } else {
             item_tree.shrink_to_fit();
-            Arc::new(item_tree)
+            (Arc::new(item_tree), Arc::new(source_maps))
         }
     }
 
@@ -309,6 +328,160 @@ struct ItemTreeData {
     vis: ItemVisibilities,
 }
 
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct ItemTreeSourceMaps {
+    all_concatenated: Box<[TypesSourceMap]>,
+    structs_offset: u32,
+    unions_offset: u32,
+    enum_generics_offset: u32,
+    variants_offset: u32,
+    consts_offset: u32,
+    statics_offset: u32,
+    trait_generics_offset: u32,
+    trait_alias_generics_offset: u32,
+    impls_offset: u32,
+    type_aliases_offset: u32,
+}
+
+#[derive(Clone, Copy)]
+pub struct GenericItemSourceMap<'a>(&'a [TypesSourceMap; 2]);
+
+impl<'a> GenericItemSourceMap<'a> {
+    #[inline]
+    pub fn item(self) -> &'a TypesSourceMap {
+        &self.0[0]
+    }
+
+    #[inline]
+    pub fn generics(self) -> &'a TypesSourceMap {
+        &self.0[1]
+    }
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct GenericItemSourceMapBuilder {
+    pub item: TypesSourceMap,
+    pub generics: TypesSourceMap,
+}
+
+#[derive(Default, Debug, Eq, PartialEq)]
+struct ItemTreeSourceMapsBuilder {
+    functions: Vec<GenericItemSourceMapBuilder>,
+    structs: Vec<GenericItemSourceMapBuilder>,
+    unions: Vec<GenericItemSourceMapBuilder>,
+    enum_generics: Vec<TypesSourceMap>,
+    variants: Vec<TypesSourceMap>,
+    consts: Vec<TypesSourceMap>,
+    statics: Vec<TypesSourceMap>,
+    trait_generics: Vec<TypesSourceMap>,
+    trait_alias_generics: Vec<TypesSourceMap>,
+    impls: Vec<GenericItemSourceMapBuilder>,
+    type_aliases: Vec<GenericItemSourceMapBuilder>,
+}
+
+impl ItemTreeSourceMapsBuilder {
+    fn build(self) -> ItemTreeSourceMaps {
+        let ItemTreeSourceMapsBuilder {
+            functions,
+            structs,
+            unions,
+            enum_generics,
+            variants,
+            consts,
+            statics,
+            trait_generics,
+            trait_alias_generics,
+            impls,
+            type_aliases,
+        } = self;
+        let structs_offset = functions.len() as u32 * 2;
+        let unions_offset = structs_offset + (structs.len() as u32 * 2);
+        let enum_generics_offset = unions_offset + (unions.len() as u32 * 2);
+        let variants_offset = enum_generics_offset + (enum_generics.len() as u32);
+        let consts_offset = variants_offset + (variants.len() as u32);
+        let statics_offset = consts_offset + (consts.len() as u32);
+        let trait_generics_offset = statics_offset + (statics.len() as u32);
+        let trait_alias_generics_offset = trait_generics_offset + (trait_generics.len() as u32);
+        let impls_offset = trait_alias_generics_offset + (trait_alias_generics.len() as u32);
+        let type_aliases_offset = impls_offset + (impls.len() as u32 * 2);
+        let all_concatenated = generics_concat(functions)
+            .chain(generics_concat(structs))
+            .chain(generics_concat(unions))
+            .chain(enum_generics)
+            .chain(variants)
+            .chain(consts)
+            .chain(statics)
+            .chain(trait_generics)
+            .chain(trait_alias_generics)
+            .chain(generics_concat(impls))
+            .chain(generics_concat(type_aliases))
+            .collect();
+        return ItemTreeSourceMaps {
+            all_concatenated,
+            structs_offset,
+            unions_offset,
+            enum_generics_offset,
+            variants_offset,
+            consts_offset,
+            statics_offset,
+            trait_generics_offset,
+            trait_alias_generics_offset,
+            impls_offset,
+            type_aliases_offset,
+        };
+
+        fn generics_concat(
+            source_maps: Vec<GenericItemSourceMapBuilder>,
+        ) -> impl Iterator<Item = TypesSourceMap> {
+            source_maps.into_iter().flat_map(|it| [it.item, it.generics])
+        }
+    }
+}
+
+impl ItemTreeSourceMaps {
+    #[inline]
+    fn generic_item(&self, offset: u32, index: u32) -> GenericItemSourceMap<'_> {
+        GenericItemSourceMap(
+            self.all_concatenated[(offset + (index * 2)) as usize..][..2].try_into().unwrap(),
+        )
+    }
+
+    #[inline]
+    fn non_generic_item(&self, offset: u32, index: u32) -> &TypesSourceMap {
+        &self.all_concatenated[(offset + index) as usize]
+    }
+
+    #[inline]
+    pub fn function(&self, index: FileItemTreeId<Function>) -> GenericItemSourceMap<'_> {
+        self.generic_item(0, index.0.into_raw().into_u32())
+    }
+}
+
+macro_rules! index_item_source_maps {
+    ( $( $name:ident; $field:ident[$tree_id:ident]; $fn:ident; $ret:ty, )* ) => {
+        impl ItemTreeSourceMaps {
+            $(
+                #[inline]
+                pub fn $name(&self, index: FileItemTreeId<$tree_id>) -> $ret {
+                    self.$fn(self.$field, index.0.into_raw().into_u32())
+                }
+            )*
+        }
+    };
+}
+index_item_source_maps! {
+    strukt; structs_offset[Struct]; generic_item; GenericItemSourceMap<'_>,
+    union; unions_offset[Union]; generic_item; GenericItemSourceMap<'_>,
+    enum_generic; enum_generics_offset[Enum]; non_generic_item; &TypesSourceMap,
+    variant; variants_offset[Variant]; non_generic_item; &TypesSourceMap,
+    konst; consts_offset[Const]; non_generic_item; &TypesSourceMap,
+    statik; statics_offset[Static]; non_generic_item; &TypesSourceMap,
+    trait_generic; trait_generics_offset[Trait]; non_generic_item; &TypesSourceMap,
+    trait_alias_generic; trait_alias_generics_offset[TraitAlias]; non_generic_item; &TypesSourceMap,
+    impl_; impls_offset[Impl]; generic_item; GenericItemSourceMap<'_>,
+    type_alias; type_aliases_offset[TypeAlias]; generic_item; GenericItemSourceMap<'_>,
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub enum AttrOwner {
     /// Attributes on an item.
@@ -364,7 +537,7 @@ pub trait ItemTreeNode: Clone {
     fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
 }
 pub trait GenericsItemTreeNode: ItemTreeNode {
-    fn generic_params(&self) -> &Interned<GenericParams>;
+    fn generic_params(&self) -> &Arc<GenericParams>;
 }
 
 pub struct FileItemTreeId<N>(Idx<N>);
@@ -429,6 +602,16 @@ impl TreeId {
         }
     }
 
+    pub fn item_tree_with_source_map(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+        match self.block {
+            Some(block) => db.block_item_tree_with_source_map(block),
+            None => db.file_item_tree_with_source_map(self.file),
+        }
+    }
+
     pub fn file_id(self) -> HirFileId {
         self.file
     }
@@ -461,6 +644,13 @@ impl<N> ItemTreeId<N> {
         self.tree.item_tree(db)
     }
 
+    pub fn item_tree_with_source_map(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (Arc<ItemTree>, Arc<ItemTreeSourceMaps>) {
+        self.tree.item_tree_with_source_map(db)
+    }
+
     pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
     where
         ItemTree: Index<FileItemTreeId<N>, Output = N>,
@@ -593,7 +783,7 @@ macro_rules! mod_items {
 
             $(
                 impl GenericsItemTreeNode for $typ {
-                    fn generic_params(&self) -> &Interned<GenericParams> {
+                    fn generic_params(&self) -> &Arc<GenericParams> {
                         &self.$generic_params
                     }
                 }
@@ -731,17 +921,18 @@ pub struct ExternBlock {
 pub struct Function {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub explicit_generic_params: Interned<GenericParams>,
+    pub explicit_generic_params: Arc<GenericParams>,
     pub abi: Option<Symbol>,
     pub params: Box<[Param]>,
-    pub ret_type: Interned<TypeRef>,
+    pub ret_type: TypeRefId,
     pub ast_id: FileAstId<ast::Fn>,
+    pub types_map: Arc<TypesMap>,
     pub(crate) flags: FnFlags,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Param {
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub type_ref: Option<TypeRefId>,
 }
 
 bitflags::bitflags! {
@@ -762,26 +953,28 @@ bitflags::bitflags! {
 pub struct Struct {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub fields: Box<[Field]>,
     pub shape: FieldsShape,
     pub ast_id: FileAstId<ast::Struct>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Union {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub fields: Box<[Field]>,
     pub ast_id: FileAstId<ast::Union>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Enum {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub variants: Range<FileItemTreeId<Variant>>,
     pub ast_id: FileAstId<ast::Enum>,
 }
@@ -792,6 +985,7 @@ pub struct Variant {
     pub fields: Box<[Field]>,
     pub shape: FieldsShape,
     pub ast_id: FileAstId<ast::Variant>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -805,7 +999,7 @@ pub enum FieldsShape {
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Field {
     pub name: Name,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub visibility: RawVisibilityId,
 }
 
@@ -814,9 +1008,10 @@ pub struct Const {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
     pub visibility: RawVisibilityId,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub ast_id: FileAstId<ast::Const>,
     pub has_body: bool,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -827,15 +1022,16 @@ pub struct Static {
     pub mutable: bool,
     pub has_safe_kw: bool,
     pub has_unsafe_kw: bool,
-    pub type_ref: Interned<TypeRef>,
+    pub type_ref: TypeRefId,
     pub ast_id: FileAstId<ast::Static>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Trait {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub is_auto: bool,
     pub is_unsafe: bool,
     pub items: Box<[AssocItem]>,
@@ -846,19 +1042,20 @@ pub struct Trait {
 pub struct TraitAlias {
     pub name: Name,
     pub visibility: RawVisibilityId,
-    pub generic_params: Interned<GenericParams>,
+    pub generic_params: Arc<GenericParams>,
     pub ast_id: FileAstId<ast::TraitAlias>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Impl {
-    pub generic_params: Interned<GenericParams>,
-    pub target_trait: Option<Interned<TraitRef>>,
-    pub self_ty: Interned<TypeRef>,
+    pub generic_params: Arc<GenericParams>,
+    pub target_trait: Option<TraitRef>,
+    pub self_ty: TypeRefId,
     pub is_negative: bool,
     pub is_unsafe: bool,
     pub items: Box<[AssocItem]>,
     pub ast_id: FileAstId<ast::Impl>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -866,10 +1063,11 @@ pub struct TypeAlias {
     pub name: Name,
     pub visibility: RawVisibilityId,
     /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
-    pub bounds: Box<[Interned<TypeBound>]>,
-    pub generic_params: Interned<GenericParams>,
-    pub type_ref: Option<Interned<TypeRef>>,
+    pub bounds: Box<[TypeBound]>,
+    pub generic_params: Arc<GenericParams>,
+    pub type_ref: Option<TypeRefId>,
     pub ast_id: FileAstId<ast::TypeAlias>,
+    pub types_map: Arc<TypesMap>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -968,6 +1166,11 @@ impl UseTree {
         self.expand_impl(None, &mut cb)
     }
 
+    /// The [`UseTreeKind`] of this `UseTree`.
+    pub fn kind(&self) -> &UseTreeKind {
+        &self.kind
+    }
+
     fn expand_impl(
         &self,
         prefix: Option<ModPath>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 431a7f66f40..bd17fce37b7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -1,12 +1,18 @@
 //! AST -> `ItemTree` lowering code.
 
-use std::collections::hash_map::Entry;
+use std::{cell::OnceCell, collections::hash_map::Entry};
 
-use hir_expand::{mod_path::path, name::AsName, span_map::SpanMapRef, HirFileId};
+use hir_expand::{
+    mod_path::path,
+    name::AsName,
+    span_map::{SpanMap, SpanMapRef},
+    HirFileId,
+};
 use intern::{sym, Symbol};
 use la_arena::Arena;
 use rustc_hash::FxHashMap;
 use span::{AstIdMap, SyntaxContextId};
+use stdx::thin_vec::ThinVec;
 use syntax::{
     ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
     AstNode,
@@ -18,14 +24,19 @@ use crate::{
     generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
     item_tree::{
         AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldParent,
-        FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, Impl,
-        ImportAlias, Interned, ItemTree, ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem,
+        FieldsShape, FileItemTreeId, FnFlags, Function, GenericArgs, GenericItemSourceMapBuilder,
+        GenericModItem, Idx, Impl, ImportAlias, Interned, ItemTree, ItemTreeData,
+        ItemTreeSourceMaps, ItemTreeSourceMapsBuilder, Macro2, MacroCall, MacroRules, Mod, ModItem,
         ModKind, ModPath, Mutability, Name, Param, Path, Range, RawAttrs, RawIdx, RawVisibilityId,
         Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
         Variant,
     },
+    lower::LowerCtx,
     path::AssociatedTypeBinding,
-    type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
+    type_ref::{
+        LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId,
+        TypesMap, TypesSourceMap,
+    },
     visibility::RawVisibility,
     LocalLifetimeParamId, LocalTypeOrConstParamId,
 };
@@ -40,7 +51,9 @@ pub(super) struct Ctx<'a> {
     source_ast_id_map: Arc<AstIdMap>,
     generic_param_attr_buffer:
         FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
-    body_ctx: crate::lower::LowerCtx<'a>,
+    span_map: OnceCell<SpanMap>,
+    file: HirFileId,
+    source_maps: ItemTreeSourceMapsBuilder,
 }
 
 impl<'a> Ctx<'a> {
@@ -50,22 +63,49 @@ impl<'a> Ctx<'a> {
             tree: ItemTree::default(),
             generic_param_attr_buffer: FxHashMap::default(),
             source_ast_id_map: db.ast_id_map(file),
-            body_ctx: crate::lower::LowerCtx::new(db, file),
+            file,
+            span_map: OnceCell::new(),
+            source_maps: ItemTreeSourceMapsBuilder::default(),
         }
     }
 
     pub(super) fn span_map(&self) -> SpanMapRef<'_> {
-        self.body_ctx.span_map()
+        self.span_map.get_or_init(|| self.db.span_map(self.file)).as_ref()
+    }
+
+    fn body_ctx<'b, 'c>(
+        &self,
+        types_map: &'b mut TypesMap,
+        types_source_map: &'b mut TypesSourceMap,
+    ) -> LowerCtx<'c>
+    where
+        'a: 'c,
+        'b: 'c,
+    {
+        // FIXME: This seems a bit wasteful that if `LowerCtx` will initialize the span map we won't benefit.
+        LowerCtx::with_span_map_cell(
+            self.db,
+            self.file,
+            self.span_map.clone(),
+            types_map,
+            types_source_map,
+        )
     }
 
-    pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
+    pub(super) fn lower_module_items(
+        mut self,
+        item_owner: &dyn HasModuleItem,
+    ) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
-    pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
+    pub(super) fn lower_macro_stmts(
+        mut self,
+        stmts: ast::MacroStmts,
+    ) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree.top_level = stmts
             .statements()
             .filter_map(|stmt| {
@@ -96,10 +136,10 @@ impl<'a> Ctx<'a> {
         }
 
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
-    pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
+    pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> (ItemTree, ItemTreeSourceMaps) {
         self.tree
             .attrs
             .insert(AttrOwner::TopLevel, RawAttrs::new(self.db.upcast(), block, self.span_map()));
@@ -125,7 +165,7 @@ impl<'a> Ctx<'a> {
         }
 
         assert!(self.generic_param_attr_buffer.is_empty());
-        self.tree
+        (self.tree, self.source_maps.build())
     }
 
     fn data(&mut self) -> &mut ItemTreeData {
@@ -144,7 +184,7 @@ impl<'a> Ctx<'a> {
             ast::Item::Module(ast) => self.lower_module(ast)?.into(),
             ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
             ast::Item::TraitAlias(ast) => self.lower_trait_alias(ast)?.into(),
-            ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
+            ast::Item::Impl(ast) => self.lower_impl(ast).into(),
             ast::Item::Use(ast) => self.lower_use(ast)?.into(),
             ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
             ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
@@ -159,12 +199,14 @@ impl<'a> Ctx<'a> {
     }
 
     fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
-        match self.tree.attrs.entry(item) {
-            Entry::Occupied(mut entry) => {
-                *entry.get_mut() = entry.get().merge(attrs);
-            }
-            Entry::Vacant(entry) => {
-                entry.insert(attrs);
+        if !attrs.is_empty() {
+            match self.tree.attrs.entry(item) {
+                Entry::Occupied(mut entry) => {
+                    *entry.get_mut() = entry.get().merge(attrs);
+                }
+                Entry::Vacant(entry) => {
+                    entry.insert(attrs);
+                }
             }
         }
     }
@@ -190,13 +232,31 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
-        let res = Struct { name, visibility, generic_params, fields, shape: kind, ast_id };
+        let (fields, kind, attrs) = self.lower_fields(&strukt.kind(), &body_ctx);
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, strukt);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Struct {
+            name,
+            visibility,
+            generic_params,
+            fields,
+            shape: kind,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().structs.alloc(res));
+        self.source_maps.structs.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -213,6 +273,7 @@ impl<'a> Ctx<'a> {
     fn lower_fields(
         &mut self,
         strukt_kind: &ast::StructKind,
+        body_ctx: &LowerCtx<'_>,
     ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
         match strukt_kind {
             ast::StructKind::Record(it) => {
@@ -220,7 +281,7 @@ impl<'a> Ctx<'a> {
                 let mut attrs = vec![];
 
                 for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_record_field(&field);
+                    let data = self.lower_record_field(&field, body_ctx);
                     fields.push(data);
                     let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
                     if !attr.is_empty() {
@@ -234,7 +295,7 @@ impl<'a> Ctx<'a> {
                 let mut attrs = vec![];
 
                 for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_tuple_field(i, &field);
+                    let data = self.lower_tuple_field(i, &field, body_ctx);
                     fields.push(data);
                     let attr = RawAttrs::new(self.db.upcast(), &field, self.span_map());
                     if !attr.is_empty() {
@@ -247,35 +308,59 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
+    fn lower_record_field(&mut self, field: &ast::RecordField, body_ctx: &LowerCtx<'_>) -> Field {
         let name = match field.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
         };
         let visibility = self.lower_visibility(field);
-        let type_ref = self.lower_type_ref_opt(field.ty());
+        let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
 
         Field { name, type_ref, visibility }
     }
 
-    fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
+    fn lower_tuple_field(
+        &mut self,
+        idx: usize,
+        field: &ast::TupleField,
+        body_ctx: &LowerCtx<'_>,
+    ) -> Field {
         let name = Name::new_tuple_field(idx);
         let visibility = self.lower_visibility(field);
-        let type_ref = self.lower_type_ref_opt(field.ty());
+        let type_ref = TypeRef::from_ast_opt(body_ctx, field.ty());
         Field { name, type_ref, visibility }
     }
 
     fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
         let (fields, _, attrs) = match union.record_field_list() {
-            Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
+            Some(record_field_list) => {
+                self.lower_fields(&StructKind::Record(record_field_list), &body_ctx)
+            }
             None => (Box::default(), FieldsShape::Record, Vec::default()),
         };
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
-        let res = Union { name, visibility, generic_params, fields, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, union);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Union {
+            name,
+            visibility,
+            generic_params,
+            fields,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().unions.alloc(res));
+        self.source_maps.unions.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -299,9 +384,11 @@ impl<'a> Ctx<'a> {
                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
             }
         };
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
         let id = id(self.data().enums.alloc(res));
+        self.source_maps.enum_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
@@ -320,14 +407,20 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = match variant.name() {
             Some(name) => name.as_name(),
             None => Name::missing(),
         };
-        let (fields, kind, attrs) = self.lower_fields(&variant.kind());
+        let (fields, kind, attrs) = self.lower_fields(&variant.kind(), &body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(variant);
-        let res = Variant { name, fields, shape: kind, ast_id };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Variant { name, fields, shape: kind, ast_id, types_map: Arc::new(types_map) };
         let id = self.data().variants.alloc(res);
+        self.source_maps.variants.push(types_source_map);
         for (idx, attr) in attrs {
             self.add_attrs(
                 AttrOwner::Field(
@@ -341,6 +434,10 @@ impl<'a> Ctx<'a> {
     }
 
     fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
 
@@ -360,27 +457,31 @@ impl<'a> Ctx<'a> {
                     RawAttrs::new(self.db.upcast(), &self_param, self.span_map()),
                 );
                 let self_type = match self_param.ty() {
-                    Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
+                    Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
                     None => {
-                        let self_type =
-                            TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into());
+                        let self_type = body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                            Name::new_symbol_root(sym::Self_.clone()).into(),
+                        ));
                         match self_param.kind() {
                             ast::SelfParamKind::Owned => self_type,
-                            ast::SelfParamKind::Ref => TypeRef::Reference(
-                                Box::new(self_type),
-                                self_param.lifetime().as_ref().map(LifetimeRef::new),
-                                Mutability::Shared,
+                            ast::SelfParamKind::Ref => body_ctx.alloc_type_ref_desugared(
+                                TypeRef::Reference(Box::new(RefType {
+                                    ty: self_type,
+                                    lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+                                    mutability: Mutability::Shared,
+                                })),
                             ),
-                            ast::SelfParamKind::MutRef => TypeRef::Reference(
-                                Box::new(self_type),
-                                self_param.lifetime().as_ref().map(LifetimeRef::new),
-                                Mutability::Mut,
+                            ast::SelfParamKind::MutRef => body_ctx.alloc_type_ref_desugared(
+                                TypeRef::Reference(Box::new(RefType {
+                                    ty: self_type,
+                                    lifetime: self_param.lifetime().as_ref().map(LifetimeRef::new),
+                                    mutability: Mutability::Mut,
+                                })),
                             ),
                         }
                     }
                 };
-                let type_ref = Interned::new(self_type);
-                params.push(Param { type_ref: Some(type_ref) });
+                params.push(Param { type_ref: Some(self_type) });
                 has_self_param = true;
             }
             for param in param_list.params() {
@@ -391,9 +492,8 @@ impl<'a> Ctx<'a> {
                         Param { type_ref: None }
                     }
                     None => {
-                        let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
-                        let ty = Interned::new(type_ref);
-                        Param { type_ref: Some(ty) }
+                        let type_ref = TypeRef::from_ast_opt(&body_ctx, param.ty());
+                        Param { type_ref: Some(type_ref) }
                     }
                 };
                 params.push(param);
@@ -402,17 +502,17 @@ impl<'a> Ctx<'a> {
 
         let ret_type = match func.ret_type() {
             Some(rt) => match rt.ty() {
-                Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
-                None if rt.thin_arrow_token().is_some() => TypeRef::Error,
-                None => TypeRef::unit(),
+                Some(type_ref) => TypeRef::from_ast(&body_ctx, type_ref),
+                None if rt.thin_arrow_token().is_some() => body_ctx.alloc_error_type(),
+                None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
             },
-            None => TypeRef::unit(),
+            None => body_ctx.alloc_type_ref_desugared(TypeRef::unit()),
         };
 
         let ret_type = if func.async_token().is_some() {
             let future_impl = desugar_future_path(ret_type);
-            let ty_bound = Interned::new(TypeBound::Path(future_impl, TraitBoundModifier::None));
-            TypeRef::ImplTrait(vec![ty_bound])
+            let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None);
+            body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound])))
         } else {
             ret_type
         };
@@ -447,18 +547,27 @@ impl<'a> Ctx<'a> {
             flags |= FnFlags::IS_VARARGS;
         }
 
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, func);
         let res = Function {
             name,
             visibility,
-            explicit_generic_params: self.lower_generic_params(HasImplicitSelf::No, func),
+            explicit_generic_params: generic_params,
             abi,
             params: params.into_boxed_slice(),
-            ret_type: Interned::new(ret_type),
+            ret_type,
             ast_id,
+            types_map: Arc::new(types_map),
             flags,
         };
 
         let id = id(self.data().functions.alloc(res));
+        self.source_maps.functions.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         for (idx, attr) in attrs {
             self.add_attrs(AttrOwner::Param(id, Idx::from_raw(RawIdx::from_u32(idx as u32))), attr);
         }
@@ -470,37 +579,82 @@ impl<'a> Ctx<'a> {
         &mut self,
         type_alias: &ast::TypeAlias,
     ) -> Option<FileItemTreeId<TypeAlias>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = type_alias.name()?.as_name();
-        let type_ref = type_alias.ty().map(|it| self.lower_type_ref(&it));
+        let type_ref = type_alias.ty().map(|it| TypeRef::from_ast(&body_ctx, it));
         let visibility = self.lower_visibility(type_alias);
-        let bounds = self.lower_type_bounds(type_alias);
+        let bounds = self.lower_type_bounds(type_alias, &body_ctx);
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
-        let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, type_alias);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = TypeAlias {
+            name,
+            visibility,
+            bounds,
+            generic_params,
+            type_ref,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().type_aliases.alloc(res));
+        self.source_maps.type_aliases.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
 
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = static_.name()?.as_name();
-        let type_ref = self.lower_type_ref_opt(static_.ty());
+        let type_ref = TypeRef::from_ast_opt(&body_ctx, static_.ty());
         let visibility = self.lower_visibility(static_);
         let mutable = static_.mut_token().is_some();
         let has_safe_kw = static_.safe_token().is_some();
         let has_unsafe_kw = static_.unsafe_token().is_some();
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res =
-            Static { name, visibility, mutable, type_ref, ast_id, has_safe_kw, has_unsafe_kw };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Static {
+            name,
+            visibility,
+            mutable,
+            type_ref,
+            ast_id,
+            has_safe_kw,
+            has_unsafe_kw,
+            types_map: Arc::new(types_map),
+        };
+        self.source_maps.statics.push(types_source_map);
         Some(id(self.data().statics.alloc(res)))
     }
 
     fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         let name = konst.name().map(|it| it.as_name());
-        let type_ref = self.lower_type_ref_opt(konst.ty());
+        let type_ref = TypeRef::from_ast_opt(&body_ctx, konst.ty());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
-        let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Const {
+            name,
+            visibility,
+            type_ref,
+            ast_id,
+            has_body: konst.body().is_some(),
+            types_map: Arc::new(types_map),
+        };
+        self.source_maps.consts.push(types_source_map);
         id(self.data().consts.alloc(res))
     }
 
@@ -539,10 +693,11 @@ impl<'a> Ctx<'a> {
             .filter_map(|item_node| self.lower_assoc_item(&item_node))
             .collect();
 
-        let generic_params =
+        let (generic_params, generics_source_map) =
             self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
         let id = id(self.data().traits.alloc(def));
+        self.source_maps.trait_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
@@ -554,24 +709,29 @@ impl<'a> Ctx<'a> {
         let name = trait_alias_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_alias_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
-        let generic_params = self.lower_generic_params(
+        let (generic_params, generics_source_map) = self.lower_generic_params(
             HasImplicitSelf::Yes(trait_alias_def.type_bound_list()),
             trait_alias_def,
         );
 
         let alias = TraitAlias { name, visibility, generic_params, ast_id };
         let id = id(self.data().trait_aliases.alloc(alias));
+        self.source_maps.trait_alias_generics.push(generics_source_map);
         self.write_generic_params_attributes(id.into());
         Some(id)
     }
 
-    fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
+    fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
+
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
-        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
+        let self_ty = TypeRef::from_ast_opt(&body_ctx, impl_def.self_ty());
+        let target_trait = impl_def.trait_().and_then(|tr| TraitRef::from_ast(&body_ctx, tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -584,12 +744,27 @@ impl<'a> Ctx<'a> {
             .collect();
         // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
         // type alias rather than a type parameter, so this is handled by the resolver.
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
-        let res =
-            Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
+        let (generic_params, generics_source_map) =
+            self.lower_generic_params(HasImplicitSelf::No, impl_def);
+        types_map.shrink_to_fit();
+        types_source_map.shrink_to_fit();
+        let res = Impl {
+            generic_params,
+            target_trait,
+            self_ty,
+            is_negative,
+            is_unsafe,
+            items,
+            ast_id,
+            types_map: Arc::new(types_map),
+        };
         let id = id(self.data().impls.alloc(res));
+        self.source_maps.impls.push(GenericItemSourceMapBuilder {
+            item: types_source_map,
+            generics: generics_source_map,
+        });
         self.write_generic_params_attributes(id.into());
-        Some(id)
+        id
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -692,14 +867,17 @@ impl<'a> Ctx<'a> {
         &mut self,
         has_implicit_self: HasImplicitSelf,
         node: &dyn ast::HasGenericParams,
-    ) -> Interned<GenericParams> {
+    ) -> (Arc<GenericParams>, TypesSourceMap) {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let body_ctx = self.body_ctx(&mut types_map, &mut types_source_map);
         debug_assert!(self.generic_param_attr_buffer.is_empty(),);
         let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
                                param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
+            let attrs = RawAttrs::new(self.db.upcast(), &param, body_ctx.span_map());
             debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
         };
-        self.body_ctx.take_impl_traits_bounds();
+        body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
         if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -715,23 +893,29 @@ impl<'a> Ctx<'a> {
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
             generics.fill_bounds(
-                &self.body_ctx,
+                &body_ctx,
                 bounds,
-                Either::Left(TypeRef::Path(Name::new_symbol_root(sym::Self_.clone()).into())),
+                Either::Left(body_ctx.alloc_type_ref_desugared(TypeRef::Path(
+                    Name::new_symbol_root(sym::Self_.clone()).into(),
+                ))),
             );
         }
 
-        generics.fill(&self.body_ctx, node, add_param_attrs);
+        generics.fill(&body_ctx, node, add_param_attrs);
 
-        Interned::new(generics.finish())
+        let generics = generics.finish(types_map, &mut types_source_map);
+        (generics, types_source_map)
     }
 
-    fn lower_type_bounds(&mut self, node: &dyn ast::HasTypeBounds) -> Box<[Interned<TypeBound>]> {
+    fn lower_type_bounds(
+        &mut self,
+        node: &dyn ast::HasTypeBounds,
+        body_ctx: &LowerCtx<'_>,
+    ) -> Box<[TypeBound]> {
         match node.type_bound_list() {
-            Some(bound_list) => bound_list
-                .bounds()
-                .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
-                .collect(),
+            Some(bound_list) => {
+                bound_list.bounds().map(|it| TypeBound::from_ast(body_ctx, it)).collect()
+            }
             None => Box::default(),
         }
     }
@@ -743,23 +927,6 @@ impl<'a> Ctx<'a> {
         self.data().vis.alloc(vis)
     }
 
-    fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
-        let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
-        Some(Interned::new(trait_ref))
-    }
-
-    fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
-        let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
-        Interned::new(tyref)
-    }
-
-    fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
-        match type_ref.map(|ty| self.lower_type_ref(&ty)) {
-            Some(it) => it,
-            None => Interned::new(TypeRef::Error),
-        }
-    }
-
     fn next_variant_idx(&self) -> Idx<Variant> {
         Idx::from_raw(RawIdx::from(
             self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
@@ -767,7 +934,7 @@ impl<'a> Ctx<'a> {
     }
 }
 
-fn desugar_future_path(orig: TypeRef) -> Path {
+fn desugar_future_path(orig: TypeRefId) -> Path {
     let path = path![core::future::Future];
     let mut generic_args: Vec<_> =
         std::iter::repeat(None).take(path.segments().len() - 1).collect();
@@ -777,10 +944,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
         type_ref: Some(orig),
         bounds: Box::default(),
     };
-    generic_args.push(Some(Interned::new(GenericArgs {
-        bindings: Box::new([binding]),
-        ..GenericArgs::empty()
-    })));
+    generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
 
     Path::from_known_path(path, generic_args)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 9dce28b2e49..b6816a1f968 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -10,11 +10,12 @@ use crate::{
     item_tree::{
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
         FieldsShape, FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl,
-        Interned, ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path,
-        RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound,
-        TypeRef, Union, Use, UseTree, UseTreeKind, Variant,
+        ItemTree, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, Path, RawAttrs,
+        RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, Union, Use,
+        UseTree, UseTreeKind, Variant,
     },
     pretty::{print_path, print_type_bounds, print_type_ref},
+    type_ref::{TypeRefId, TypesMap},
     visibility::RawVisibility,
 };
 
@@ -121,7 +122,13 @@ impl Printer<'_> {
         };
     }
 
-    fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
+    fn print_fields(
+        &mut self,
+        parent: FieldParent,
+        kind: FieldsShape,
+        fields: &[Field],
+        map: &TypesMap,
+    ) {
         let edition = self.edition;
         match kind {
             FieldsShape::Record => {
@@ -135,7 +142,7 @@ impl Printer<'_> {
                         );
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name.display(self.db.upcast(), edition));
-                        this.print_type_ref(type_ref);
+                        this.print_type_ref(*type_ref, map);
                         wln!(this, ",");
                     }
                 });
@@ -151,7 +158,7 @@ impl Printer<'_> {
                         );
                         this.print_visibility(*visibility);
                         w!(this, "{}: ", name.display(self.db.upcast(), edition));
-                        this.print_type_ref(type_ref);
+                        this.print_type_ref(*type_ref, map);
                         wln!(this, ",");
                     }
                 });
@@ -167,20 +174,21 @@ impl Printer<'_> {
         kind: FieldsShape,
         fields: &[Field],
         params: &GenericParams,
+        map: &TypesMap,
     ) {
         match kind {
             FieldsShape::Record => {
                 if self.print_where_clause(params) {
                     wln!(self);
                 }
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
             }
             FieldsShape::Unit => {
                 self.print_where_clause(params);
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
             }
             FieldsShape::Tuple => {
-                self.print_fields(parent, kind, fields);
+                self.print_fields(parent, kind, fields, map);
                 self.print_where_clause(params);
             }
         }
@@ -262,6 +270,7 @@ impl Printer<'_> {
                     params,
                     ret_type,
                     ast_id,
+                    types_map,
                     flags,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
@@ -298,7 +307,7 @@ impl Printer<'_> {
                                 w!(this, "self: ");
                             }
                             if let Some(type_ref) = type_ref {
-                                this.print_type_ref(type_ref);
+                                this.print_type_ref(*type_ref, types_map);
                             } else {
                                 wln!(this, "...");
                             }
@@ -307,7 +316,7 @@ impl Printer<'_> {
                     });
                 }
                 w!(self, ") -> ");
-                self.print_type_ref(ret_type);
+                self.print_type_ref(*ret_type, types_map);
                 self.print_where_clause(explicit_generic_params);
                 if flags.contains(FnFlags::HAS_BODY) {
                     wln!(self, " {{ ... }}");
@@ -316,8 +325,15 @@ impl Printer<'_> {
                 }
             }
             ModItem::Struct(it) => {
-                let Struct { visibility, name, fields, shape: kind, generic_params, ast_id } =
-                    &self.tree[it];
+                let Struct {
+                    visibility,
+                    name,
+                    fields,
+                    shape: kind,
+                    generic_params,
+                    ast_id,
+                    types_map,
+                } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db.upcast(), self.edition));
@@ -327,6 +343,7 @@ impl Printer<'_> {
                     *kind,
                     fields,
                     generic_params,
+                    types_map,
                 );
                 if matches!(kind, FieldsShape::Record) {
                     wln!(self);
@@ -335,7 +352,8 @@ impl Printer<'_> {
                 }
             }
             ModItem::Union(it) => {
-                let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it];
+                let Union { name, visibility, fields, generic_params, ast_id, types_map } =
+                    &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db.upcast(), self.edition));
@@ -345,6 +363,7 @@ impl Printer<'_> {
                     FieldsShape::Record,
                     fields,
                     generic_params,
+                    types_map,
                 );
                 wln!(self);
             }
@@ -358,18 +377,20 @@ impl Printer<'_> {
                 let edition = self.edition;
                 self.indented(|this| {
                     for variant in FileItemTreeId::range_iter(variants.clone()) {
-                        let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
+                        let Variant { name, fields, shape: kind, ast_id, types_map } =
+                            &this.tree[variant];
                         this.print_ast_id(ast_id.erase());
                         this.print_attrs_of(variant, "\n");
                         w!(this, "{}", name.display(self.db.upcast(), edition));
-                        this.print_fields(FieldParent::Variant(variant), *kind, fields);
+                        this.print_fields(FieldParent::Variant(variant), *kind, fields, types_map);
                         wln!(this, ",");
                     }
                 });
                 wln!(self, "}}");
             }
             ModItem::Const(it) => {
-                let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
+                let Const { name, visibility, type_ref, ast_id, has_body: _, types_map } =
+                    &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "const ");
@@ -378,7 +399,7 @@ impl Printer<'_> {
                     None => w!(self, "_"),
                 }
                 w!(self, ": ");
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, types_map);
                 wln!(self, " = _;");
             }
             ModItem::Static(it) => {
@@ -390,6 +411,7 @@ impl Printer<'_> {
                     ast_id,
                     has_safe_kw,
                     has_unsafe_kw,
+                    types_map,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
@@ -404,7 +426,7 @@ impl Printer<'_> {
                     w!(self, "mut ");
                 }
                 w!(self, "{}: ", name.display(self.db.upcast(), self.edition));
-                self.print_type_ref(type_ref);
+                self.print_type_ref(*type_ref, types_map);
                 w!(self, " = _;");
                 wln!(self);
             }
@@ -449,6 +471,7 @@ impl Printer<'_> {
                     items,
                     generic_params,
                     ast_id,
+                    types_map,
                 } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 if *is_unsafe {
@@ -461,10 +484,10 @@ impl Printer<'_> {
                     w!(self, "!");
                 }
                 if let Some(tr) = target_trait {
-                    self.print_path(&tr.path);
+                    self.print_path(&tr.path, types_map);
                     w!(self, " for ");
                 }
-                self.print_type_ref(self_ty);
+                self.print_type_ref(*self_ty, types_map);
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
@@ -474,19 +497,26 @@ impl Printer<'_> {
                 wln!(self, "}}");
             }
             ModItem::TypeAlias(it) => {
-                let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id } =
-                    &self.tree[it];
+                let TypeAlias {
+                    name,
+                    visibility,
+                    bounds,
+                    type_ref,
+                    generic_params,
+                    ast_id,
+                    types_map,
+                } = &self.tree[it];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db.upcast(), self.edition));
                 self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
-                    self.print_type_bounds(bounds);
+                    self.print_type_bounds(bounds, types_map);
                 }
                 if let Some(ty) = type_ref {
                     w!(self, " = ");
-                    self.print_type_ref(ty);
+                    self.print_type_ref(*ty, types_map);
                 }
                 self.print_where_clause(generic_params);
                 w!(self, ";");
@@ -543,19 +573,19 @@ impl Printer<'_> {
         self.blank();
     }
 
-    fn print_type_ref(&mut self, type_ref: &TypeRef) {
+    fn print_type_ref(&mut self, type_ref: TypeRefId, map: &TypesMap) {
         let edition = self.edition;
-        print_type_ref(self.db, type_ref, self, edition).unwrap();
+        print_type_ref(self.db, type_ref, map, self, edition).unwrap();
     }
 
-    fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
+    fn print_type_bounds(&mut self, bounds: &[TypeBound], map: &TypesMap) {
         let edition = self.edition;
-        print_type_bounds(self.db, bounds, self, edition).unwrap();
+        print_type_bounds(self.db, bounds, map, self, edition).unwrap();
     }
 
-    fn print_path(&mut self, path: &Path) {
+    fn print_path(&mut self, path: &Path, map: &TypesMap) {
         let edition = self.edition;
-        print_path(self.db, path, self, edition).unwrap();
+        print_path(self.db, path, map, self, edition).unwrap();
     }
 
     fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
@@ -586,7 +616,7 @@ impl Printer<'_> {
                 },
                 TypeOrConstParamData::ConstParamData(konst) => {
                     w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition));
-                    self.print_type_ref(&konst.ty);
+                    self.print_type_ref(konst.ty, &params.types_map);
                 }
             }
         }
@@ -640,14 +670,16 @@ impl Printer<'_> {
                 };
 
                 match target {
-                    WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
+                    WherePredicateTypeTarget::TypeRef(ty) => {
+                        this.print_type_ref(*ty, &params.types_map)
+                    }
                     WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
                         Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)),
                         None => w!(this, "_anon_{}", id.into_raw()),
                     },
                 }
                 w!(this, ": ");
-                this.print_type_bounds(std::slice::from_ref(bound));
+                this.print_type_bounds(std::slice::from_ref(bound), &params.types_map);
             }
         });
         true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 157c9ef0805..f6ed826f04c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -1531,11 +1531,3 @@ fn macro_call_as_call_id_with_eager(
 pub struct UnresolvedMacro {
     pub path: hir_expand::mod_path::ModPath,
 }
-
-intern::impl_internable!(
-    crate::type_ref::TypeRef,
-    crate::type_ref::TraitRef,
-    crate::type_ref::TypeBound,
-    crate::path::GenericArgs,
-    generics::GenericParams,
-);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index e4786a1dd40..df5847929c5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -5,43 +5,53 @@ use hir_expand::{
     span_map::{SpanMap, SpanMapRef},
     AstId, HirFileId, InFile,
 };
-use intern::Interned;
 use span::{AstIdMap, AstIdNode};
+use stdx::thin_vec::ThinVec;
 use syntax::ast;
 use triomphe::Arc;
 
-use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
+use crate::{
+    db::DefDatabase,
+    path::Path,
+    type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap},
+};
 
 pub struct LowerCtx<'a> {
     pub db: &'a dyn DefDatabase,
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
-    impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
+    impl_trait_bounds: RefCell<Vec<ThinVec<TypeBound>>>,
     // Prevent nested impl traits like `impl Foo<impl Bar>`.
     outer_impl_trait: RefCell<bool>,
+    types_map: RefCell<(&'a mut TypesMap, &'a mut TypesSourceMap)>,
 }
 
-pub(crate) struct OuterImplTraitGuard<'a> {
-    ctx: &'a LowerCtx<'a>,
+pub(crate) struct OuterImplTraitGuard<'a, 'b> {
+    ctx: &'a LowerCtx<'b>,
     old: bool,
 }
 
-impl<'a> OuterImplTraitGuard<'a> {
-    fn new(ctx: &'a LowerCtx<'a>, impl_trait: bool) -> Self {
+impl<'a, 'b> OuterImplTraitGuard<'a, 'b> {
+    fn new(ctx: &'a LowerCtx<'b>, impl_trait: bool) -> Self {
         let old = ctx.outer_impl_trait.replace(impl_trait);
         Self { ctx, old }
     }
 }
 
-impl<'a> Drop for OuterImplTraitGuard<'a> {
+impl Drop for OuterImplTraitGuard<'_, '_> {
     fn drop(&mut self) {
         self.ctx.outer_impl_trait.replace(self.old);
     }
 }
 
 impl<'a> LowerCtx<'a> {
-    pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
+    pub fn new(
+        db: &'a dyn DefDatabase,
+        file_id: HirFileId,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
+    ) -> Self {
         LowerCtx {
             db,
             file_id,
@@ -49,6 +59,7 @@ impl<'a> LowerCtx<'a> {
             ast_id_map: OnceCell::new(),
             impl_trait_bounds: RefCell::new(Vec::new()),
             outer_impl_trait: RefCell::default(),
+            types_map: RefCell::new((types_map, types_source_map)),
         }
     }
 
@@ -56,6 +67,8 @@ impl<'a> LowerCtx<'a> {
         db: &'a dyn DefDatabase,
         file_id: HirFileId,
         span_map: OnceCell<SpanMap>,
+        types_map: &'a mut TypesMap,
+        types_source_map: &'a mut TypesSourceMap,
     ) -> Self {
         LowerCtx {
             db,
@@ -64,6 +77,7 @@ impl<'a> LowerCtx<'a> {
             ast_id_map: OnceCell::new(),
             impl_trait_bounds: RefCell::new(Vec::new()),
             outer_impl_trait: RefCell::default(),
+            types_map: RefCell::new((types_map, types_source_map)),
         }
     }
 
@@ -82,11 +96,11 @@ impl<'a> LowerCtx<'a> {
         )
     }
 
-    pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
+    pub fn update_impl_traits_bounds(&self, bounds: ThinVec<TypeBound>) {
         self.impl_trait_bounds.borrow_mut().push(bounds);
     }
 
-    pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
+    pub fn take_impl_traits_bounds(&self) -> Vec<ThinVec<TypeBound>> {
         self.impl_trait_bounds.take()
     }
 
@@ -94,7 +108,32 @@ impl<'a> LowerCtx<'a> {
         *self.outer_impl_trait.borrow()
     }
 
-    pub(crate) fn outer_impl_trait_scope(&'a self, impl_trait: bool) -> OuterImplTraitGuard<'a> {
+    pub(crate) fn outer_impl_trait_scope<'b>(
+        &'b self,
+        impl_trait: bool,
+    ) -> OuterImplTraitGuard<'b, 'a> {
         OuterImplTraitGuard::new(self, impl_trait)
     }
+
+    pub(crate) fn alloc_type_ref(&self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
+        let mut types_map = self.types_map.borrow_mut();
+        let (types_map, types_source_map) = &mut *types_map;
+        let id = types_map.types.alloc(type_ref);
+        types_source_map.types_map_back.insert(id, InFile::new(self.file_id, node));
+        id
+    }
+
+    pub(crate) fn alloc_type_ref_desugared(&self, type_ref: TypeRef) -> TypeRefId {
+        self.types_map.borrow_mut().0.types.alloc(type_ref)
+    }
+
+    pub(crate) fn alloc_error_type(&self) -> TypeRefId {
+        self.types_map.borrow_mut().0.types.alloc(TypeRef::Error)
+    }
+
+    // FIXME: If we alloc while holding this, well... Bad Things will happen. Need to change this
+    // to use proper mutability instead of interior mutability.
+    pub(crate) fn types_map(&self) -> std::cell::Ref<'_, TypesMap> {
+        std::cell::Ref::map(self.types_map.borrow(), |it| &*it.0)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index 450a15bd66e..d5b94f0ae44 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -122,7 +122,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
 
         let mut expn_text = String::new();
         if let Some(err) = exp.err {
-            format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).0);
+            format_to!(expn_text, "/* error: {} */", err.render_to_string(&db).message);
         }
         let (parse, token_map) = exp.value;
         if expect_errors {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 22b9c2b4e37..a37e3c70e22 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -31,7 +31,7 @@ use crate::{
     item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
     item_tree::{
         self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
-        ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+        ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
     },
     macro_call_as_call_id, macro_call_as_call_id_with_eager,
     nameres::{
@@ -985,12 +985,8 @@ impl DefCollector<'_> {
         for (name, res) in resolutions {
             match name {
                 Some(name) => {
-                    changed |= self.push_res_and_update_glob_vis(
-                        module_id,
-                        name,
-                        res.with_visibility(vis),
-                        import,
-                    );
+                    changed |=
+                        self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
                 }
                 None => {
                     let tr = match res.take_types() {
@@ -1043,10 +1039,11 @@ impl DefCollector<'_> {
             .collect::<Vec<_>>();
 
         for (glob_importing_module, glob_import_vis, use_) in glob_imports {
+            let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
             self.update_recursive(
                 glob_importing_module,
                 resolutions,
-                glob_import_vis,
+                vis,
                 Some(ImportType::Glob(use_)),
                 depth + 1,
             );
@@ -1058,8 +1055,44 @@ impl DefCollector<'_> {
         module_id: LocalModuleId,
         name: &Name,
         mut defs: PerNs,
+        vis: Visibility,
         def_import_type: Option<ImportType>,
     ) -> bool {
+        // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
+        // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
+        // or `pub use ::crate_name`.
+        //
+        // This has been historically allowed, but may be not allowed in future
+        // https://github.com/rust-lang/rust/issues/127909
+        if let Some((_, v, it)) = defs.types.as_mut() {
+            let is_extern_crate_reimport_without_prefix = || {
+                let Some(ImportOrExternCrate::ExternCrate(_)) = it else {
+                    return false;
+                };
+                let Some(ImportType::Import(id)) = def_import_type else {
+                    return false;
+                };
+                let use_id = id.import.lookup(self.db).id;
+                let item_tree = use_id.item_tree(self.db);
+                let use_kind = item_tree[use_id.value].use_tree.kind();
+                let UseTreeKind::Single { path, .. } = use_kind else {
+                    return false;
+                };
+                path.segments().len() < 2
+            };
+            if is_extern_crate_reimport_without_prefix() {
+                *v = vis;
+            } else {
+                *v = v.min(vis, &self.def_map).unwrap_or(vis);
+            }
+        }
+        if let Some((_, v, _)) = defs.values.as_mut() {
+            *v = v.min(vis, &self.def_map).unwrap_or(vis);
+        }
+        if let Some((_, v, _)) = defs.macros.as_mut() {
+            *v = v.min(vis, &self.def_map).unwrap_or(vis);
+        }
+
         let mut changed = false;
 
         if let Some(ImportType::Glob(_)) = def_import_type {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 75cab137f78..29379d00749 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -10,6 +10,7 @@
 //!
 //! `ReachedFixedPoint` signals about this.
 
+use either::Either;
 use hir_expand::{name::Name, Lookup};
 use span::Edition;
 use triomphe::Arc;
@@ -150,17 +151,8 @@ impl DefMap {
 
         let mut arc;
         let mut current_map = self;
-        loop {
-            let new = current_map.resolve_path_fp_with_macro_single(
-                db,
-                mode,
-                original_module,
-                path,
-                shadow,
-                expected_macro_subns,
-            );
 
-            // Merge `new` into `result`.
+        let mut merge = |new: ResolvePathResult| {
             result.resolved_def = result.resolved_def.or(new.resolved_def);
             if result.reached_fixedpoint == ReachedFixedPoint::No {
                 result.reached_fixedpoint = new.reached_fixedpoint;
@@ -171,7 +163,9 @@ impl DefMap {
                 (Some(old), Some(new)) => Some(old.max(new)),
                 (None, new) => new,
             };
+        };
 
+        loop {
             match current_map.block {
                 Some(block) if original_module == Self::ROOT => {
                     // Block modules "inherit" names from its parent module.
@@ -180,8 +174,38 @@ impl DefMap {
                     current_map = &arc;
                 }
                 // Proper (non-block) modules, including those in block `DefMap`s, don't.
-                _ => return result,
+                _ => {
+                    if original_module != Self::ROOT && current_map.block.is_some() {
+                        // A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
+                        // the prelude items (which are not inserted into blocks because they can be overridden there).
+                        original_module = Self::ROOT;
+                        arc = db.crate_def_map(self.krate);
+                        current_map = &arc;
+
+                        let new = current_map.resolve_path_fp_in_all_preludes(
+                            db,
+                            mode,
+                            original_module,
+                            path,
+                            shadow,
+                        );
+                        merge(new);
+                    }
+
+                    return result;
+                }
             }
+
+            let new = current_map.resolve_path_fp_with_macro_single(
+                db,
+                mode,
+                original_module,
+                path,
+                shadow,
+                expected_macro_subns,
+            );
+
+            merge(new);
         }
     }
 
@@ -195,7 +219,7 @@ impl DefMap {
         expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
         let mut segments = path.segments().iter().enumerate();
-        let mut curr_per_ns = match path.kind {
+        let curr_per_ns = match path.kind {
             PathKind::DollarCrate(krate) => {
                 if krate == self.krate {
                     cov_mark::hit!(macro_dollar_crate_self);
@@ -296,25 +320,96 @@ impl DefMap {
 
                 PerNs::types(module.into(), Visibility::Public, None)
             }
-            PathKind::Abs => {
-                // 2018-style absolute path -- only extern prelude
-                let segment = match segments.next() {
-                    Some((_, segment)) => segment,
+            PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+                Either::Left(it) => it,
+                Either::Right(reached_fixed_point) => {
+                    return ResolvePathResult::empty(reached_fixed_point)
+                }
+            },
+        };
+
+        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+    }
+
+    /// Resolves a path only in the preludes, without accounting for item scopes.
+    pub(super) fn resolve_path_fp_in_all_preludes(
+        &self,
+        db: &dyn DefDatabase,
+        mode: ResolveMode,
+        original_module: LocalModuleId,
+        path: &ModPath,
+        shadow: BuiltinShadowMode,
+    ) -> ResolvePathResult {
+        let mut segments = path.segments().iter().enumerate();
+        let curr_per_ns = match path.kind {
+            // plain import or absolute path in 2015: crate-relative with
+            // fallback to extern prelude (with the simplification in
+            // rust-lang/rust#57745)
+            // FIXME there must be a nicer way to write this condition
+            PathKind::Plain | PathKind::Abs
+                if self.data.edition == Edition::Edition2015
+                    && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
+            {
+                let (_, segment) = match segments.next() {
+                    Some((idx, segment)) => (idx, segment),
                     None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
                 };
-                if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
-                    tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
-                    PerNs::types(
-                        def.into(),
-                        Visibility::Public,
-                        extern_crate.map(ImportOrExternCrate::ExternCrate),
-                    )
-                } else {
-                    return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
+                tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
+                self.resolve_name_in_extern_prelude(segment)
+            }
+            PathKind::Plain => {
+                let (_, segment) = match segments.next() {
+                    Some((idx, segment)) => (idx, segment),
+                    None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
+                };
+                tracing::debug!("resolving {:?} in module", segment);
+                self.resolve_name_in_all_preludes(db, segment)
+            }
+            PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
+                Either::Left(it) => it,
+                Either::Right(reached_fixed_point) => {
+                    return ResolvePathResult::empty(reached_fixed_point)
                 }
+            },
+            PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
+                return ResolvePathResult::empty(ReachedFixedPoint::Yes)
             }
         };
 
+        self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
+    }
+
+    /// 2018-style absolute path -- only extern prelude
+    fn resolve_path_abs<'a>(
+        &self,
+        segments: &mut impl Iterator<Item = (usize, &'a Name)>,
+        path: &ModPath,
+    ) -> Either<PerNs, ReachedFixedPoint> {
+        let segment = match segments.next() {
+            Some((_, segment)) => segment,
+            None => return Either::Right(ReachedFixedPoint::Yes),
+        };
+        if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
+            tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
+            Either::Left(PerNs::types(
+                def.into(),
+                Visibility::Public,
+                extern_crate.map(ImportOrExternCrate::ExternCrate),
+            ))
+        } else {
+            Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
+        }
+    }
+
+    fn resolve_remaining_segments<'a>(
+        &self,
+        segments: impl Iterator<Item = (usize, &'a Name)>,
+        mut curr_per_ns: PerNs,
+        path: &ModPath,
+        db: &dyn DefDatabase,
+        shadow: BuiltinShadowMode,
+        original_module: LocalModuleId,
+    ) -> ResolvePathResult {
         for (i, segment) in segments {
             let (curr, vis, imp) = match curr_per_ns.take_types_full() {
                 Some(r) => r,
@@ -475,24 +570,9 @@ impl DefMap {
                 // they might been shadowed by local names.
                 return PerNs::none();
             }
-            self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
-                PerNs::types(
-                    it.into(),
-                    Visibility::Public,
-                    extern_crate.map(ImportOrExternCrate::ExternCrate),
-                )
-            })
-        };
-        let macro_use_prelude = || {
-            self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
-                PerNs::macros(
-                    it,
-                    Visibility::Public,
-                    // FIXME?
-                    None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
-                )
-            })
+            self.resolve_name_in_extern_prelude(name)
         };
+        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
         let prelude = || {
             if self.block.is_some() && module == DefMap::ROOT {
                 return PerNs::none();
@@ -507,6 +587,38 @@ impl DefMap {
             .or_else(prelude)
     }
 
+    fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
+        // Resolve in:
+        //  - extern prelude / macro_use prelude
+        //  - std prelude
+        let extern_prelude = self.resolve_name_in_extern_prelude(name);
+        let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
+        let prelude = || self.resolve_in_prelude(db, name);
+
+        extern_prelude.or_else(macro_use_prelude).or_else(prelude)
+    }
+
+    fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
+        self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
+            PerNs::types(
+                it.into(),
+                Visibility::Public,
+                extern_crate.map(ImportOrExternCrate::ExternCrate),
+            )
+        })
+    }
+
+    fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
+        self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
+            PerNs::macros(
+                it,
+                Visibility::Public,
+                // FIXME?
+                None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
+            )
+        })
+    }
+
     fn resolve_name_in_crate_root_or_extern_prelude(
         &self,
         db: &dyn DefDatabase,
@@ -525,16 +637,7 @@ impl DefMap {
                 // Don't resolve extern prelude in pseudo-module of a block.
                 return PerNs::none();
             }
-            self.data.extern_prelude.get(name).copied().map_or(
-                PerNs::none(),
-                |(it, extern_crate)| {
-                    PerNs::types(
-                        it.into(),
-                        Visibility::Public,
-                        extern_crate.map(ImportOrExternCrate::ExternCrate),
-                    )
-                },
-            )
+            self.resolve_name_in_extern_prelude(name)
         };
 
         from_crate_root.or_else(from_extern_prelude)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 7b02a89e5de..e1e30e5cec9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -386,6 +386,52 @@ pub struct Arc;
 }
 
 #[test]
+fn extern_crate_reexport() {
+    check(
+        r#"
+//- /main.rs crate:main deps:importer
+use importer::*;
+use importer::extern_crate1::exported::*;
+use importer::allowed_reexport::*;
+use importer::extern_crate2::*;
+use importer::not_allowed_reexport1;
+use importer::not_allowed_reexport2;
+
+//- /importer.rs crate:importer deps:extern_crate1,extern_crate2
+extern crate extern_crate1;
+extern crate extern_crate2;
+
+pub use extern_crate1;
+pub use extern_crate1 as allowed_reexport;
+
+pub use ::extern_crate;
+pub use self::extern_crate as not_allowed_reexport1;
+pub use crate::extern_crate as not_allowed_reexport2;
+
+//- /extern_crate1.rs crate:extern_crate1
+pub mod exported {
+    pub struct PublicItem;
+    struct PrivateItem;
+}
+
+pub struct Exported;
+
+//- /extern_crate2.rs crate:extern_crate2
+pub struct NotExported;
+"#,
+        expect![[r#"
+            crate
+            Exported: t v
+            PublicItem: t v
+            allowed_reexport: t
+            exported: t
+            not_allowed_reexport1: _
+            not_allowed_reexport2: _
+        "#]],
+    );
+}
+
+#[test]
 fn extern_crate_rename_2015_edition() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index a2696055ca1..543ab41cd59 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -412,3 +412,42 @@ use reexport::*;
         "#]],
     );
 }
+
+#[test]
+fn regression_18308() {
+    check(
+        r#"
+use outer::*;
+
+mod outer {
+    mod inner_superglob {
+        pub use super::*;
+    }
+
+    // The importing order matters!
+    pub use inner_superglob::*;
+    use super::glob_target::*;
+}
+
+mod glob_target {
+    pub struct ShouldBePrivate;
+}
+"#,
+        expect![[r#"
+            crate
+            glob_target: t
+            outer: t
+
+            crate::glob_target
+            ShouldBePrivate: t v
+
+            crate::outer
+            ShouldBePrivate: t v
+            inner_superglob: t
+
+            crate::outer::inner_superglob
+            ShouldBePrivate: t v
+            inner_superglob: t
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index d319831867c..d920c108266 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -253,7 +253,8 @@ m!(Z);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
         });
-        let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        let n_recalculated_item_trees =
+            events.iter().filter(|it| it.contains("item_tree(")).count();
         assert_eq!(n_recalculated_item_trees, 6);
         let n_reparsed_macros =
             events.iter().filter(|it| it.contains("parse_macro_expansion(")).count();
@@ -308,7 +309,7 @@ pub type Ty = ();
         let events = db.log_executed(|| {
             db.file_item_tree(pos.file_id.into());
         });
-        let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count();
+        let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree(")).count();
         assert_eq!(n_calculated_item_trees, 1);
         let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count();
         assert_eq!(n_parsed_files, 1);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
index 077863c0c93..dc6947c5b56 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs
@@ -9,11 +9,12 @@ use std::{
 use crate::{
     lang_item::LangItemTarget,
     lower::LowerCtx,
-    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
+    type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRefId},
 };
 use hir_expand::name::Name;
 use intern::Interned;
 use span::Edition;
+use stdx::thin_vec::thin_vec_with_header_struct;
 use syntax::ast;
 
 pub use hir_expand::mod_path::{path, ModPath, PathKind};
@@ -47,20 +48,33 @@ impl Display for ImportAliasDisplay<'_> {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum Path {
-    /// A normal path
-    Normal {
-        /// Type based path like `<T>::foo`.
-        /// Note that paths like `<Type as Trait>::foo` are desugared to `Trait::<Self=Type>::foo`.
-        type_anchor: Option<Interned<TypeRef>>,
-        mod_path: Interned<ModPath>,
-        /// Invariant: the same len as `self.mod_path.segments` or `None` if all segments are `None`.
-        generic_args: Option<Box<[Option<Interned<GenericArgs>>]>>,
-    },
+    /// `BarePath` is used when the path has neither generics nor type anchor, since the vast majority of paths
+    /// are in this category, and splitting `Path` this way allows it to be more thin. When the path has either generics
+    /// or type anchor, it is `Path::Normal` with the generics filled with `None` even if there are none (practically
+    /// this is not a problem since many more paths have generics than a type anchor).
+    BarePath(Interned<ModPath>),
+    /// `Path::Normal` may have empty generics and type anchor (but generic args will be filled with `None`).
+    Normal(NormalPath),
     /// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
     /// links via a normal path since they might be private and not accessible in the usage place.
     LangItem(LangItemTarget, Option<Name>),
 }
 
+// This type is being used a lot, make sure it doesn't grow unintentionally.
+#[cfg(target_arch = "x86_64")]
+const _: () = {
+    assert!(size_of::<Path>() == 16);
+    assert!(size_of::<Option<Path>>() == 16);
+};
+
+thin_vec_with_header_struct! {
+    pub new(pub(crate)) struct NormalPath, NormalPathHeader {
+        pub generic_args: [Option<GenericArgs>],
+        pub type_anchor: Option<TypeRefId>,
+        pub mod_path: Interned<ModPath>; ref,
+    }
+}
+
 /// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
 /// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -86,20 +100,20 @@ pub struct AssociatedTypeBinding {
     pub name: Name,
     /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
     /// would be `['a, T]`.
-    pub args: Option<Interned<GenericArgs>>,
+    pub args: Option<GenericArgs>,
     /// The type bound to this associated type (in `Item = T`, this would be the
     /// `T`). This can be `None` if there are bounds instead.
-    pub type_ref: Option<TypeRef>,
+    pub type_ref: Option<TypeRefId>,
     /// Bounds for the associated type, like in `Iterator<Item:
     /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
     /// feature.)
-    pub bounds: Box<[Interned<TypeBound>]>,
+    pub bounds: Box<[TypeBound]>,
 }
 
 /// A single generic argument.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum GenericArg {
-    Type(TypeRef),
+    Type(TypeRefId),
     Lifetime(LifetimeRef),
     Const(ConstRef),
 }
@@ -112,50 +126,49 @@ impl Path {
     }
 
     /// Converts a known mod path to `Path`.
-    pub fn from_known_path(
-        path: ModPath,
-        generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
-    ) -> Path {
-        let generic_args = generic_args.into();
-        assert_eq!(path.len(), generic_args.len());
-        Path::Normal {
-            type_anchor: None,
-            mod_path: Interned::new(path),
-            generic_args: Some(generic_args),
-        }
+    pub fn from_known_path(path: ModPath, generic_args: Vec<Option<GenericArgs>>) -> Path {
+        Path::Normal(NormalPath::new(None, Interned::new(path), generic_args))
     }
 
     /// Converts a known mod path to `Path`.
     pub fn from_known_path_with_no_generic(path: ModPath) -> Path {
-        Path::Normal { type_anchor: None, mod_path: Interned::new(path), generic_args: None }
+        Path::BarePath(Interned::new(path))
     }
 
+    #[inline]
     pub fn kind(&self) -> &PathKind {
         match self {
-            Path::Normal { mod_path, .. } => &mod_path.kind,
+            Path::BarePath(mod_path) => &mod_path.kind,
+            Path::Normal(path) => &path.mod_path().kind,
             Path::LangItem(..) => &PathKind::Abs,
         }
     }
 
-    pub fn type_anchor(&self) -> Option<&TypeRef> {
+    #[inline]
+    pub fn type_anchor(&self) -> Option<TypeRefId> {
         match self {
-            Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
-            Path::LangItem(..) => None,
+            Path::Normal(path) => path.type_anchor(),
+            Path::LangItem(..) | Path::BarePath(_) => None,
+        }
+    }
+
+    #[inline]
+    pub fn generic_args(&self) -> Option<&[Option<GenericArgs>]> {
+        match self {
+            Path::Normal(path) => Some(path.generic_args()),
+            Path::LangItem(..) | Path::BarePath(_) => None,
         }
     }
 
     pub fn segments(&self) -> PathSegments<'_> {
         match self {
-            Path::Normal { mod_path, generic_args, .. } => {
-                let s = PathSegments {
-                    segments: mod_path.segments(),
-                    generic_args: generic_args.as_deref(),
-                };
-                if let Some(generic_args) = s.generic_args {
-                    assert_eq!(s.segments.len(), generic_args.len());
-                }
-                s
+            Path::BarePath(mod_path) => {
+                PathSegments { segments: mod_path.segments(), generic_args: None }
             }
+            Path::Normal(path) => PathSegments {
+                segments: path.mod_path().segments(),
+                generic_args: Some(path.generic_args()),
+            },
             Path::LangItem(_, seg) => PathSegments {
                 segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
                 generic_args: None,
@@ -165,34 +178,55 @@ impl Path {
 
     pub fn mod_path(&self) -> Option<&ModPath> {
         match self {
-            Path::Normal { mod_path, .. } => Some(mod_path),
+            Path::BarePath(mod_path) => Some(mod_path),
+            Path::Normal(path) => Some(path.mod_path()),
             Path::LangItem(..) => None,
         }
     }
 
     pub fn qualifier(&self) -> Option<Path> {
-        let Path::Normal { mod_path, generic_args, type_anchor } = self else {
-            return None;
-        };
-        if mod_path.is_ident() {
-            return None;
+        match self {
+            Path::BarePath(mod_path) => {
+                if mod_path.is_ident() {
+                    return None;
+                }
+                Some(Path::BarePath(Interned::new(ModPath::from_segments(
+                    mod_path.kind,
+                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+                ))))
+            }
+            Path::Normal(path) => {
+                let mod_path = path.mod_path();
+                if mod_path.is_ident() {
+                    return None;
+                }
+                let type_anchor = path.type_anchor();
+                let generic_args = path.generic_args();
+                let qualifier_mod_path = Interned::new(ModPath::from_segments(
+                    mod_path.kind,
+                    mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
+                ));
+                let qualifier_generic_args = &generic_args[..generic_args.len() - 1];
+                Some(Path::Normal(NormalPath::new(
+                    type_anchor,
+                    qualifier_mod_path,
+                    qualifier_generic_args.iter().cloned(),
+                )))
+            }
+            Path::LangItem(..) => None,
         }
-        let res = Path::Normal {
-            type_anchor: type_anchor.clone(),
-            mod_path: Interned::new(ModPath::from_segments(
-                mod_path.kind,
-                mod_path.segments()[..mod_path.segments().len() - 1].iter().cloned(),
-            )),
-            generic_args: generic_args.as_ref().map(|it| it[..it.len() - 1].to_vec().into()),
-        };
-        Some(res)
     }
 
     pub fn is_self_type(&self) -> bool {
-        let Path::Normal { mod_path, generic_args, type_anchor } = self else {
-            return false;
-        };
-        type_anchor.is_none() && generic_args.as_deref().is_none() && mod_path.is_Self()
+        match self {
+            Path::BarePath(mod_path) => mod_path.is_Self(),
+            Path::Normal(path) => {
+                path.type_anchor().is_none()
+                    && path.mod_path().is_Self()
+                    && path.generic_args().iter().all(|args| args.is_none())
+            }
+            Path::LangItem(..) => false,
+        }
     }
 }
 
@@ -204,7 +238,7 @@ pub struct PathSegment<'a> {
 
 pub struct PathSegments<'a> {
     segments: &'a [Name],
-    generic_args: Option<&'a [Option<Interned<GenericArgs>>]>,
+    generic_args: Option<&'a [Option<GenericArgs>]>,
 }
 
 impl<'a> PathSegments<'a> {
@@ -224,7 +258,7 @@ impl<'a> PathSegments<'a> {
     pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
         let res = PathSegment {
             name: self.segments.get(idx)?,
-            args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_deref()),
+            args_and_bindings: self.generic_args.and_then(|it| it.get(idx)?.as_ref()),
         };
         Some(res)
     }
@@ -244,7 +278,7 @@ impl<'a> PathSegments<'a> {
         self.segments
             .iter()
             .zip(self.generic_args.into_iter().flatten().chain(iter::repeat(&None)))
-            .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_deref() })
+            .map(|(name, args)| PathSegment { name, args_and_bindings: args.as_ref() })
     }
 }
 
@@ -268,16 +302,6 @@ impl GenericArgs {
 
 impl From<Name> for Path {
     fn from(name: Name) -> Path {
-        Path::Normal {
-            type_anchor: None,
-            mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
-            generic_args: None,
-        }
-    }
-}
-
-impl From<Name> for Box<Path> {
-    fn from(name: Name) -> Box<Path> {
-        Box::new(Path::from(name))
+        Path::BarePath(Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))))
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index 70918a9358e..c328b9c6ce2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -2,13 +2,14 @@
 
 use std::iter;
 
-use crate::{lower::LowerCtx, type_ref::ConstRef};
+use crate::{lower::LowerCtx, path::NormalPath, type_ref::ConstRef};
 
 use hir_expand::{
     mod_path::resolve_crate_root,
     name::{AsName, Name},
 };
 use intern::{sym, Interned};
+use stdx::thin_vec::EmptyOptimizedThinVec;
 use syntax::ast::{self, AstNode, HasGenericArgs, HasTypeBounds};
 
 use crate::{
@@ -51,8 +52,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                             segment.param_list(),
                             segment.ret_type(),
                         )
-                    })
-                    .map(Interned::new);
+                    });
                 if args.is_some() {
                     generic_args.resize(segments.len(), None);
                     generic_args.push(args);
@@ -70,16 +70,14 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                 match trait_ref {
                     // <T>::foo
                     None => {
-                        type_anchor = Some(Interned::new(self_type));
+                        type_anchor = Some(self_type);
                         kind = PathKind::Plain;
                     }
                     // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
                     Some(trait_ref) => {
-                        let Path::Normal { mod_path, generic_args: path_generic_args, .. } =
-                            Path::from_src(ctx, trait_ref.path()?)?
-                        else {
-                            return None;
-                        };
+                        let path = Path::from_src(ctx, trait_ref.path()?)?;
+                        let mod_path = path.mod_path()?;
+                        let path_generic_args = path.generic_args();
                         let num_segments = mod_path.segments().len();
                         kind = mod_path.kind;
 
@@ -95,7 +93,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
 
                         // Insert the type reference (T in the above example) as Self parameter for the trait
                         let last_segment = generic_args.get_mut(segments.len() - num_segments)?;
-                        *last_segment = Some(Interned::new(match last_segment.take() {
+                        *last_segment = Some(match last_segment.take() {
                             Some(it) => GenericArgs {
                                 args: iter::once(self_type)
                                     .chain(it.args.iter().cloned())
@@ -110,7 +108,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
                                 has_self_type: true,
                                 ..GenericArgs::empty()
                             },
-                        }));
+                        });
                     }
                 }
             }
@@ -137,7 +135,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
         };
     }
     segments.reverse();
-    if !generic_args.is_empty() {
+    if !generic_args.is_empty() || type_anchor.is_some() {
         generic_args.resize(segments.len(), None);
         generic_args.reverse();
     }
@@ -166,11 +164,11 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option<Path
     }
 
     let mod_path = Interned::new(ModPath::from_segments(kind, segments));
-    return Some(Path::Normal {
-        type_anchor,
-        mod_path,
-        generic_args: if generic_args.is_empty() { None } else { Some(generic_args.into()) },
-    });
+    if type_anchor.is_none() && generic_args.is_empty() {
+        return Some(Path::BarePath(mod_path));
+    } else {
+        return Some(Path::Normal(NormalPath::new(type_anchor, mod_path, generic_args)));
+    }
 
     fn qualifier(path: &ast::Path) -> Option<ast::Path> {
         if let Some(q) = path.qualifier() {
@@ -194,11 +192,13 @@ pub(super) fn lower_generic_args(
         match generic_arg {
             ast::GenericArg::TypeArg(type_arg) => {
                 let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.ty());
-                type_ref.walk(&mut |tr| {
+                let types_map = lower_ctx.types_map();
+                TypeRef::walk(type_ref, &types_map, &mut |tr| {
                     if let TypeRef::ImplTrait(bounds) = tr {
                         lower_ctx.update_impl_traits_bounds(bounds.clone());
                     }
                 });
+                drop(types_map);
                 args.push(GenericArg::Type(type_ref));
             }
             ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
@@ -212,20 +212,19 @@ pub(super) fn lower_generic_args(
                     let name = name_ref.as_name();
                     let args = assoc_type_arg
                         .generic_arg_list()
-                        .and_then(|args| lower_generic_args(lower_ctx, args))
-                        .map(Interned::new);
+                        .and_then(|args| lower_generic_args(lower_ctx, args));
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
-                    let type_ref = type_ref.inspect(|tr| {
-                        tr.walk(&mut |tr| {
+                    let type_ref = type_ref.inspect(|&tr| {
+                        let types_map = lower_ctx.types_map();
+                        TypeRef::walk(tr, &types_map, &mut |tr| {
                             if let TypeRef::ImplTrait(bounds) = tr {
                                 lower_ctx.update_impl_traits_bounds(bounds.clone());
                             }
                         });
+                        drop(types_map);
                     });
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
-                        l.bounds()
-                            .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
-                            .collect()
+                        l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect()
                     } else {
                         Box::default()
                     };
@@ -269,7 +268,9 @@ fn lower_generic_args_from_fn_path(
         let type_ref = TypeRef::from_ast_opt(ctx, param.ty());
         param_types.push(type_ref);
     }
-    let args = Box::new([GenericArg::Type(TypeRef::Tuple(param_types))]);
+    let args = Box::new([GenericArg::Type(
+        ctx.alloc_type_ref_desugared(TypeRef::Tuple(EmptyOptimizedThinVec::from_iter(param_types))),
+    )]);
     let bindings = if let Some(ret_type) = ret_type {
         let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
         Box::new([AssociatedTypeBinding {
@@ -280,7 +281,7 @@ fn lower_generic_args_from_fn_path(
         }])
     } else {
         // -> ()
-        let type_ref = TypeRef::Tuple(Vec::new());
+        let type_ref = ctx.alloc_type_ref_desugared(TypeRef::unit());
         Box::new([AssociatedTypeBinding {
             name: Name::new_symbol_root(sym::Output.clone()),
             args: None,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
index d5ef17a91fb..9ceb82d5fd6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs
@@ -1,9 +1,11 @@
 //! Display and pretty printing routines.
 
-use std::fmt::{self, Write};
+use std::{
+    fmt::{self, Write},
+    mem,
+};
 
 use hir_expand::mod_path::PathKind;
-use intern::Interned;
 use itertools::Itertools;
 use span::Edition;
 
@@ -11,12 +13,15 @@ use crate::{
     db::DefDatabase,
     lang_item::LangItemTarget,
     path::{GenericArg, GenericArgs, Path},
-    type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
+    type_ref::{
+        Mutability, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, UseArgRef,
+    },
 };
 
 pub(crate) fn print_path(
     db: &dyn DefDatabase,
     path: &Path,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -58,7 +63,7 @@ pub(crate) fn print_path(
     match path.type_anchor() {
         Some(anchor) => {
             write!(buf, "<")?;
-            print_type_ref(db, anchor, buf, edition)?;
+            print_type_ref(db, anchor, map, buf, edition)?;
             write!(buf, ">::")?;
         }
         None => match path.kind() {
@@ -87,7 +92,7 @@ pub(crate) fn print_path(
         write!(buf, "{}", segment.name.display(db.upcast(), edition))?;
         if let Some(generics) = segment.args_and_bindings {
             write!(buf, "::<")?;
-            print_generic_args(db, generics, buf, edition)?;
+            print_generic_args(db, generics, map, buf, edition)?;
 
             write!(buf, ">")?;
         }
@@ -99,6 +104,7 @@ pub(crate) fn print_path(
 pub(crate) fn print_generic_args(
     db: &dyn DefDatabase,
     generics: &GenericArgs,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -106,7 +112,7 @@ pub(crate) fn print_generic_args(
     let args = if generics.has_self_type {
         let (self_ty, args) = generics.args.split_first().unwrap();
         write!(buf, "Self=")?;
-        print_generic_arg(db, self_ty, buf, edition)?;
+        print_generic_arg(db, self_ty, map, buf, edition)?;
         first = false;
         args
     } else {
@@ -117,7 +123,7 @@ pub(crate) fn print_generic_args(
             write!(buf, ", ")?;
         }
         first = false;
-        print_generic_arg(db, arg, buf, edition)?;
+        print_generic_arg(db, arg, map, buf, edition)?;
     }
     for binding in generics.bindings.iter() {
         if !first {
@@ -127,11 +133,11 @@ pub(crate) fn print_generic_args(
         write!(buf, "{}", binding.name.display(db.upcast(), edition))?;
         if !binding.bounds.is_empty() {
             write!(buf, ": ")?;
-            print_type_bounds(db, &binding.bounds, buf, edition)?;
+            print_type_bounds(db, &binding.bounds, map, buf, edition)?;
         }
-        if let Some(ty) = &binding.type_ref {
+        if let Some(ty) = binding.type_ref {
             write!(buf, " = ")?;
-            print_type_ref(db, ty, buf, edition)?;
+            print_type_ref(db, ty, map, buf, edition)?;
         }
     }
     Ok(())
@@ -140,11 +146,12 @@ pub(crate) fn print_generic_args(
 pub(crate) fn print_generic_arg(
     db: &dyn DefDatabase,
     arg: &GenericArg,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
     match arg {
-        GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition),
+        GenericArg::Type(ty) => print_type_ref(db, *ty, map, buf, edition),
         GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)),
         GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)),
     }
@@ -152,12 +159,13 @@ pub(crate) fn print_generic_arg(
 
 pub(crate) fn print_type_ref(
     db: &dyn DefDatabase,
-    type_ref: &TypeRef,
+    type_ref: TypeRefId,
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
     // FIXME: deduplicate with `HirDisplay` impl
-    match type_ref {
+    match &map[type_ref] {
         TypeRef::Never => write!(buf, "!")?,
         TypeRef::Placeholder => write!(buf, "_")?,
         TypeRef::Tuple(fields) => {
@@ -166,48 +174,48 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, field, buf, edition)?;
+                print_type_ref(db, *field, map, buf, edition)?;
             }
             write!(buf, ")")?;
         }
-        TypeRef::Path(path) => print_path(db, path, buf, edition)?,
+        TypeRef::Path(path) => print_path(db, path, map, buf, edition)?,
         TypeRef::RawPtr(pointee, mtbl) => {
             let mtbl = match mtbl {
                 Mutability::Shared => "*const",
                 Mutability::Mut => "*mut",
             };
             write!(buf, "{mtbl} ")?;
-            print_type_ref(db, pointee, buf, edition)?;
+            print_type_ref(db, *pointee, map, buf, edition)?;
         }
-        TypeRef::Reference(pointee, lt, mtbl) => {
-            let mtbl = match mtbl {
+        TypeRef::Reference(ref_) => {
+            let mtbl = match ref_.mutability {
                 Mutability::Shared => "",
                 Mutability::Mut => "mut ",
             };
             write!(buf, "&")?;
-            if let Some(lt) = lt {
+            if let Some(lt) = &ref_.lifetime {
                 write!(buf, "{} ", lt.name.display(db.upcast(), edition))?;
             }
             write!(buf, "{mtbl}")?;
-            print_type_ref(db, pointee, buf, edition)?;
+            print_type_ref(db, ref_.ty, map, buf, edition)?;
         }
-        TypeRef::Array(elem, len) => {
+        TypeRef::Array(array) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf, edition)?;
-            write!(buf, "; {}]", len.display(db.upcast(), edition))?;
+            print_type_ref(db, array.ty, map, buf, edition)?;
+            write!(buf, "; {}]", array.len.display(db.upcast(), edition))?;
         }
         TypeRef::Slice(elem) => {
             write!(buf, "[")?;
-            print_type_ref(db, elem, buf, edition)?;
+            print_type_ref(db, *elem, map, buf, edition)?;
             write!(buf, "]")?;
         }
-        TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => {
+        TypeRef::Fn(fn_) => {
             let ((_, return_type), args) =
-                args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
-            if *is_unsafe {
+                fn_.params().split_last().expect("TypeRef::Fn is missing return type");
+            if fn_.is_unsafe() {
                 write!(buf, "unsafe ")?;
             }
-            if let Some(abi) = abi {
+            if let Some(abi) = fn_.abi() {
                 buf.write_str("extern ")?;
                 buf.write_str(abi.as_str())?;
                 buf.write_char(' ')?;
@@ -217,16 +225,16 @@ pub(crate) fn print_type_ref(
                 if i != 0 {
                     write!(buf, ", ")?;
                 }
-                print_type_ref(db, typeref, buf, edition)?;
+                print_type_ref(db, *typeref, map, buf, edition)?;
             }
-            if *varargs {
+            if fn_.is_varargs() {
                 if !args.is_empty() {
                     write!(buf, ", ")?;
                 }
                 write!(buf, "...")?;
             }
             write!(buf, ") -> ")?;
-            print_type_ref(db, return_type, buf, edition)?;
+            print_type_ref(db, *return_type, map, buf, edition)?;
         }
         TypeRef::Macro(_ast_id) => {
             write!(buf, "<macro>")?;
@@ -234,11 +242,11 @@ pub(crate) fn print_type_ref(
         TypeRef::Error => write!(buf, "{{unknown}}")?,
         TypeRef::ImplTrait(bounds) => {
             write!(buf, "impl ")?;
-            print_type_bounds(db, bounds, buf, edition)?;
+            print_type_bounds(db, bounds, map, buf, edition)?;
         }
         TypeRef::DynTrait(bounds) => {
             write!(buf, "dyn ")?;
-            print_type_bounds(db, bounds, buf, edition)?;
+            print_type_bounds(db, bounds, map, buf, edition)?;
         }
     }
 
@@ -247,7 +255,8 @@ pub(crate) fn print_type_ref(
 
 pub(crate) fn print_type_bounds(
     db: &dyn DefDatabase,
-    bounds: &[Interned<TypeBound>],
+    bounds: &[TypeBound],
+    map: &TypesMap,
     buf: &mut dyn Write,
     edition: Edition,
 ) -> fmt::Result {
@@ -256,13 +265,13 @@ pub(crate) fn print_type_bounds(
             write!(buf, " + ")?;
         }
 
-        match bound.as_ref() {
+        match bound {
             TypeBound::Path(path, modifier) => {
                 match modifier {
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(buf, "?")?,
                 }
-                print_path(db, path, buf, edition)?;
+                print_path(db, path, map, buf, edition)?;
             }
             TypeBound::ForLifetime(lifetimes, path) => {
                 write!(
@@ -270,9 +279,25 @@ pub(crate) fn print_type_bounds(
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ")
                 )?;
-                print_path(db, path, buf, edition)?;
+                print_path(db, path, map, buf, edition)?;
             }
             TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?,
+            TypeBound::Use(args) => {
+                write!(buf, "use<")?;
+                let mut first = true;
+                for arg in args {
+                    if !mem::take(&mut first) {
+                        write!(buf, ", ")?;
+                    }
+                    match arg {
+                        UseArgRef::Name(it) => write!(buf, "{}", it.display(db.upcast(), edition))?,
+                        UseArgRef::Lifetime(it) => {
+                            write!(buf, "{}", it.name.display(db.upcast(), edition))?
+                        }
+                    }
+                }
+                write!(buf, ">")?
+            }
             TypeBound::Error => write!(buf, "{{unknown}}")?,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index f0f2210ec2c..26655e40ca7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -3,14 +3,17 @@ use std::{fmt, iter, mem};
 
 use base_db::CrateId;
 use hir_expand::{name::Name, MacroDefId};
-use intern::{sym, Interned};
+use intern::sym;
 use itertools::Itertools as _;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
 use triomphe::Arc;
 
 use crate::{
-    body::scope::{ExprScopes, ScopeId},
+    body::{
+        scope::{ExprScopes, ScopeId},
+        HygieneId,
+    },
     builtin_type::BuiltinType,
     data::ExternCrateDeclData,
     db::DefDatabase,
@@ -21,7 +24,7 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     path::{ModPath, Path, PathKind},
     per_ns::PerNs,
-    type_ref::LifetimeRef,
+    type_ref::{LifetimeRef, TypesMap},
     visibility::{RawVisibility, Visibility},
     AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
     ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
@@ -73,13 +76,15 @@ enum Scope {
     /// All the items and imported names of a module
     BlockScope(ModuleItemMap),
     /// Brings the generic parameters of an item into scope
-    GenericParams { def: GenericDefId, params: Interned<GenericParams> },
+    GenericParams { def: GenericDefId, params: Arc<GenericParams> },
     /// Brings `Self` in `impl` block into scope
     ImplDefScope(ImplId),
     /// Brings `Self` in enum, struct and union definitions into scope
     AdtScope(AdtId),
     /// Local bindings
     ExprScope(ExprScope),
+    /// Macro definition inside bodies that affects all paths after it in the same block.
+    MacroDefScope(Box<MacroDefId>),
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -162,7 +167,8 @@ impl Resolver {
         path: &Path,
     ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
         let path = match path {
-            Path::Normal { mod_path, .. } => mod_path,
+            Path::BarePath(mod_path) => mod_path,
+            Path::Normal(it) => it.mod_path(),
             Path::LangItem(l, seg) => {
                 let type_ns = match *l {
                     LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
@@ -188,7 +194,7 @@ impl Resolver {
 
         for scope in self.scopes() {
             match scope {
-                Scope::ExprScope(_) => continue,
+                Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
                 Scope::GenericParams { params, def } => {
                     if let Some(id) = params.find_type_by_name(first_name, *def) {
                         return Some((TypeNs::GenericParam(id), remaining_idx(), None));
@@ -257,9 +263,11 @@ impl Resolver {
         &self,
         db: &dyn DefDatabase,
         path: &Path,
+        mut hygiene_id: HygieneId,
     ) -> Option<ResolveValueResult> {
         let path = match path {
-            Path::Normal { mod_path, .. } => mod_path,
+            Path::BarePath(mod_path) => mod_path,
+            Path::Normal(it) => it.mod_path(),
             Path::LangItem(l, None) => {
                 return Some(ResolveValueResult::ValueNs(
                     match *l {
@@ -300,14 +308,22 @@ impl Resolver {
         }
 
         if n_segments <= 1 {
+            let mut hygiene_info = if !hygiene_id.is_root() {
+                let ctx = db.lookup_intern_syntax_context(hygiene_id.0);
+                ctx.outer_expn.map(|expansion| {
+                    let expansion = db.lookup_intern_macro_call(expansion);
+                    (ctx.parent, expansion.def)
+                })
+            } else {
+                None
+            };
             for scope in self.scopes() {
                 match scope {
                     Scope::ExprScope(scope) => {
-                        let entry = scope
-                            .expr_scopes
-                            .entries(scope.scope_id)
-                            .iter()
-                            .find(|entry| entry.name() == first_name);
+                        let entry =
+                            scope.expr_scopes.entries(scope.scope_id).iter().find(|entry| {
+                                entry.name() == first_name && entry.hygiene() == hygiene_id
+                            });
 
                         if let Some(e) = entry {
                             return Some(ResolveValueResult::ValueNs(
@@ -316,6 +332,21 @@ impl Resolver {
                             ));
                         }
                     }
+                    Scope::MacroDefScope(macro_id) => {
+                        if let Some((parent_ctx, label_macro_id)) = hygiene_info {
+                            if label_macro_id == **macro_id {
+                                // A macro is allowed to refer to variables from before its declaration.
+                                // Therefore, if we got to the rib of its declaration, give up its hygiene
+                                // and use its parent expansion.
+                                let parent_ctx = db.lookup_intern_syntax_context(parent_ctx);
+                                hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent);
+                                hygiene_info = parent_ctx.outer_expn.map(|expansion| {
+                                    let expansion = db.lookup_intern_macro_call(expansion);
+                                    (parent_ctx.parent, expansion.def)
+                                });
+                            }
+                        }
+                    }
                     Scope::GenericParams { params, def } => {
                         if let Some(id) = params.find_const_by_name(first_name, *def) {
                             let val = ValueNs::GenericParam(id);
@@ -342,7 +373,7 @@ impl Resolver {
         } else {
             for scope in self.scopes() {
                 match scope {
-                    Scope::ExprScope(_) => continue,
+                    Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue,
                     Scope::GenericParams { params, def } => {
                         if let Some(id) = params.find_type_by_name(first_name, *def) {
                             let ty = TypeNs::GenericParam(id);
@@ -393,8 +424,9 @@ impl Resolver {
         &self,
         db: &dyn DefDatabase,
         path: &Path,
+        hygiene: HygieneId,
     ) -> Option<ValueNs> {
-        match self.resolve_path_in_value_ns(db, path)? {
+        match self.resolve_path_in_value_ns(db, path, hygiene)? {
             ResolveValueResult::ValueNs(it, _) => Some(it),
             ResolveValueResult::Partial(..) => None,
         }
@@ -590,13 +622,15 @@ impl Resolver {
 
     pub fn where_predicates_in_scope(
         &self,
-    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
+    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, (&GenericDefId, &TypesMap))> {
         self.scopes()
             .filter_map(|scope| match scope {
                 Scope::GenericParams { params, def } => Some((params, def)),
                 _ => None,
             })
-            .flat_map(|(params, def)| params.where_predicates().zip(iter::repeat(def)))
+            .flat_map(|(params, def)| {
+                params.where_predicates().zip(iter::repeat((def, &params.types_map)))
+            })
     }
 
     pub fn generic_def(&self) -> Option<GenericDefId> {
@@ -606,13 +640,20 @@ impl Resolver {
         })
     }
 
-    pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
+    pub fn generic_params(&self) -> Option<&Arc<GenericParams>> {
         self.scopes().find_map(|scope| match scope {
             Scope::GenericParams { params, .. } => Some(params),
             _ => None,
         })
     }
 
+    pub fn all_generic_params(&self) -> impl Iterator<Item = (&GenericParams, &GenericDefId)> {
+        self.scopes().filter_map(|scope| match scope {
+            Scope::GenericParams { params, def } => Some((&**params, def)),
+            _ => None,
+        })
+    }
+
     pub fn body_owner(&self) -> Option<DefWithBodyId> {
         self.scopes().find_map(|scope| match scope {
             Scope::ExprScope(it) => Some(it.owner),
@@ -622,7 +663,7 @@ impl Resolver {
 
     pub fn type_owner(&self) -> Option<TypeOwnerId> {
         self.scopes().find_map(|scope| match scope {
-            Scope::BlockScope(_) => None,
+            Scope::BlockScope(_) | Scope::MacroDefScope(_) => None,
             &Scope::GenericParams { def, .. } => Some(def.into()),
             &Scope::ImplDefScope(id) => Some(id.into()),
             &Scope::AdtScope(adt) => Some(adt.into()),
@@ -653,6 +694,9 @@ impl Resolver {
             expr_scopes: &Arc<ExprScopes>,
             scope_id: ScopeId,
         ) {
+            if let Some(macro_id) = expr_scopes.macro_def(scope_id) {
+                resolver.scopes.push(Scope::MacroDefScope(macro_id.clone()));
+            }
             resolver.scopes.push(Scope::ExprScope(ExprScope {
                 owner,
                 expr_scopes: expr_scopes.clone(),
@@ -670,7 +714,7 @@ impl Resolver {
         }
 
         let start = self.scopes.len();
-        let innermost_scope = self.scopes().next();
+        let innermost_scope = self.scopes().find(|scope| !matches!(scope, Scope::MacroDefScope(_)));
         match innermost_scope {
             Some(&Scope::ExprScope(ExprScope { scope_id, ref expr_scopes, owner })) => {
                 let expr_scopes = expr_scopes.clone();
@@ -794,6 +838,7 @@ impl Scope {
                     acc.add_local(e.name(), e.binding());
                 });
             }
+            Scope::MacroDefScope(_) => {}
         }
     }
 }
@@ -833,6 +878,9 @@ fn resolver_for_scope_(
             // already traverses all parents, so this is O(n²). I think we could only store the
             // innermost module scope instead?
         }
+        if let Some(macro_id) = scopes.macro_def(scope) {
+            r = r.push_scope(Scope::MacroDefScope(macro_id.clone()));
+        }
 
         r = r.push_expr_scope(owner, Arc::clone(&scopes), scope);
     }
@@ -1006,12 +1054,12 @@ impl HasResolver for ModuleId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         let mut def_map = self.def_map(db);
         let mut module_id = self.local_id;
-        let mut modules: SmallVec<[_; 1]> = smallvec![];
 
         if !self.is_block_module() {
             return Resolver { scopes: vec![], module_scope: ModuleItemMap { def_map, module_id } };
         }
 
+        let mut modules: SmallVec<[_; 1]> = smallvec![];
         while let Some(parent) = def_map.parent() {
             let block_def_map = mem::replace(&mut def_map, parent.def_map(db));
             modules.push(block_def_map);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 4db21eb46bd..0c36c88fb09 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -198,7 +198,10 @@ impl TestDB {
             .filter_map(|node| {
                 let block = ast::BlockExpr::cast(node)?;
                 let expr = ast::Expr::from(block);
-                let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?;
+                let expr_id = source_map
+                    .node_expr(InFile::new(position.file_id.into(), &expr))?
+                    .as_expr()
+                    .unwrap();
                 let scope = scopes.scope_for(expr_id).unwrap();
                 Some(scope)
             });
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 3aeb88047a0..4edb6835922 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -191,6 +191,11 @@ impl Visibility {
                     return None;
                 }
 
+                let def_block = def_map.block_id();
+                if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+                    return None;
+                }
+
                 let mut a_ancestors =
                     iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
                 let mut b_ancestors =
@@ -210,6 +215,43 @@ impl Visibility {
             }
         }
     }
+
+    /// Returns the least permissive visibility of `self` and `other`.
+    ///
+    /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
+    /// visible in unrelated modules).
+    pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
+        match (self, other) {
+            (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
+            (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
+                if mod_a.krate != mod_b.krate {
+                    return None;
+                }
+
+                let def_block = def_map.block_id();
+                if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+                    return None;
+                }
+
+                let mut a_ancestors =
+                    iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+                let mut b_ancestors =
+                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
+
+                if a_ancestors.any(|m| m == mod_b.local_id) {
+                    // B is above A
+                    return Some(Visibility::Module(mod_a, expl_b));
+                }
+
+                if b_ancestors.any(|m| m == mod_a.local_id) {
+                    // A is above B
+                    return Some(Visibility::Module(mod_b, expl_a));
+                }
+
+                None
+            }
+        }
+    }
 }
 
 /// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index 79cfeb4cf18..12df3cf2188 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -26,6 +26,7 @@ use crate::{
 /// Syntactical attributes, without filtering of `cfg_attr`s.
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct RawAttrs {
+    // FIXME: This can become `Box<[Attr]>` if https://internals.rust-lang.org/t/layout-of-dst-box/21728?u=chrefr is accepted.
     entries: Option<ThinArc<(), Attr>>,
 }
 
@@ -169,6 +170,10 @@ impl RawAttrs {
         };
         RawAttrs { entries }
     }
+
+    pub fn is_empty(&self) -> bool {
+        self.entries.is_none()
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index a8191189157..f48de807c28 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -227,7 +227,7 @@ pub(crate) fn dump_syntax_contexts(db: &dyn ExpandDatabase) -> String {
             &'a SyntaxContextData,
         );
 
-        impl<'a> std::fmt::Debug for SyntaxContextDebug<'a> {
+        impl std::fmt::Debug for SyntaxContextDebug<'_> {
             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 fancy_debug(self.2, self.1, self.0, f)
             }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 5d5f72490d0..7d2f556406d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -165,40 +165,73 @@ pub enum ExpandErrorKind {
 }
 
 impl ExpandError {
-    pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
+    pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
         self.inner.0.render_to_string(db)
     }
 }
 
+pub struct RenderedExpandError {
+    pub message: String,
+    pub error: bool,
+    pub kind: &'static str,
+}
+
+impl RenderedExpandError {
+    const GENERAL_KIND: &str = "macro-error";
+}
+
 impl ExpandErrorKind {
-    pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> (String, bool) {
+    pub fn render_to_string(&self, db: &dyn ExpandDatabase) -> RenderedExpandError {
         match self {
-            ExpandErrorKind::ProcMacroAttrExpansionDisabled => {
-                ("procedural attribute macro expansion is disabled".to_owned(), false)
-            }
-            ExpandErrorKind::MacroDisabled => {
-                ("proc-macro is explicitly disabled".to_owned(), false)
-            }
+            ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError {
+                message: "procedural attribute macro expansion is disabled".to_owned(),
+                error: false,
+                kind: "proc-macros-disabled",
+            },
+            ExpandErrorKind::MacroDisabled => RenderedExpandError {
+                message: "proc-macro is explicitly disabled".to_owned(),
+                error: false,
+                kind: "proc-macro-disabled",
+            },
             &ExpandErrorKind::MissingProcMacroExpander(def_crate) => {
                 match db.proc_macros().get_error_for_crate(def_crate) {
-                    Some((e, hard_err)) => (e.to_owned(), hard_err),
-                    None => (
-                        format!(
-                            "internal error: proc-macro map is missing error entry for crate {def_crate:?}"
-                        ),
-                        true,
-                    ),
+                    Some((e, hard_err)) => RenderedExpandError {
+                        message: e.to_owned(),
+                        error: hard_err,
+                        kind: RenderedExpandError::GENERAL_KIND,
+                    },
+                    None => RenderedExpandError {
+                        message: format!("internal error: proc-macro map is missing error entry for crate {def_crate:?}"),
+                        error: true,
+                        kind: RenderedExpandError::GENERAL_KIND,
+                    },
                 }
             }
-            ExpandErrorKind::MacroDefinition => {
-                ("macro definition has parse errors".to_owned(), true)
-            }
-            ExpandErrorKind::Mbe(e) => (e.to_string(), true),
-            ExpandErrorKind::RecursionOverflow => {
-                ("overflow expanding the original macro".to_owned(), true)
-            }
-            ExpandErrorKind::Other(e) => ((**e).to_owned(), true),
-            ExpandErrorKind::ProcMacroPanic(e) => (format!("proc-macro panicked: {e}"), true),
+            ExpandErrorKind::MacroDefinition => RenderedExpandError {
+                message: "macro definition has parse errors".to_owned(),
+                error: true,
+                kind: RenderedExpandError::GENERAL_KIND,
+            },
+            ExpandErrorKind::Mbe(e) => RenderedExpandError {
+                message: e.to_string(),
+                error: true,
+                kind: RenderedExpandError::GENERAL_KIND,
+            },
+            ExpandErrorKind::RecursionOverflow => RenderedExpandError {
+                message: "overflow expanding the original macro".to_owned(),
+                error: true,
+                kind: RenderedExpandError::GENERAL_KIND,
+            },
+            ExpandErrorKind::Other(e) => RenderedExpandError {
+                message: (**e).to_owned(),
+                error: true,
+                kind: RenderedExpandError::GENERAL_KIND,
+            },
+            ExpandErrorKind::ProcMacroPanic(e) => RenderedExpandError {
+                message: format!("proc-macro panicked: {e}"),
+                error: true,
+                kind: RenderedExpandError::GENERAL_KIND,
+            },
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 54313904a7e..267d5458333 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -18,6 +18,8 @@ use syntax::utils::is_raw_identifier;
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Name {
     symbol: Symbol,
+    // If you are making this carry actual hygiene, beware that the special handling for variables and labels
+    // in bodies can go.
     ctx: (),
 }
 
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 7a3846df40e..2b5342314a6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -114,7 +114,7 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
 }
 
 #[allow(private_bounds)]
-impl<'table, 'db, T: TrackAutoderefSteps> Autoderef<'table, 'db, T> {
+impl<T: TrackAutoderefSteps> Autoderef<'_, '_, T> {
     pub(crate) fn step_count(&self) -> usize {
         self.steps.len()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index f7bacbd49b3..4bc78afacc0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -521,7 +521,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     }
 }
 
-impl<'a> ChalkContext<'a> {
+impl ChalkContext<'_> {
     fn edition(&self) -> Edition {
         self.db.crate_graph()[self.krate].edition
     }
@@ -615,8 +615,9 @@ pub(crate) fn associated_ty_data_query(
     let type_alias_data = db.type_alias_data(type_alias);
     let generic_params = generics(db.upcast(), type_alias.into());
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
-    let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into())
-        .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
+    let ctx =
+        crate::TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, type_alias.into())
+            .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
 
     let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
         .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
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 e41058aac2a..091cfcd4654 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -3,7 +3,7 @@
 use base_db::{ra_salsa::Cycle, CrateId};
 use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
 use hir_def::{
-    body::Body,
+    body::{Body, HygieneId},
     hir::{Expr, ExprId},
     path::Path,
     resolver::{Resolver, ValueNs},
@@ -11,7 +11,7 @@ use hir_def::{
     ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
 };
 use hir_expand::Lookup;
-use stdx::{never, IsNoneOr};
+use stdx::never;
 use triomphe::Arc;
 
 use crate::{
@@ -80,7 +80,7 @@ pub(crate) fn path_to_const<'g>(
     debruijn: DebruijnIndex,
     expected_ty: Ty,
 ) -> Option<Const> {
-    match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
+    match resolver.resolve_path_in_value_ns_fully(db.upcast(), path, HygieneId::ROOT) {
         Some(ValueNs::GenericParam(p)) => {
             let ty = db.const_param_ty(p);
             let value = match mode {
@@ -287,7 +287,7 @@ pub(crate) fn const_eval_discriminant_variant(
     }
 
     let repr = db.enum_data(loc.parent).repr;
-    let is_signed = IsNoneOr::is_none_or(repr.and_then(|repr| repr.int), |int| int.is_signed());
+    let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
 
     let mir_body = db.monomorphized_mir_body(
         def,
@@ -319,7 +319,7 @@ pub(crate) fn eval_to_const(
             return true;
         }
         let mut r = false;
-        body[expr].walk_child_exprs(|idx| r |= has_closure(body, idx));
+        body.walk_child_exprs(expr, |idx| r |= has_closure(body, idx));
         r
     }
     if has_closure(ctx.body, expr) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 7f6b7e392b3..c9ab0acc084 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -309,7 +309,7 @@ impl<'a> DeclValidator<'a> {
     /// Check incorrect names for struct fields.
     fn validate_struct_fields(&mut self, struct_id: StructId) {
         let data = self.db.struct_data(struct_id);
-        let VariantData::Record(fields) = data.variant_data.as_ref() else {
+        let VariantData::Record { fields, .. } = data.variant_data.as_ref() else {
             return;
         };
         let edition = self.edition(struct_id);
@@ -469,7 +469,7 @@ impl<'a> DeclValidator<'a> {
     /// Check incorrect names for fields of enum variant.
     fn validate_enum_variant_fields(&mut self, variant_id: EnumVariantId) {
         let variant_data = self.db.enum_variant_data(variant_id);
-        let VariantData::Record(fields) = variant_data.variant_data.as_ref() else {
+        let VariantData::Record { fields, .. } = variant_data.variant_data.as_ref() else {
             return;
         };
         let edition = self.edition(variant_id);
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 f8b5c7d0ce2..92404e3a10e 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
@@ -289,10 +289,12 @@ impl ExprValidator {
         match &self.body[scrutinee_expr] {
             Expr::UnaryOp { op: UnaryOp::Deref, .. } => false,
             Expr::Path(path) => {
-                let value_or_partial = self
-                    .owner
-                    .resolver(db.upcast())
-                    .resolve_path_in_value_ns_fully(db.upcast(), path);
+                let value_or_partial =
+                    self.owner.resolver(db.upcast()).resolve_path_in_value_ns_fully(
+                        db.upcast(),
+                        path,
+                        self.body.expr_path_hygiene(scrutinee_expr),
+                    );
                 value_or_partial.map_or(true, |v| !matches!(v, ValueNs::StaticId(_)))
             }
             Expr::Field { expr, .. } => match self.infer.type_of_expr[*expr].kind(Interner) {
@@ -546,10 +548,7 @@ pub fn record_literal_missing_fields(
     expr: &Expr,
 ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> {
     let (fields, exhaustive) = match expr {
-        Expr::RecordLit { fields, spread, ellipsis, is_assignee_expr, .. } => {
-            let exhaustive = if *is_assignee_expr { !*ellipsis } else { spread.is_none() };
-            (fields, exhaustive)
-        }
+        Expr::RecordLit { fields, spread, .. } => (fields, spread.is_none()),
         _ => return None,
     };
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index 4bc07bc9ec8..c5d8c956615 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -341,7 +341,7 @@ impl HirDisplay for Pat {
                     };
 
                     let variant_data = variant.variant_data(f.db.upcast());
-                    if let VariantData::Record(rec_fields) = &*variant_data {
+                    if let VariantData::Record { fields: rec_fields, .. } = &*variant_data {
                         write!(f, " {{ ")?;
 
                         let mut printed = 0;
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 1066a28c3ff..58de19ba81e 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
@@ -519,7 +519,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> {
     }
 }
 
-impl<'db> fmt::Debug for MatchCheckCtx<'db> {
+impl fmt::Debug for MatchCheckCtx<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("MatchCheckCtx").finish()
     }
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 bcfc37c8671..c7f7fb7ad3d 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
@@ -3,7 +3,7 @@
 
 use hir_def::{
     body::Body,
-    hir::{Expr, ExprId, UnaryOp},
+    hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp},
     resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
     type_ref::Rawness,
     DefWithBodyId,
@@ -16,7 +16,7 @@ use crate::{
 /// Returns `(unsafe_exprs, fn_is_unsafe)`.
 ///
 /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
-pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>, bool) {
+pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) {
     let _p = tracing::info_span!("missing_unsafe").entered();
 
     let mut res = Vec::new();
@@ -32,7 +32,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
     let infer = db.infer(def);
     unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
         if !expr.inside_unsafe_block {
-            res.push(expr.expr);
+            res.push(expr.node);
         }
     });
 
@@ -40,7 +40,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprId>,
 }
 
 pub struct UnsafeExpr {
-    pub expr: ExprId,
+    pub node: ExprOrPatId,
     pub inside_unsafe_block: bool,
 }
 
@@ -75,26 +75,29 @@ fn walk_unsafe(
     inside_unsafe_block: bool,
     unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
 ) {
+    let mut mark_unsafe_path = |path, node| {
+        let g = resolver.update_to_inner_scope(db.upcast(), def, current);
+        let hygiene = body.expr_or_pat_path_hygiene(node);
+        let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene);
+        if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
+            let static_data = db.static_data(id);
+            if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
+                unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block });
+            }
+        }
+        resolver.reset_to_guard(g);
+    };
+
     let expr = &body.exprs[current];
     match expr {
         &Expr::Call { callee, .. } => {
             if let Some(func) = infer[callee].as_fn_def(db) {
                 if is_fn_unsafe_to_call(db, func) {
-                    unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
-                }
-            }
-        }
-        Expr::Path(path) => {
-            let g = resolver.update_to_inner_scope(db.upcast(), def, current);
-            let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
-            if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
-                let static_data = db.static_data(id);
-                if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) {
-                    unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+                    unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
                 }
             }
-            resolver.reset_to_guard(g);
         }
+        Expr::Path(path) => mark_unsafe_path(path, current.into()),
         Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => {
             if let Expr::Path(_) = body.exprs[*expr] {
                 // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`,
@@ -108,23 +111,30 @@ fn walk_unsafe(
                 .map(|(func, _)| is_fn_unsafe_to_call(db, func))
                 .unwrap_or(false)
             {
-                unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+                unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
             }
         }
         Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
             if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
-                unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
+                unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block });
             }
         }
         Expr::Unsafe { .. } => {
-            return expr.walk_child_exprs(|child| {
+            return body.walk_child_exprs(current, |child| {
                 walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
             });
         }
+        &Expr::Assignment { target, value: _ } => {
+            body.walk_pats(target, &mut |pat| {
+                if let Pat::Path(path) = &body[pat] {
+                    mark_unsafe_path(path, pat.into());
+                }
+            });
+        }
         _ => {}
     }
 
-    expr.walk_child_exprs(|child| {
+    body.walk_child_exprs(current, |child| {
         walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb);
     });
 }
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 10f5bcdad86..277dabe9aa3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -19,7 +19,9 @@ use hir_def::{
     lang_item::{LangItem, LangItemTarget},
     nameres::DefMap,
     path::{Path, PathKind},
-    type_ref::{TraitBoundModifier, TypeBound, TypeRef},
+    type_ref::{
+        TraitBoundModifier, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, UseArgRef,
+    },
     visibility::Visibility,
     GenericDefId, HasModule, ImportPathConfig, ItemContainerId, LocalFieldId, Lookup, ModuleDefId,
     ModuleId, TraitId,
@@ -806,7 +808,7 @@ fn render_variant_after_name(
     memory_map: &MemoryMap,
 ) -> Result<(), HirDisplayError> {
     match data {
-        VariantData::Record(fields) | VariantData::Tuple(fields) => {
+        VariantData::Record { fields, .. } | VariantData::Tuple { fields, .. } => {
             let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
                 let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
                 let ty = field_types[id].clone().substitute(Interner, subst);
@@ -817,7 +819,7 @@ fn render_variant_after_name(
                 render_const_scalar(f, &b[offset..offset + size], memory_map, &ty)
             };
             let mut it = fields.iter();
-            if matches!(data, VariantData::Record(_)) {
+            if matches!(data, VariantData::Record { .. }) {
                 write!(f, " {{")?;
                 if let Some((id, data)) = it.next() {
                     write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?;
@@ -1897,100 +1899,150 @@ pub fn write_visibility(
     }
 }
 
-impl HirDisplay for TypeRef {
+pub trait HirDisplayWithTypesMap {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError>;
+}
+
+impl<T: ?Sized + HirDisplayWithTypesMap> HirDisplayWithTypesMap for &'_ T {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
+        T::hir_fmt(&**self, f, types_map)
+    }
+}
+
+pub fn hir_display_with_types_map<'a, T: HirDisplayWithTypesMap + 'a>(
+    value: T,
+    types_map: &'a TypesMap,
+) -> impl HirDisplay + 'a {
+    TypesMapAdapter(value, types_map)
+}
+
+struct TypesMapAdapter<'a, T>(T, &'a TypesMap);
+
+impl<'a, T> TypesMapAdapter<'a, T> {
+    fn wrap(types_map: &'a TypesMap) -> impl Fn(T) -> TypesMapAdapter<'a, T> {
+        move |value| TypesMapAdapter(value, types_map)
+    }
+}
+
+impl<T: HirDisplayWithTypesMap> HirDisplay for TypesMapAdapter<'_, T> {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        match self {
+        T::hir_fmt(&self.0, f, self.1)
+    }
+}
+
+impl HirDisplayWithTypesMap for TypeRefId {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
+        match &types_map[*self] {
             TypeRef::Never => write!(f, "!")?,
             TypeRef::Placeholder => write!(f, "_")?,
             TypeRef::Tuple(elems) => {
                 write!(f, "(")?;
-                f.write_joined(elems, ", ")?;
+                f.write_joined(elems.iter().map(TypesMapAdapter::wrap(types_map)), ", ")?;
                 if elems.len() == 1 {
                     write!(f, ",")?;
                 }
                 write!(f, ")")?;
             }
-            TypeRef::Path(path) => path.hir_fmt(f)?,
+            TypeRef::Path(path) => path.hir_fmt(f, types_map)?,
             TypeRef::RawPtr(inner, mutability) => {
                 let mutability = match mutability {
                     hir_def::type_ref::Mutability::Shared => "*const ",
                     hir_def::type_ref::Mutability::Mut => "*mut ",
                 };
                 write!(f, "{mutability}")?;
-                inner.hir_fmt(f)?;
+                inner.hir_fmt(f, types_map)?;
             }
-            TypeRef::Reference(inner, lifetime, mutability) => {
-                let mutability = match mutability {
+            TypeRef::Reference(ref_) => {
+                let mutability = match ref_.mutability {
                     hir_def::type_ref::Mutability::Shared => "",
                     hir_def::type_ref::Mutability::Mut => "mut ",
                 };
                 write!(f, "&")?;
-                if let Some(lifetime) = lifetime {
+                if let Some(lifetime) = &ref_.lifetime {
                     write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
                 write!(f, "{mutability}")?;
-                inner.hir_fmt(f)?;
+                ref_.ty.hir_fmt(f, types_map)?;
             }
-            TypeRef::Array(inner, len) => {
+            TypeRef::Array(array) => {
                 write!(f, "[")?;
-                inner.hir_fmt(f)?;
-                write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?;
+                array.ty.hir_fmt(f, types_map)?;
+                write!(f, "; {}]", array.len.display(f.db.upcast(), f.edition()))?;
             }
             TypeRef::Slice(inner) => {
                 write!(f, "[")?;
-                inner.hir_fmt(f)?;
+                inner.hir_fmt(f, types_map)?;
                 write!(f, "]")?;
             }
-            &TypeRef::Fn(ref parameters, is_varargs, is_unsafe, ref abi) => {
-                if is_unsafe {
+            TypeRef::Fn(fn_) => {
+                if fn_.is_unsafe() {
                     write!(f, "unsafe ")?;
                 }
-                if let Some(abi) = abi {
+                if let Some(abi) = fn_.abi() {
                     f.write_str("extern \"")?;
                     f.write_str(abi.as_str())?;
                     f.write_str("\" ")?;
                 }
                 write!(f, "fn(")?;
-                if let Some(((_, return_type), function_parameters)) = parameters.split_last() {
+                if let Some(((_, return_type), function_parameters)) = fn_.params().split_last() {
                     for index in 0..function_parameters.len() {
                         let (param_name, param_type) = &function_parameters[index];
                         if let Some(name) = param_name {
                             write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?;
                         }
 
-                        param_type.hir_fmt(f)?;
+                        param_type.hir_fmt(f, types_map)?;
 
                         if index != function_parameters.len() - 1 {
                             write!(f, ", ")?;
                         }
                     }
-                    if is_varargs {
-                        write!(f, "{}...", if parameters.len() == 1 { "" } else { ", " })?;
+                    if fn_.is_varargs() {
+                        write!(f, "{}...", if fn_.params().len() == 1 { "" } else { ", " })?;
                     }
                     write!(f, ")")?;
-                    match &return_type {
+                    match &types_map[*return_type] {
                         TypeRef::Tuple(tup) if tup.is_empty() => {}
                         _ => {
                             write!(f, " -> ")?;
-                            return_type.hir_fmt(f)?;
+                            return_type.hir_fmt(f, types_map)?;
                         }
                     }
                 }
             }
             TypeRef::ImplTrait(bounds) => {
                 write!(f, "impl ")?;
-                f.write_joined(bounds, " + ")?;
+                f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
             }
             TypeRef::DynTrait(bounds) => {
                 write!(f, "dyn ")?;
-                f.write_joined(bounds, " + ")?;
+                f.write_joined(bounds.iter().map(TypesMapAdapter::wrap(types_map)), " + ")?;
             }
             TypeRef::Macro(macro_call) => {
-                let ctx = hir_def::lower::LowerCtx::new(f.db.upcast(), macro_call.file_id);
+                let (mut types_map, mut types_source_map) =
+                    (TypesMap::default(), TypesSourceMap::default());
+                let ctx = hir_def::lower::LowerCtx::new(
+                    f.db.upcast(),
+                    macro_call.file_id,
+                    &mut types_map,
+                    &mut types_source_map,
+                );
                 let macro_call = macro_call.to_node(f.db.upcast());
                 match macro_call.path() {
                     Some(path) => match Path::from_src(&ctx, path) {
-                        Some(path) => path.hir_fmt(f)?,
+                        Some(path) => path.hir_fmt(f, &types_map)?,
                         None => write!(f, "{{macro}}")?,
                     },
                     None => write!(f, "{{macro}}")?,
@@ -2003,15 +2055,19 @@ impl HirDisplay for TypeRef {
     }
 }
 
-impl HirDisplay for TypeBound {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for TypeBound {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match self {
             TypeBound::Path(path, modifier) => {
                 match modifier {
                     TraitBoundModifier::None => (),
                     TraitBoundModifier::Maybe => write!(f, "?")?,
                 }
-                path.hir_fmt(f)
+                path.hir_fmt(f, types_map)
             }
             TypeBound::Lifetime(lifetime) => {
                 write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))
@@ -2023,19 +2079,36 @@ impl HirDisplay for TypeBound {
                     "for<{}> ",
                     lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ")
                 )?;
-                path.hir_fmt(f)
+                path.hir_fmt(f, types_map)
+            }
+            TypeBound::Use(args) => {
+                let edition = f.edition();
+                write!(
+                    f,
+                    "use<{}> ",
+                    args.iter()
+                        .map(|it| match it {
+                            UseArgRef::Lifetime(lt) => lt.name.display(f.db.upcast(), edition),
+                            UseArgRef::Name(n) => n.display(f.db.upcast(), edition),
+                        })
+                        .format(", ")
+                )
             }
             TypeBound::Error => write!(f, "{{error}}"),
         }
     }
 }
 
-impl HirDisplay for Path {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for Path {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match (self.type_anchor(), self.kind()) {
             (Some(anchor), _) => {
                 write!(f, "<")?;
-                anchor.hir_fmt(f)?;
+                anchor.hir_fmt(f, types_map)?;
                 write!(f, ">")?;
             }
             (_, PathKind::Plain) => {}
@@ -2078,7 +2151,7 @@ impl HirDisplay for Path {
         });
         if let Some(ty) = trait_self_ty {
             write!(f, "<")?;
-            ty.hir_fmt(f)?;
+            ty.hir_fmt(f, types_map)?;
             write!(f, " as ")?;
             // Now format the path of the trait...
         }
@@ -2094,21 +2167,26 @@ impl HirDisplay for Path {
                 if generic_args.desugared_from_fn {
                     // First argument will be a tuple, which already includes the parentheses.
                     // If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
-                    if let hir_def::path::GenericArg::Type(TypeRef::Tuple(v)) =
-                        &generic_args.args[0]
-                    {
+                    let tuple = match generic_args.args[0] {
+                        hir_def::path::GenericArg::Type(ty) => match &types_map[ty] {
+                            TypeRef::Tuple(it) => Some(it),
+                            _ => None,
+                        },
+                        _ => None,
+                    };
+                    if let Some(v) = tuple {
                         if v.len() == 1 {
                             write!(f, "(")?;
-                            v[0].hir_fmt(f)?;
+                            v[0].hir_fmt(f, types_map)?;
                             write!(f, ")")?;
                         } else {
-                            generic_args.args[0].hir_fmt(f)?;
+                            generic_args.args[0].hir_fmt(f, types_map)?;
                         }
                     }
-                    if let Some(ret) = &generic_args.bindings[0].type_ref {
-                        if !matches!(ret, TypeRef::Tuple(v) if v.is_empty()) {
+                    if let Some(ret) = generic_args.bindings[0].type_ref {
+                        if !matches!(&types_map[ret], TypeRef::Tuple(v) if v.is_empty()) {
                             write!(f, " -> ")?;
-                            ret.hir_fmt(f)?;
+                            ret.hir_fmt(f, types_map)?;
                         }
                     }
                     return Ok(());
@@ -2123,7 +2201,7 @@ impl HirDisplay for Path {
                     } else {
                         write!(f, ", ")?;
                     }
-                    arg.hir_fmt(f)?;
+                    arg.hir_fmt(f, types_map)?;
                 }
                 for binding in generic_args.bindings.iter() {
                     if first {
@@ -2136,11 +2214,14 @@ impl HirDisplay for Path {
                     match &binding.type_ref {
                         Some(ty) => {
                             write!(f, " = ")?;
-                            ty.hir_fmt(f)?
+                            ty.hir_fmt(f, types_map)?
                         }
                         None => {
                             write!(f, ": ")?;
-                            f.write_joined(binding.bounds.iter(), " + ")?;
+                            f.write_joined(
+                                binding.bounds.iter().map(TypesMapAdapter::wrap(types_map)),
+                                " + ",
+                            )?;
                         }
                     }
                 }
@@ -2162,10 +2243,14 @@ impl HirDisplay for Path {
     }
 }
 
-impl HirDisplay for hir_def::path::GenericArg {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
+impl HirDisplayWithTypesMap for hir_def::path::GenericArg {
+    fn hir_fmt(
+        &self,
+        f: &mut HirFormatter<'_>,
+        types_map: &TypesMap,
+    ) -> Result<(), HirDisplayError> {
         match self {
-            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
+            hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f, types_map),
             hir_def::path::GenericArg::Const(c) => {
                 write!(f, "{}", c.display(f.db.upcast(), f.edition()))
             }
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 e0d1758210e..3d21785a70a 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
@@ -266,7 +266,7 @@ fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>(
         trait_self_param_idx: usize,
         allow_self_projection: AllowSelfProjection,
     }
-    impl<'a> TypeVisitor<Interner> for IllegalSelfTypeVisitor<'a> {
+    impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> {
         type BreakTy = ();
 
         fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index 89ca707c2e6..c094bc39512 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -16,12 +16,13 @@ use hir_def::{
         GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
         TypeParamProvenance,
     },
+    type_ref::TypesMap,
     ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId,
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
-use intern::Interned;
 use itertools::chain;
 use stdx::TupleExt;
+use triomphe::Arc;
 
 use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
 
@@ -34,7 +35,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
 #[derive(Clone, Debug)]
 pub(crate) struct Generics {
     def: GenericDefId,
-    params: Interned<GenericParams>,
+    params: Arc<GenericParams>,
     parent_generics: Option<Box<Generics>>,
     has_trait_self_param: bool,
 }
@@ -85,6 +86,18 @@ impl Generics {
         self.iter_self().chain(self.iter_parent())
     }
 
+    pub(crate) fn iter_with_types_map(
+        &self,
+    ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ {
+        self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain(
+            self.iter_parent().zip(
+                self.parent_generics()
+                    .into_iter()
+                    .flat_map(|it| std::iter::repeat(&it.params.types_map)),
+            ),
+        )
+    }
+
     /// Iterate over the params without parent params.
     pub(crate) fn iter_self(
         &self,
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 88334b492d5..3685ed56964 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -33,7 +33,7 @@ use chalk_ir::{
 };
 use either::Either;
 use hir_def::{
-    body::Body,
+    body::{Body, HygieneId},
     builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
     data::{ConstData, StaticData},
     hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -41,7 +41,7 @@ use hir_def::{
     layout::Integer,
     path::{ModPath, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
-    type_ref::{LifetimeRef, TypeRef},
+    type_ref::{LifetimeRef, TypeRefId, TypesMap},
     AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ImplId, ItemContainerId, Lookup,
     TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
 };
@@ -228,7 +228,7 @@ pub enum InferenceDiagnostic {
         id: ExprOrPatId,
     },
     UnresolvedIdent {
-        expr: ExprId,
+        id: ExprOrPatId,
     },
     // FIXME: This should be emitted in body lowering
     BreakOutsideOfLoop {
@@ -482,12 +482,27 @@ impl InferenceResult {
     pub fn variant_resolution_for_pat(&self, id: PatId) -> Option<VariantId> {
         self.variant_resolutions.get(&id.into()).copied()
     }
+    pub fn variant_resolution_for_expr_or_pat(&self, id: ExprOrPatId) -> Option<VariantId> {
+        match id {
+            ExprOrPatId::ExprId(id) => self.variant_resolution_for_expr(id),
+            ExprOrPatId::PatId(id) => self.variant_resolution_for_pat(id),
+        }
+    }
     pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<(AssocItemId, Substitution)> {
         self.assoc_resolutions.get(&id.into()).cloned()
     }
     pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<(AssocItemId, Substitution)> {
         self.assoc_resolutions.get(&id.into()).cloned()
     }
+    pub fn assoc_resolutions_for_expr_or_pat(
+        &self,
+        id: ExprOrPatId,
+    ) -> Option<(AssocItemId, Substitution)> {
+        match id {
+            ExprOrPatId::ExprId(id) => self.assoc_resolutions_for_expr(id),
+            ExprOrPatId::PatId(id) => self.assoc_resolutions_for_pat(id),
+        }
+    }
     pub fn type_mismatch_for_expr(&self, expr: ExprId) -> Option<&TypeMismatch> {
         self.type_mismatches.get(&expr.into())
     }
@@ -506,6 +521,12 @@ impl InferenceResult {
     pub fn closure_info(&self, closure: &ClosureId) -> &(Vec<CapturedItem>, FnTrait) {
         self.closure_info.get(closure).unwrap()
     }
+    pub fn type_of_expr_or_pat(&self, id: ExprOrPatId) -> Option<&Ty> {
+        match id {
+            ExprOrPatId::ExprId(id) => self.type_of_expr.get(id),
+            ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
+        }
+    }
 }
 
 impl Index<ExprId> for InferenceResult {
@@ -524,6 +545,14 @@ impl Index<PatId> for InferenceResult {
     }
 }
 
+impl Index<ExprOrPatId> for InferenceResult {
+    type Output = Ty;
+
+    fn index(&self, id: ExprOrPatId) -> &Ty {
+        self.type_of_expr_or_pat(id).unwrap_or(&self.standard_types.unknown)
+    }
+}
+
 impl Index<BindingId> for InferenceResult {
     type Output = Ty;
 
@@ -561,6 +590,9 @@ pub(crate) struct InferenceContext<'a> {
     diverges: Diverges,
     breakables: Vec<BreakableContext>,
 
+    /// Whether we are inside the pattern of a destructuring assignment.
+    inside_assignment: bool,
+
     deferred_cast_checks: Vec<CastCheck>,
 
     // fields related to closure capture
@@ -656,6 +688,7 @@ impl<'a> InferenceContext<'a> {
             current_closure: None,
             deferred_closures: FxHashMap::default(),
             closure_dependencies: FxHashMap::default(),
+            inside_assignment: false,
         }
     }
 
@@ -825,7 +858,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_const(&mut self, data: &ConstData) {
-        let return_ty = self.make_ty(&data.type_ref);
+        let return_ty = self.make_ty(data.type_ref, &data.types_map);
 
         // Constants might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -834,7 +867,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn collect_static(&mut self, data: &StaticData) {
-        let return_ty = self.make_ty(&data.type_ref);
+        let return_ty = self.make_ty(data.type_ref, &data.types_map);
 
         // Statics might be defining usage sites of TAITs.
         self.make_tait_coercion_table(iter::once(&return_ty));
@@ -844,11 +877,11 @@ impl<'a> InferenceContext<'a> {
 
     fn collect_fn(&mut self, func: FunctionId) {
         let data = self.db.function_data(func);
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Param);
-        let mut param_tys =
-            data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>();
+        let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| {
+            ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                .impl_trait_mode(ImplTraitLoweringMode::Param);
+            data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>()
+        });
         // Check if function contains a va_list, if it does then we append it to the parameter types
         // that are collected from the function data
         if data.is_varargs() {
@@ -883,12 +916,13 @@ impl<'a> InferenceContext<'a> {
                 tait_candidates.insert(ty);
             }
         }
-        let return_ty = &*data.ret_type;
+        let return_ty = data.ret_type;
 
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into())
-            .with_type_param_mode(ParamLoweringMode::Placeholder)
-            .with_impl_trait_mode(ImplTraitLoweringMode::Opaque);
-        let return_ty = ctx.lower_ty(return_ty);
+        let return_ty = self.with_ty_lowering(&data.types_map, |ctx| {
+            ctx.type_param_mode(ParamLoweringMode::Placeholder)
+                .impl_trait_mode(ImplTraitLoweringMode::Opaque)
+                .lower_ty(return_ty)
+        });
         let return_ty = self.insert_type_vars(return_ty);
 
         let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) {
@@ -1022,7 +1056,7 @@ impl<'a> InferenceContext<'a> {
             non_assocs: FxHashMap<OpaqueTyId, Ty>,
         }
 
-        impl<'a, 'b> TypeVisitor<Interner> for TypeAliasImplTraitCollector<'a, 'b> {
+        impl TypeVisitor<Interner> for TypeAliasImplTraitCollector<'_, '_> {
             type BreakTy = ();
 
             fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
@@ -1192,20 +1226,43 @@ impl<'a> InferenceContext<'a> {
         self.result.diagnostics.push(diagnostic);
     }
 
-    fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let ty = ctx.lower_ty(type_ref);
+    fn with_ty_lowering<R>(
+        &self,
+        types_map: &TypesMap,
+        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+    ) -> R {
+        let mut ctx = crate::lower::TyLoweringContext::new(
+            self.db,
+            &self.resolver,
+            types_map,
+            self.owner.into(),
+        );
+        f(&mut ctx)
+    }
+
+    fn with_body_ty_lowering<R>(
+        &self,
+        f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R,
+    ) -> R {
+        self.with_ty_lowering(&self.body.types, f)
+    }
+
+    fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty {
+        let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref));
         let ty = self.insert_type_vars(ty);
         self.normalize_associated_types_in(ty)
     }
 
+    fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty {
+        self.make_ty(type_ref, &self.body.types)
+    }
+
     fn err_ty(&self) -> Ty {
         self.result.standard_types.unknown.clone()
     }
 
     fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let lt = ctx.lower_lifetime(lifetime_ref);
+        let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref));
         self.insert_type_vars(lt)
     }
 
@@ -1363,9 +1420,14 @@ impl<'a> InferenceContext<'a> {
             Some(path) => path,
             None => return (self.err_ty(), None),
         };
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+        let ctx = crate::lower::TyLoweringContext::new(
+            self.db,
+            &self.resolver,
+            &self.body.types,
+            self.owner.into(),
+        );
         let (resolution, unresolved) = if value_ns {
-            match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path) {
+            match self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, HygieneId::ROOT) {
                 Some(ResolveValueResult::ValueNs(value, _)) => match value {
                     ValueNs::EnumVariantId(var) => {
                         let substs = ctx.substs_from_path(path, var.into(), true);
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 e9825cf0998..5a251683b96 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
@@ -11,11 +11,12 @@ use either::Either;
 use hir_def::{
     data::adt::VariantData,
     hir::{
-        Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement,
-        UnaryOp,
+        Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
+        Statement, UnaryOp,
     },
     lang_item::LangItem,
-    resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
+    path::Path,
+    resolver::ValueNs,
     DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
 };
 use hir_expand::name::Name;
@@ -282,11 +283,11 @@ impl CapturedItem {
                 ProjectionElem::Deref => {}
                 ProjectionElem::Field(Either::Left(f)) => {
                     match &*f.parent.variant_data(db.upcast()) {
-                        VariantData::Record(fields) => {
+                        VariantData::Record { fields, .. } => {
                             result.push('_');
                             result.push_str(fields[f.local_id].name.as_str())
                         }
-                        VariantData::Tuple(fields) => {
+                        VariantData::Tuple { fields, .. } => {
                             let index = fields.iter().position(|it| it.0 == f.local_id);
                             if let Some(index) = index {
                                 format_to!(result, "_{index}");
@@ -324,12 +325,12 @@ impl CapturedItem {
                 ProjectionElem::Field(Either::Left(f)) => {
                     let variant_data = f.parent.variant_data(db.upcast());
                     match &*variant_data {
-                        VariantData::Record(fields) => format_to!(
+                        VariantData::Record { fields, .. } => format_to!(
                             result,
                             ".{}",
                             fields[f.local_id].name.display(db.upcast(), edition)
                         ),
-                        VariantData::Tuple(fields) => format_to!(
+                        VariantData::Tuple { fields, .. } => format_to!(
                             result,
                             ".{}",
                             fields.iter().position(|it| it.0 == f.local_id).unwrap_or_default()
@@ -382,8 +383,10 @@ impl CapturedItem {
                     }
                     let variant_data = f.parent.variant_data(db.upcast());
                     let field = match &*variant_data {
-                        VariantData::Record(fields) => fields[f.local_id].name.as_str().to_owned(),
-                        VariantData::Tuple(fields) => fields
+                        VariantData::Record { fields, .. } => {
+                            fields[f.local_id].name.as_str().to_owned()
+                        }
+                        VariantData::Tuple { fields, .. } => fields
                             .iter()
                             .position(|it| it.0 == f.local_id)
                             .unwrap_or_default()
@@ -508,18 +511,39 @@ impl InferenceContext<'_> {
         apply_adjusts_to_place(&mut self.current_capture_span_stack, r, adjustments)
     }
 
+    /// Pushes the span into `current_capture_span_stack`, *without clearing it first*.
+    fn path_place(&mut self, path: &Path, id: ExprOrPatId) -> Option<HirPlace> {
+        if path.type_anchor().is_some() {
+            return None;
+        }
+        let hygiene = self.body.expr_or_pat_path_hygiene(id);
+        let result = self
+            .resolver
+            .resolve_path_in_value_ns_fully(self.db.upcast(), path, hygiene)
+            .and_then(|result| match result {
+                ValueNs::LocalBinding(binding) => {
+                    let mir_span = match id {
+                        ExprOrPatId::ExprId(id) => MirSpan::ExprId(id),
+                        ExprOrPatId::PatId(id) => MirSpan::PatId(id),
+                    };
+                    self.current_capture_span_stack.push(mir_span);
+                    Some(HirPlace { local: binding, projections: Vec::new() })
+                }
+                _ => None,
+            });
+        result
+    }
+
     /// Changes `current_capture_span_stack` to contain the stack of spans for this expr.
     fn place_of_expr_without_adjust(&mut self, tgt_expr: ExprId) -> Option<HirPlace> {
         self.current_capture_span_stack.clear();
         match &self.body[tgt_expr] {
             Expr::Path(p) => {
-                let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr);
-                if let Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(b), _)) =
-                    resolver.resolve_path_in_value_ns(self.db.upcast(), p)
-                {
-                    self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
-                    return Some(HirPlace { local: b, projections: vec![] });
-                }
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+                let result = self.path_place(p, tgt_expr.into());
+                self.resolver.reset_to_guard(resolver_guard);
+                return result;
             }
             Expr::Field { expr, name: _ } => {
                 let mut place = self.place_of_expr(*expr)?;
@@ -590,6 +614,16 @@ impl InferenceContext<'_> {
         }
     }
 
+    fn mutate_path_pat(&mut self, path: &Path, id: PatId) {
+        if let Some(place) = self.path_place(path, id.into()) {
+            self.add_capture(
+                place,
+                CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::Default }),
+            );
+            self.current_capture_span_stack.pop(); // Remove the pattern span.
+        }
+    }
+
     fn mutate_expr(&mut self, expr: ExprId, place: Option<HirPlace>) {
         if let Some(place) = place {
             self.add_capture(
@@ -715,14 +749,14 @@ impl InferenceContext<'_> {
                         Statement::Expr { expr, has_semi: _ } => {
                             self.consume_expr(*expr);
                         }
-                        Statement::Item => (),
+                        Statement::Item(_) => (),
                     }
                 }
                 if let Some(tail) = tail {
                     self.consume_expr(*tail);
                 }
             }
-            Expr::Call { callee, args, is_assignee_expr: _ } => {
+            Expr::Call { callee, args } => {
                 self.consume_expr(*callee);
                 self.consume_exprs(args.iter().copied());
             }
@@ -838,7 +872,7 @@ impl InferenceContext<'_> {
                     self.consume_expr(expr);
                 }
             }
-            Expr::Index { base, index, is_assignee_expr: _ } => {
+            Expr::Index { base, index } => {
                 self.select_from_expr(*base);
                 self.consume_expr(*index);
             }
@@ -862,10 +896,30 @@ impl InferenceContext<'_> {
                 }));
                 self.current_captures = cc;
             }
-            Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ })
-            | Expr::Tuple { exprs, is_assignee_expr: _ } => {
+            Expr::Array(Array::ElementList { elements: exprs }) | Expr::Tuple { exprs } => {
                 self.consume_exprs(exprs.iter().copied())
             }
+            &Expr::Assignment { target, value } => {
+                self.walk_expr(value);
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+                match self.place_of_expr(value) {
+                    Some(rhs_place) => {
+                        self.inside_assignment = true;
+                        self.consume_with_pat(rhs_place, target);
+                        self.inside_assignment = false;
+                    }
+                    None => self.body.walk_pats(target, &mut |pat| match &self.body[pat] {
+                        Pat::Path(path) => self.mutate_path_pat(path, pat),
+                        &Pat::Expr(expr) => {
+                            let place = self.place_of_expr(expr);
+                            self.mutate_expr(expr, place);
+                        }
+                        _ => {}
+                    }),
+                }
+                self.resolver.reset_to_guard(resolver_guard);
+            }
 
             Expr::Missing
             | Expr::Continue { .. }
@@ -903,6 +957,7 @@ impl InferenceContext<'_> {
             | Pat::Missing
             | Pat::Wild
             | Pat::Tuple { .. }
+            | Pat::Expr(_)
             | Pat::Or(_) => (),
             Pat::TupleStruct { .. } | Pat::Record { .. } => {
                 if let Some(variant) = self.result.variant_resolution_for_pat(p) {
@@ -1122,11 +1177,15 @@ impl InferenceContext<'_> {
                         }
                     }
                 }
-                Pat::Range { .. }
-                | Pat::Slice { .. }
-                | Pat::ConstBlock(_)
-                | Pat::Path(_)
-                | Pat::Lit(_) => self.consume_place(place),
+                Pat::Range { .. } | Pat::Slice { .. } | Pat::ConstBlock(_) | Pat::Lit(_) => {
+                    self.consume_place(place)
+                }
+                Pat::Path(path) => {
+                    if self.inside_assignment {
+                        self.mutate_path_pat(path, tgt_pat);
+                    }
+                    self.consume_place(place);
+                }
                 &Pat::Bind { id, subpat: _ } => {
                     let mode = self.result.binding_modes[tgt_pat];
                     let capture_kind = match mode {
@@ -1180,6 +1239,15 @@ impl InferenceContext<'_> {
                     self.current_capture_span_stack.pop();
                 }
                 Pat::Box { .. } => (), // not supported
+                &Pat::Expr(expr) => {
+                    self.consume_place(place);
+                    let pat_capture_span_stack = mem::take(&mut self.current_capture_span_stack);
+                    let old_inside_assignment = mem::replace(&mut self.inside_assignment, false);
+                    let lhs_place = self.place_of_expr(expr);
+                    self.mutate_expr(expr, lhs_place);
+                    self.inside_assignment = old_inside_assignment;
+                    self.current_capture_span_stack = pat_capture_span_stack;
+                }
             }
         }
         self.current_capture_span_stack
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 657e4d77966..32b4ea2f28b 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
@@ -9,8 +9,8 @@ use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKin
 use either::Either;
 use hir_def::{
     hir::{
-        ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, LabelId,
-        Literal, Pat, PatId, Statement, UnaryOp,
+        ArithOp, Array, AsmOperand, AsmOptions, BinaryOp, ClosureKind, Expr, ExprId, ExprOrPatId,
+        LabelId, Literal, Pat, PatId, Statement, UnaryOp,
     },
     lang_item::{LangItem, LangItemTarget},
     path::{GenericArg, GenericArgs, Path},
@@ -188,6 +188,9 @@ impl InferenceContext<'_> {
             | Pat::ConstBlock(_)
             | Pat::Record { .. }
             | Pat::Missing => true,
+            Pat::Expr(_) => unreachable!(
+                "we don't call pat_guaranteed_to_constitute_read_for_never() with assignments"
+            ),
         }
     }
 
@@ -195,10 +198,14 @@ impl InferenceContext<'_> {
         match &self.body[expr] {
             // Lang item paths cannot currently be local variables or statics.
             Expr::Path(Path::LangItem(_, _)) => false,
-            Expr::Path(Path::Normal { type_anchor: Some(_), .. }) => false,
+            Expr::Path(Path::Normal(path)) => path.type_anchor().is_none(),
             Expr::Path(path) => self
                 .resolver
-                .resolve_path_in_value_ns_fully(self.db.upcast(), path)
+                .resolve_path_in_value_ns_fully(
+                    self.db.upcast(),
+                    path,
+                    self.body.expr_path_hygiene(expr),
+                )
                 .map_or(true, |res| matches!(res, ValueNs::LocalBinding(_) | ValueNs::StaticId(_))),
             Expr::Underscore => true,
             Expr::UnaryOp { op: UnaryOp::Deref, .. } => true,
@@ -223,6 +230,7 @@ impl InferenceContext<'_> {
             | Expr::Const(..)
             | Expr::UnaryOp { .. }
             | Expr::BinaryOp { .. }
+            | Expr::Assignment { .. }
             | Expr::Yield { .. }
             | Expr::Cast { .. }
             | Expr::Async { .. }
@@ -374,7 +382,7 @@ impl InferenceContext<'_> {
                 // collect explicitly written argument types
                 for arg_type in arg_types.iter() {
                     let arg_ty = match arg_type {
-                        Some(type_ref) => self.make_ty(type_ref),
+                        Some(type_ref) => self.make_body_ty(*type_ref),
                         None => self.table.new_type_var(),
                     };
                     sig_tys.push(arg_ty);
@@ -382,7 +390,7 @@ impl InferenceContext<'_> {
 
                 // add return type
                 let ret_ty = match ret_type {
-                    Some(type_ref) => self.make_ty(type_ref),
+                    Some(type_ref) => self.make_body_ty(*type_ref),
                     None => self.table.new_type_var(),
                 };
                 if let ClosureKind::Async = closure_kind {
@@ -609,23 +617,7 @@ impl InferenceContext<'_> {
                     coerce.complete(self)
                 }
             }
-            Expr::Path(p) => {
-                let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
-                let ty = match self.infer_path(p, tgt_expr.into()) {
-                    Some(ty) => ty,
-                    None => {
-                        if matches!(p, Path::Normal { mod_path, .. } if mod_path.is_ident() || mod_path.is_self())
-                        {
-                            self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent {
-                                expr: tgt_expr,
-                            });
-                        }
-                        self.err_ty()
-                    }
-                };
-                self.resolver.reset_to_guard(g);
-                ty
-            }
+            Expr::Path(p) => self.infer_expr_path(p, tgt_expr.into(), tgt_expr),
             &Expr::Continue { label } => {
                 if find_continuable(&mut self.breakables, label).is_none() {
                     self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
@@ -794,7 +786,7 @@ impl InferenceContext<'_> {
                 self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
             }
             Expr::Cast { expr, type_ref } => {
-                let cast_ty = self.make_ty(type_ref);
+                let cast_ty = self.make_body_ty(*type_ref);
                 let expr_ty = self.infer_expr(
                     *expr,
                     &Expectation::Castable(cast_ty.clone()),
@@ -892,36 +884,6 @@ impl InferenceContext<'_> {
                 }
             }
             Expr::BinaryOp { lhs, rhs, op } => match op {
-                Some(BinaryOp::Assignment { op: None }) => {
-                    let lhs = *lhs;
-                    let is_ordinary = match &self.body[lhs] {
-                        Expr::Array(_)
-                        | Expr::RecordLit { .. }
-                        | Expr::Tuple { .. }
-                        | Expr::Underscore => false,
-                        Expr::Call { callee, .. } => !matches!(&self.body[*callee], Expr::Path(_)),
-                        _ => true,
-                    };
-
-                    // In ordinary (non-destructuring) assignments, the type of
-                    // `lhs` must be inferred first so that the ADT fields
-                    // instantiations in RHS can be coerced to it. Note that this
-                    // cannot happen in destructuring assignments because of how
-                    // they are desugared.
-                    if is_ordinary {
-                        // LHS of assignment doesn't constitute reads.
-                        let lhs_ty = self.infer_expr(lhs, &Expectation::none(), ExprIsRead::No);
-                        self.infer_expr_coerce(
-                            *rhs,
-                            &Expectation::has_type(lhs_ty),
-                            ExprIsRead::No,
-                        );
-                    } else {
-                        let rhs_ty = self.infer_expr(*rhs, &Expectation::none(), ExprIsRead::Yes);
-                        self.infer_assignee_expr(lhs, &rhs_ty);
-                    }
-                    self.result.standard_types.unit.clone()
-                }
                 Some(BinaryOp::LogicOp(_)) => {
                     let bool_ty = self.result.standard_types.bool_.clone();
                     self.infer_expr_coerce(
@@ -942,6 +904,35 @@ impl InferenceContext<'_> {
                 Some(op) => self.infer_overloadable_binop(*lhs, *op, *rhs, tgt_expr),
                 _ => self.err_ty(),
             },
+            &Expr::Assignment { target, value } => {
+                // In ordinary (non-destructuring) assignments, the type of
+                // `lhs` must be inferred first so that the ADT fields
+                // instantiations in RHS can be coerced to it. Note that this
+                // cannot happen in destructuring assignments because of how
+                // they are desugared.
+                let lhs_ty = match &self.body[target] {
+                    // LHS of assignment doesn't constitute reads.
+                    &Pat::Expr(expr) => {
+                        Some(self.infer_expr(expr, &Expectation::none(), ExprIsRead::No))
+                    }
+                    Pat::Path(path) => Some(self.infer_expr_path(path, target.into(), tgt_expr)),
+                    _ => None,
+                };
+
+                if let Some(lhs_ty) = lhs_ty {
+                    self.write_pat_ty(target, lhs_ty.clone());
+                    self.infer_expr_coerce(value, &Expectation::has_type(lhs_ty), ExprIsRead::No);
+                } else {
+                    let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes);
+                    let resolver_guard =
+                        self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
+                    self.inside_assignment = true;
+                    self.infer_top_pat(target, &rhs_ty);
+                    self.inside_assignment = false;
+                    self.resolver.reset_to_guard(resolver_guard);
+                }
+                self.result.standard_types.unit.clone()
+            }
             Expr::Range { lhs, rhs, range_type } => {
                 let lhs_ty =
                     lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
@@ -981,7 +972,7 @@ impl InferenceContext<'_> {
                     (RangeOp::Inclusive, _, None) => self.err_ty(),
                 }
             }
-            Expr::Index { base, index, is_assignee_expr } => {
+            Expr::Index { base, index } => {
                 let base_ty = self.infer_expr_inner(*base, &Expectation::none(), ExprIsRead::Yes);
                 let index_ty = self.infer_expr(*index, &Expectation::none(), ExprIsRead::Yes);
 
@@ -1017,23 +1008,11 @@ impl InferenceContext<'_> {
                         self.write_method_resolution(tgt_expr, func, subst);
                     }
                     let assoc = self.resolve_ops_index_output();
-                    let res = self.resolve_associated_type_with_params(
+                    self.resolve_associated_type_with_params(
                         self_ty.clone(),
                         assoc,
                         &[index_ty.clone().cast(Interner)],
-                    );
-
-                    if *is_assignee_expr {
-                        if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) {
-                            let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
-                                .push(self_ty)
-                                .fill(|_| index_ty.clone().cast(Interner))
-                                .build();
-                            self.push_obligation(trait_ref.cast(Interner));
-                        }
-                    }
-
-                    res
+                    )
                 } else {
                     self.err_ty()
                 }
@@ -1151,9 +1130,7 @@ impl InferenceContext<'_> {
                 },
             },
             Expr::Underscore => {
-                // Underscore expressions may only appear in assignee expressions,
-                // which are handled by `infer_assignee_expr()`.
-                // Any other underscore expression is an error, we render a specialized diagnostic
+                // Underscore expression is an error, we render a specialized diagnostic
                 // to let the user know what type is expected though.
                 let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty());
                 self.push_diagnostic(InferenceDiagnostic::TypedHole {
@@ -1232,6 +1209,22 @@ impl InferenceContext<'_> {
         ty
     }
 
+    fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty {
+        let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, scope_id);
+        let ty = match self.infer_path(path, id) {
+            Some(ty) => ty,
+            None => {
+                if path.mod_path().is_some_and(|mod_path| mod_path.is_ident() || mod_path.is_self())
+                {
+                    self.push_diagnostic(InferenceDiagnostic::UnresolvedIdent { id });
+                }
+                self.err_ty()
+            }
+        };
+        self.resolver.reset_to_guard(g);
+        ty
+    }
+
     fn infer_async_block(
         &mut self,
         tgt_expr: ExprId,
@@ -1482,107 +1475,6 @@ impl InferenceContext<'_> {
         }
     }
 
-    pub(super) fn infer_assignee_expr(&mut self, lhs: ExprId, rhs_ty: &Ty) -> Ty {
-        let is_rest_expr = |expr| {
-            matches!(
-                &self.body[expr],
-                Expr::Range { lhs: None, rhs: None, range_type: RangeOp::Exclusive },
-            )
-        };
-
-        let rhs_ty = self.resolve_ty_shallow(rhs_ty);
-
-        let ty = match &self.body[lhs] {
-            Expr::Tuple { exprs, .. } => {
-                // We don't consider multiple ellipses. This is analogous to
-                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
-                let ellipsis = exprs.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
-                let exprs: Vec<_> = exprs.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
-
-                self.infer_tuple_pat_like(&rhs_ty, (), ellipsis, &exprs)
-            }
-            Expr::Call { callee, args, .. } => {
-                // Tuple structs
-                let path = match &self.body[*callee] {
-                    Expr::Path(path) => Some(path),
-                    _ => None,
-                };
-
-                // We don't consider multiple ellipses. This is analogous to
-                // `hir_def::body::lower::ExprCollector::collect_tuple_pat()`.
-                let ellipsis = args.iter().position(|e| is_rest_expr(*e)).map(|it| it as u32);
-                let args: Vec<_> = args.iter().filter(|e| !is_rest_expr(**e)).copied().collect();
-
-                self.infer_tuple_struct_pat_like(path, &rhs_ty, (), lhs, ellipsis, &args)
-            }
-            Expr::Array(Array::ElementList { elements, .. }) => {
-                let elem_ty = match rhs_ty.kind(Interner) {
-                    TyKind::Array(st, _) => st.clone(),
-                    _ => self.err_ty(),
-                };
-
-                // There's no need to handle `..` as it cannot be bound.
-                let sub_exprs = elements.iter().filter(|e| !is_rest_expr(**e));
-
-                for e in sub_exprs {
-                    self.infer_assignee_expr(*e, &elem_ty);
-                }
-
-                match rhs_ty.kind(Interner) {
-                    TyKind::Array(_, _) => rhs_ty.clone(),
-                    // Even when `rhs_ty` is not an array type, this assignee
-                    // expression is inferred to be an array (of unknown element
-                    // type and length). This should not be just an error type,
-                    // because we are to compute the unifiability of this type and
-                    // `rhs_ty` in the end of this function to issue type mismatches.
-                    _ => TyKind::Array(
-                        self.err_ty(),
-                        crate::consteval::usize_const(self.db, None, self.resolver.krate()),
-                    )
-                    .intern(Interner),
-                }
-            }
-            Expr::RecordLit { path, fields, .. } => {
-                let subs = fields.iter().map(|f| (f.name.clone(), f.expr));
-
-                self.infer_record_pat_like(path.as_deref(), &rhs_ty, (), lhs, subs)
-            }
-            Expr::Underscore => rhs_ty.clone(),
-            _ => {
-                // `lhs` is a place expression, a unit struct, or an enum variant.
-                // LHS of assignment doesn't constitute reads.
-                let lhs_ty = self.infer_expr_inner(lhs, &Expectation::none(), ExprIsRead::No);
-
-                // This is the only branch where this function may coerce any type.
-                // We are returning early to avoid the unifiability check below.
-                let lhs_ty = self.insert_type_vars_shallow(lhs_ty);
-                let ty = match self.coerce(None, &rhs_ty, &lhs_ty, CoerceNever::Yes) {
-                    Ok(ty) => ty,
-                    Err(_) => {
-                        self.result.type_mismatches.insert(
-                            lhs.into(),
-                            TypeMismatch { expected: rhs_ty.clone(), actual: lhs_ty.clone() },
-                        );
-                        // `rhs_ty` is returned so no further type mismatches are
-                        // reported because of this mismatch.
-                        rhs_ty
-                    }
-                };
-                self.write_expr_ty(lhs, ty.clone());
-                return ty;
-            }
-        };
-
-        let ty = self.insert_type_vars_shallow(ty);
-        if !self.unify(&ty, &rhs_ty) {
-            self.result
-                .type_mismatches
-                .insert(lhs.into(), TypeMismatch { expected: rhs_ty.clone(), actual: ty.clone() });
-        }
-        self.write_expr_ty(lhs, ty.clone());
-        ty
-    }
-
     fn infer_overloadable_binop(
         &mut self,
         lhs: ExprId,
@@ -1706,7 +1598,7 @@ impl InferenceContext<'_> {
                         Statement::Let { pat, type_ref, initializer, else_branch } => {
                             let decl_ty = type_ref
                                 .as_ref()
-                                .map(|tr| this.make_ty(tr))
+                                .map(|&tr| this.make_body_ty(tr))
                                 .unwrap_or_else(|| this.table.new_type_var());
 
                             let ty = if let Some(expr) = initializer {
@@ -1764,7 +1656,7 @@ impl InferenceContext<'_> {
                                 );
                             }
                         }
-                        Statement::Item => (),
+                        Statement::Item(_) => (),
                     }
                 }
 
@@ -2249,7 +2141,8 @@ impl InferenceContext<'_> {
                         kind_id,
                         args.next().unwrap(), // `peek()` is `Some(_)`, so guaranteed no panic
                         self,
-                        |this, type_ref| this.make_ty(type_ref),
+                        &self.body.types,
+                        |this, type_ref| this.make_body_ty(type_ref),
                         |this, c, ty| {
                             const_or_path_to_chalk(
                                 this.db,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
index 6a0daee6ea9..d74a383f44e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs
@@ -4,7 +4,8 @@
 use chalk_ir::{cast::Cast, Mutability};
 use hir_def::{
     hir::{
-        Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp,
+        Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, Statement,
+        UnaryOp,
     },
     lang_item::LangItem,
 };
@@ -88,7 +89,7 @@ impl InferenceContext<'_> {
                         Statement::Expr { expr, has_semi: _ } => {
                             self.infer_mut_expr(*expr, Mutability::Not);
                         }
-                        Statement::Item => (),
+                        Statement::Item(_) => (),
                     }
                 }
                 if let Some(tail) = tail {
@@ -96,7 +97,7 @@ impl InferenceContext<'_> {
                 }
             }
             Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
-            | Expr::Call { callee: it, args, is_assignee_expr: _ } => {
+            | Expr::Call { callee: it, args } => {
                 self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
             }
             Expr::Match { expr, arms } => {
@@ -120,10 +121,10 @@ impl InferenceContext<'_> {
             Expr::Become { expr } => {
                 self.infer_mut_expr(*expr, Mutability::Not);
             }
-            Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
+            Expr::RecordLit { path: _, fields, spread } => {
                 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
             }
-            &Expr::Index { base, index, is_assignee_expr } => {
+            &Expr::Index { base, index } => {
                 if mutability == Mutability::Mut {
                     if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
                         if let Some(index_trait) = self
@@ -148,11 +149,8 @@ impl InferenceContext<'_> {
                                     target,
                                 }) = base_adjustments
                                 {
-                                    // For assignee exprs `IndexMut` obligations are already applied
-                                    if !is_assignee_expr {
-                                        if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
-                                            base_ty = Some(ty.clone());
-                                        }
+                                    if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
+                                        base_ty = Some(ty.clone());
                                     }
                                     *mutability = Mutability::Mut;
                                 }
@@ -233,6 +231,14 @@ impl InferenceContext<'_> {
                 self.infer_mut_expr(*lhs, Mutability::Mut);
                 self.infer_mut_expr(*rhs, Mutability::Not);
             }
+            &Expr::Assignment { target, value } => {
+                self.body.walk_pats(target, &mut |pat| match self.body[pat] {
+                    Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut),
+                    Pat::ConstBlock(block) => self.infer_mut_expr(block, Mutability::Not),
+                    _ => {}
+                });
+                self.infer_mut_expr(value, Mutability::Not);
+            }
             Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs })
             | Expr::BinaryOp { lhs, rhs, op: _ }
             | Expr::Range { lhs: Some(lhs), rhs: Some(rhs), range_type: _ } => {
@@ -242,8 +248,7 @@ impl InferenceContext<'_> {
             Expr::Closure { body, .. } => {
                 self.infer_mut_expr(*body, Mutability::Not);
             }
-            Expr::Tuple { exprs, is_assignee_expr: _ }
-            | Expr::Array(Array::ElementList { elements: exprs, is_assignee_expr: _ }) => {
+            Expr::Tuple { exprs } | Expr::Array(Array::ElementList { elements: exprs }) => {
                 self.infer_mut_not_expr_iter(exprs.iter().copied());
             }
             // These don't need any action, as they don't have sub expressions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index fee6755408e..50e761196ec 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -4,7 +4,7 @@ use std::iter::repeat_with;
 
 use hir_def::{
     body::Body,
-    hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
+    hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
     path::Path,
 };
 use hir_expand::name::Name;
@@ -12,63 +12,28 @@ use stdx::TupleExt;
 
 use crate::{
     consteval::{try_const_usize, usize_const},
-    infer::{expr::ExprIsRead, BindingMode, Expectation, InferenceContext, TypeMismatch},
+    infer::{
+        coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext,
+        TypeMismatch,
+    },
     lower::lower_to_chalk_mutability,
     primitive::UintTy,
     static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
     TyBuilder, TyExt, TyKind,
 };
 
-/// Used to generalize patterns and assignee expressions.
-pub(super) trait PatLike: Into<ExprOrPatId> + Copy {
-    type BindingMode: Copy;
-
-    fn infer(
-        this: &mut InferenceContext<'_>,
-        id: Self,
-        expected_ty: &Ty,
-        default_bm: Self::BindingMode,
-    ) -> Ty;
-}
-
-impl PatLike for ExprId {
-    type BindingMode = ();
-
-    fn infer(
-        this: &mut InferenceContext<'_>,
-        id: Self,
-        expected_ty: &Ty,
-        (): Self::BindingMode,
-    ) -> Ty {
-        this.infer_assignee_expr(id, expected_ty)
-    }
-}
-
-impl PatLike for PatId {
-    type BindingMode = BindingMode;
-
-    fn infer(
-        this: &mut InferenceContext<'_>,
-        id: Self,
-        expected_ty: &Ty,
-        default_bm: Self::BindingMode,
-    ) -> Ty {
-        this.infer_pat(id, expected_ty, default_bm)
-    }
-}
-
 impl InferenceContext<'_> {
     /// Infers type for tuple struct pattern or its corresponding assignee expression.
     ///
     /// Ellipses found in the original pattern or expression must be filtered out.
-    pub(super) fn infer_tuple_struct_pat_like<T: PatLike>(
+    pub(super) fn infer_tuple_struct_pat_like(
         &mut self,
         path: Option<&Path>,
         expected: &Ty,
-        default_bm: T::BindingMode,
-        id: T,
+        default_bm: BindingMode,
+        id: PatId,
         ellipsis: Option<u32>,
-        subs: &[T],
+        subs: &[PatId],
     ) -> Ty {
         let (ty, def) = self.resolve_variant(path, true);
         let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@@ -127,13 +92,13 @@ impl InferenceContext<'_> {
                         }
                     };
 
-                    T::infer(self, subpat, &expected_ty, default_bm);
+                    self.infer_pat(subpat, &expected_ty, default_bm);
                 }
             }
             None => {
                 let err_ty = self.err_ty();
                 for &inner in subs {
-                    T::infer(self, inner, &err_ty, default_bm);
+                    self.infer_pat(inner, &err_ty, default_bm);
                 }
             }
         }
@@ -142,13 +107,13 @@ impl InferenceContext<'_> {
     }
 
     /// Infers type for record pattern or its corresponding assignee expression.
-    pub(super) fn infer_record_pat_like<T: PatLike>(
+    pub(super) fn infer_record_pat_like(
         &mut self,
         path: Option<&Path>,
         expected: &Ty,
-        default_bm: T::BindingMode,
-        id: T,
-        subs: impl ExactSizeIterator<Item = (Name, T)>,
+        default_bm: BindingMode,
+        id: PatId,
+        subs: impl ExactSizeIterator<Item = (Name, PatId)>,
     ) -> Ty {
         let (ty, def) = self.resolve_variant(path, false);
         if let Some(variant) = def {
@@ -197,13 +162,13 @@ impl InferenceContext<'_> {
                         }
                     };
 
-                    T::infer(self, inner, &expected_ty, default_bm);
+                    self.infer_pat(inner, &expected_ty, default_bm);
                 }
             }
             None => {
                 let err_ty = self.err_ty();
                 for (_, inner) in subs {
-                    T::infer(self, inner, &err_ty, default_bm);
+                    self.infer_pat(inner, &err_ty, default_bm);
                 }
             }
         }
@@ -214,12 +179,12 @@ impl InferenceContext<'_> {
     /// Infers type for tuple pattern or its corresponding assignee expression.
     ///
     /// Ellipses found in the original pattern or expression must be filtered out.
-    pub(super) fn infer_tuple_pat_like<T: PatLike>(
+    pub(super) fn infer_tuple_pat_like(
         &mut self,
         expected: &Ty,
-        default_bm: T::BindingMode,
+        default_bm: BindingMode,
         ellipsis: Option<u32>,
-        subs: &[T],
+        subs: &[PatId],
     ) -> Ty {
         let expected = self.resolve_ty_shallow(expected);
         let expectations = match expected.as_tuple() {
@@ -244,18 +209,20 @@ impl InferenceContext<'_> {
 
         // Process pre
         for (ty, pat) in inner_tys.iter_mut().zip(pre) {
-            *ty = T::infer(self, *pat, ty, default_bm);
+            *ty = self.infer_pat(*pat, ty, default_bm);
         }
 
         // Process post
         for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
-            *ty = T::infer(self, *pat, ty, default_bm);
+            *ty = self.infer_pat(*pat, ty, default_bm);
         }
 
         TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
             .intern(Interner)
     }
 
+    /// The resolver needs to be updated to the surrounding expression when inside assignment
+    /// (because there, `Pat::Path` can refer to a variable).
     pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
         self.infer_pat(pat, expected, BindingMode::default());
     }
@@ -263,7 +230,14 @@ impl InferenceContext<'_> {
     fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
         let mut expected = self.resolve_ty_shallow(expected);
 
-        if self.is_non_ref_pat(self.body, pat) {
+        if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
+            cov_mark::hit!(match_ergonomics_ref);
+            // When you encounter a `&pat` pattern, reset to Move.
+            // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
+            // Destructuring assignments also reset the binding mode and
+            // don't do match ergonomics.
+            default_bm = BindingMode::Move;
+        } else if self.is_non_ref_pat(self.body, pat) {
             let mut pat_adjustments = Vec::new();
             while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
                 pat_adjustments.push(expected.clone());
@@ -279,11 +253,6 @@ impl InferenceContext<'_> {
                 pat_adjustments.shrink_to_fit();
                 self.result.pat_adjustments.insert(pat, pat_adjustments);
             }
-        } else if let Pat::Ref { .. } = &self.body[pat] {
-            cov_mark::hit!(match_ergonomics_ref);
-            // When you encounter a `&pat` pattern, reset to Move.
-            // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
-            default_bm = BindingMode::Move;
         }
 
         // Lose mutability.
@@ -320,8 +289,34 @@ impl InferenceContext<'_> {
                 self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
             }
             Pat::Path(path) => {
-                // FIXME update resolver for the surrounding expression
-                self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty())
+                let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
+                let ty_inserted_vars = self.insert_type_vars_shallow(ty.clone());
+                match self.table.coerce(&expected, &ty_inserted_vars, CoerceNever::Yes) {
+                    Ok((adjustments, coerced_ty)) => {
+                        if !adjustments.is_empty() {
+                            self.result
+                                .pat_adjustments
+                                .entry(pat)
+                                .or_default()
+                                .extend(adjustments.into_iter().map(|adjust| adjust.target));
+                        }
+                        self.write_pat_ty(pat, coerced_ty);
+                        return self.pat_ty_after_adjustment(pat);
+                    }
+                    Err(_) => {
+                        self.result.type_mismatches.insert(
+                            pat.into(),
+                            TypeMismatch {
+                                expected: expected.clone(),
+                                actual: ty_inserted_vars.clone(),
+                            },
+                        );
+                        self.write_pat_ty(pat, ty);
+                        // We return `expected` to prevent cascading errors. I guess an alternative is to
+                        // not emit type mismatches for error types and emit an error type here.
+                        return expected;
+                    }
+                }
             }
             Pat::Bind { id, subpat } => {
                 return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected);
@@ -361,7 +356,40 @@ impl InferenceContext<'_> {
                 None => self.err_ty(),
             },
             Pat::ConstBlock(expr) => {
-                self.infer_expr(*expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes)
+                let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
+                let result = self.infer_expr(
+                    *expr,
+                    &Expectation::has_type(expected.clone()),
+                    ExprIsRead::Yes,
+                );
+                self.inside_assignment = old_inside_assign;
+                result
+            }
+            Pat::Expr(expr) => {
+                let old_inside_assign = std::mem::replace(&mut self.inside_assignment, false);
+                // LHS of assignment doesn't constitute reads.
+                let result = self.infer_expr_coerce(
+                    *expr,
+                    &Expectation::has_type(expected.clone()),
+                    ExprIsRead::No,
+                );
+                // We are returning early to avoid the unifiability check below.
+                let lhs_ty = self.insert_type_vars_shallow(result);
+                let ty = match self.coerce(None, &expected, &lhs_ty, CoerceNever::Yes) {
+                    Ok(ty) => ty,
+                    Err(_) => {
+                        self.result.type_mismatches.insert(
+                            pat.into(),
+                            TypeMismatch { expected: expected.clone(), actual: lhs_ty.clone() },
+                        );
+                        // `rhs_ty` is returned so no further type mismatches are
+                        // reported because of this mismatch.
+                        expected
+                    }
+                };
+                self.write_pat_ty(pat, ty.clone());
+                self.inside_assignment = old_inside_assign;
+                return ty;
             }
             Pat::Missing => self.err_ty(),
         };
@@ -517,9 +545,12 @@ impl InferenceContext<'_> {
                 body[*expr],
                 Expr::Literal(Literal::String(..) | Literal::CString(..) | Literal::ByteString(..))
             ),
-            Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => {
-                false
-            }
+            Pat::Wild
+            | Pat::Bind { .. }
+            | Pat::Ref { .. }
+            | Pat::Box { .. }
+            | Pat::Missing
+            | Pat::Expr(_) => false,
         }
     }
 }
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 e4841c7b15b..442daa9f9ee 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
@@ -94,8 +94,7 @@ impl InferenceContext<'_> {
             return Some(ValuePathResolution::NonGeneric(ty));
         };
 
-        let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
-        let substs = ctx.substs_from_path(path, value_def, true);
+        let substs = self.with_body_ty_lowering(|ctx| ctx.substs_from_path(path, value_def, true));
         let substs = substs.as_slice(Interner);
 
         if let ValueNs::EnumVariantId(_) = value {
@@ -152,8 +151,12 @@ impl InferenceContext<'_> {
             let last = path.segments().last()?;
 
             // Don't use `self.make_ty()` here as we need `orig_ns`.
-            let ctx =
-                crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
+            let ctx = crate::lower::TyLoweringContext::new(
+                self.db,
+                &self.resolver,
+                &self.body.types,
+                self.owner.into(),
+            );
             let (ty, orig_ns) = ctx.lower_ty_ext(type_ref);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
@@ -164,9 +167,10 @@ impl InferenceContext<'_> {
             let ty = self.table.normalize_associated_types_in(ty);
             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
         } else {
+            let hygiene = self.body.expr_or_pat_path_hygiene(id);
             // FIXME: report error, unresolved first path segment
             let value_or_partial =
-                self.resolver.resolve_path_in_value_ns(self.db.upcast(), path)?;
+                self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene)?;
 
             match value_or_partial {
                 ResolveValueResult::ValueNs(it, _) => (it, None),
@@ -218,7 +222,7 @@ impl InferenceContext<'_> {
 
         let _d;
         let (resolved_segment, remaining_segments) = match path {
-            Path::Normal { .. } => {
+            Path::Normal { .. } | Path::BarePath(_) => {
                 assert!(remaining_index < path.segments().len());
                 (
                     path.segments().get(remaining_index - 1).unwrap(),
@@ -242,17 +246,10 @@ impl InferenceContext<'_> {
             (TypeNs::TraitId(trait_), true) => {
                 let segment =
                     remaining_segments.last().expect("there should be at least one segment here");
-                let ctx = crate::lower::TyLoweringContext::new(
-                    self.db,
-                    &self.resolver,
-                    self.owner.into(),
-                );
-                let trait_ref = ctx.lower_trait_ref_from_resolved_path(
-                    trait_,
-                    resolved_segment,
-                    self.table.new_type_var(),
-                );
-
+                let self_ty = self.table.new_type_var();
+                let trait_ref = self.with_body_ty_lowering(|ctx| {
+                    ctx.lower_trait_ref_from_resolved_path(trait_, resolved_segment, self_ty)
+                });
                 self.resolve_trait_assoc_item(trait_ref, segment, id)
             }
             (def, _) => {
@@ -262,17 +259,14 @@ impl InferenceContext<'_> {
                 // as Iterator>::Item::default`)
                 let remaining_segments_for_ty =
                     remaining_segments.take(remaining_segments.len() - 1);
-                let ctx = crate::lower::TyLoweringContext::new(
-                    self.db,
-                    &self.resolver,
-                    self.owner.into(),
-                );
-                let (ty, _) = ctx.lower_partly_resolved_path(
-                    def,
-                    resolved_segment,
-                    remaining_segments_for_ty,
-                    true,
-                );
+                let (ty, _) = self.with_body_ty_lowering(|ctx| {
+                    ctx.lower_partly_resolved_path(
+                        def,
+                        resolved_segment,
+                        remaining_segments_for_ty,
+                        true,
+                    )
+                });
                 if ty.is_unknown() {
                     return None;
                 }
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 80831440720..9f4cc98993e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -6,7 +6,7 @@ use base_db::ra_salsa::Cycle;
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
-        Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutS,
+        Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutCalculatorError, LayoutData,
         Primitive, ReprOptions, Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
     },
     LocalFieldId, StructId,
@@ -66,7 +66,7 @@ impl rustc_index::Idx for RustcFieldIdx {
     }
 }
 
-pub type Layout = LayoutS<RustcFieldIdx, RustcEnumVariantIdx>;
+pub type Layout = LayoutData<RustcFieldIdx, RustcEnumVariantIdx>;
 pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
 pub type Variants = hir_def::layout::Variants<RustcFieldIdx, RustcEnumVariantIdx>;
 
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 c7ed68448bb..e3a92e52f61 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -34,6 +34,7 @@ use hir_def::{
     resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
     type_ref::{
         ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
+        TypeRefId, TypesMap, TypesSourceMap,
     },
     AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
     FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId,
@@ -41,7 +42,6 @@ use hir_def::{
     TypeOwnerId, UnionId, VariantId,
 };
 use hir_expand::{name::Name, ExpandResult};
-use intern::Interned;
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashSet;
 use rustc_pattern_analysis::Captures;
@@ -122,6 +122,11 @@ pub struct TyLoweringContext<'a> {
     pub db: &'a dyn HirDatabase,
     resolver: &'a Resolver,
     generics: OnceCell<Option<Generics>>,
+    types_map: &'a TypesMap,
+    /// If this is set, that means we're in a context of a freshly expanded macro, and that means
+    /// we should not use `TypeRefId` in diagnostics because the caller won't have the `TypesMap`,
+    /// instead we need to put `TypeSource` from the source map.
+    types_source_map: Option<&'a TypesSourceMap>,
     in_binders: DebruijnIndex,
     // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases
     // where expected
@@ -138,13 +143,20 @@ pub struct TyLoweringContext<'a> {
 }
 
 impl<'a> TyLoweringContext<'a> {
-    pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver, owner: TypeOwnerId) -> Self {
-        Self::new_maybe_unowned(db, resolver, Some(owner))
+    pub fn new(
+        db: &'a dyn HirDatabase,
+        resolver: &'a Resolver,
+        types_map: &'a TypesMap,
+        owner: TypeOwnerId,
+    ) -> Self {
+        Self::new_maybe_unowned(db, resolver, types_map, None, Some(owner))
     }
 
     pub fn new_maybe_unowned(
         db: &'a dyn HirDatabase,
         resolver: &'a Resolver,
+        types_map: &'a TypesMap,
+        types_source_map: Option<&'a TypesSourceMap>,
         owner: Option<TypeOwnerId>,
     ) -> Self {
         let impl_trait_mode = ImplTraitLoweringState::Disallowed;
@@ -154,6 +166,8 @@ impl<'a> TyLoweringContext<'a> {
             db,
             resolver,
             generics: OnceCell::new(),
+            types_map,
+            types_source_map,
             owner,
             in_binders,
             impl_trait_mode,
@@ -201,6 +215,16 @@ impl<'a> TyLoweringContext<'a> {
     pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
         Self { type_param_mode, ..self }
     }
+
+    pub fn impl_trait_mode(&mut self, impl_trait_mode: ImplTraitLoweringMode) -> &mut Self {
+        self.impl_trait_mode = ImplTraitLoweringState::new(impl_trait_mode);
+        self
+    }
+
+    pub fn type_param_mode(&mut self, type_param_mode: ParamLoweringMode) -> &mut Self {
+        self.type_param_mode = type_param_mode;
+        self
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -230,7 +254,7 @@ pub enum ParamLoweringMode {
 }
 
 impl<'a> TyLoweringContext<'a> {
-    pub fn lower_ty(&self, type_ref: &TypeRef) -> Ty {
+    pub fn lower_ty(&self, type_ref: TypeRefId) -> Ty {
         self.lower_ty_ext(type_ref).0
     }
 
@@ -254,12 +278,13 @@ impl<'a> TyLoweringContext<'a> {
             .as_ref()
     }
 
-    pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
+    pub fn lower_ty_ext(&self, type_ref_id: TypeRefId) -> (Ty, Option<TypeNs>) {
         let mut res = None;
+        let type_ref = &self.types_map[type_ref_id];
         let ty = match type_ref {
             TypeRef::Never => TyKind::Never.intern(Interner),
             TypeRef::Tuple(inner) => {
-                let inner_tys = inner.iter().map(|tr| self.lower_ty(tr));
+                let inner_tys = inner.iter().map(|&tr| self.lower_ty(tr));
                 TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
                     .intern(Interner)
             }
@@ -268,38 +293,43 @@ impl<'a> TyLoweringContext<'a> {
                 res = res_;
                 ty
             }
-            TypeRef::RawPtr(inner, mutability) => {
+            &TypeRef::RawPtr(inner, mutability) => {
                 let inner_ty = self.lower_ty(inner);
-                TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(Interner)
+                TyKind::Raw(lower_to_chalk_mutability(mutability), inner_ty).intern(Interner)
             }
-            TypeRef::Array(inner, len) => {
-                let inner_ty = self.lower_ty(inner);
-                let const_len = self.lower_const(len, TyBuilder::usize());
+            TypeRef::Array(array) => {
+                let inner_ty = self.lower_ty(array.ty);
+                let const_len = self.lower_const(&array.len, TyBuilder::usize());
                 TyKind::Array(inner_ty, const_len).intern(Interner)
             }
-            TypeRef::Slice(inner) => {
+            &TypeRef::Slice(inner) => {
                 let inner_ty = self.lower_ty(inner);
                 TyKind::Slice(inner_ty).intern(Interner)
             }
-            TypeRef::Reference(inner, lifetime, mutability) => {
-                let inner_ty = self.lower_ty(inner);
+            TypeRef::Reference(ref_) => {
+                let inner_ty = self.lower_ty(ref_.ty);
                 // FIXME: It should infer the eldided lifetimes instead of stubbing with static
-                let lifetime =
-                    lifetime.as_ref().map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
-                TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
+                let lifetime = ref_
+                    .lifetime
+                    .as_ref()
+                    .map_or_else(error_lifetime, |lr| self.lower_lifetime(lr));
+                TyKind::Ref(lower_to_chalk_mutability(ref_.mutability), lifetime, inner_ty)
                     .intern(Interner)
             }
             TypeRef::Placeholder => TyKind::Error.intern(Interner),
-            &TypeRef::Fn(ref params, variadic, is_unsafe, ref abi) => {
+            TypeRef::Fn(fn_) => {
                 let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
-                    Substitution::from_iter(Interner, params.iter().map(|(_, tr)| ctx.lower_ty(tr)))
+                    Substitution::from_iter(
+                        Interner,
+                        fn_.params().iter().map(|&(_, tr)| ctx.lower_ty(tr)),
+                    )
                 });
                 TyKind::Function(FnPointer {
                     num_binders: 0, // FIXME lower `for<'a> fn()` correctly
                     sig: FnSig {
-                        abi: abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
-                        safety: if is_unsafe { Safety::Unsafe } else { Safety::Safe },
-                        variadic,
+                        abi: fn_.abi().as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol),
+                        safety: if fn_.is_unsafe() { Safety::Unsafe } else { Safety::Safe },
+                        variadic: fn_.is_varargs(),
                     },
                     substitution: FnSubst(substs),
                 })
@@ -351,8 +381,8 @@ impl<'a> TyLoweringContext<'a> {
                     ImplTraitLoweringState::Param(counter) => {
                         let idx = counter.get();
                         // Count the number of `impl Trait` things that appear within our bounds.
-                        // Since t hose have been emitted as implicit type args already.
-                        counter.set(idx + count_impl_traits(type_ref) as u16);
+                        // Since those have been emitted as implicit type args already.
+                        counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
                         let kind = self
                             .generics()
                             .expect("param impl trait lowering must be in a generic def")
@@ -376,7 +406,7 @@ impl<'a> TyLoweringContext<'a> {
                         let idx = counter.get();
                         // Count the number of `impl Trait` things that appear within our bounds.
                         // Since t hose have been emitted as implicit type args already.
-                        counter.set(idx + count_impl_traits(type_ref) as u16);
+                        counter.set(idx + self.count_impl_traits(type_ref_id) as u16);
                         let kind = self
                             .generics()
                             .expect("variable impl trait lowering must be in a generic def")
@@ -432,12 +462,40 @@ impl<'a> TyLoweringContext<'a> {
                     match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, resolver)
                     {
                         Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
-                            let ctx = expander.ctx(self.db.upcast());
+                            let (mut types_map, mut types_source_map) =
+                                (TypesMap::default(), TypesSourceMap::default());
+
+                            let ctx = expander.ctx(
+                                self.db.upcast(),
+                                &mut types_map,
+                                &mut types_source_map,
+                            );
                             // FIXME: Report syntax errors in expansion here
                             let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
 
                             drop(expander);
-                            let ty = self.lower_ty(&type_ref);
+
+                            // FIXME: That may be better served by mutating `self` then restoring, but this requires
+                            // making it `&mut self`.
+                            let inner_ctx = TyLoweringContext {
+                                db: self.db,
+                                resolver: self.resolver,
+                                generics: self.generics.clone(),
+                                types_map: &types_map,
+                                types_source_map: Some(&types_source_map),
+                                in_binders: self.in_binders,
+                                owner: self.owner,
+                                type_param_mode: self.type_param_mode,
+                                impl_trait_mode: self.impl_trait_mode.take(),
+                                expander: RefCell::new(self.expander.take()),
+                                unsized_types: RefCell::new(self.unsized_types.take()),
+                            };
+
+                            let ty = inner_ctx.lower_ty(type_ref);
+
+                            self.impl_trait_mode.swap(&inner_ctx.impl_trait_mode);
+                            *self.expander.borrow_mut() = inner_ctx.expander.into_inner();
+                            *self.unsized_types.borrow_mut() = inner_ctx.unsized_types.into_inner();
 
                             self.expander.borrow_mut().as_mut().unwrap().exit(mark);
                             Some(ty)
@@ -463,7 +521,8 @@ impl<'a> TyLoweringContext<'a> {
     /// This is only for `generic_predicates_for_param`, where we can't just
     /// lower the self types of the predicates since that could lead to cycles.
     /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
+    fn lower_ty_only_param(&self, type_ref: TypeRefId) -> Option<TypeOrConstParamId> {
+        let type_ref = &self.types_map[type_ref];
         let path = match type_ref {
             TypeRef::Path(path) => path,
             _ => return None,
@@ -663,7 +722,7 @@ impl<'a> TyLoweringContext<'a> {
         if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() {
             // trait object type without dyn
             let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None);
-            let ty = self.lower_dyn_trait(&[Interned::new(bound)]);
+            let ty = self.lower_dyn_trait(&[bound]);
             return (ty, None);
         }
 
@@ -864,7 +923,7 @@ impl<'a> TyLoweringContext<'a> {
                     assert!(matches!(id, GenericParamId::TypeParamId(_)));
                     had_explicit_args = true;
                     if let GenericArg::Type(ty) = &args[0] {
-                        substs.push(self.lower_ty(ty).cast(Interner));
+                        substs.push(self.lower_ty(*ty).cast(Interner));
                     }
                 }
             } else {
@@ -901,6 +960,7 @@ impl<'a> TyLoweringContext<'a> {
                     id,
                     arg,
                     &mut (),
+                    self.types_map,
                     |_, type_ref| self.lower_ty(type_ref),
                     |_, const_ref, ty| self.lower_const(const_ref, ty),
                     |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
@@ -998,7 +1058,7 @@ impl<'a> TyLoweringContext<'a> {
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
                 let self_ty = match target {
-                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
+                    WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(*type_ref),
                     &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
                         let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
                         match self.type_param_mode {
@@ -1029,12 +1089,12 @@ impl<'a> TyLoweringContext<'a> {
 
     pub(crate) fn lower_type_bound(
         &'a self,
-        bound: &'a Interned<TypeBound>,
+        bound: &'a TypeBound,
         self_ty: Ty,
         ignore_bindings: bool,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
         let mut trait_ref = None;
-        let clause = match bound.as_ref() {
+        let clause = match bound {
             TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, self_ty);
                 trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
@@ -1067,7 +1127,7 @@ impl<'a> TyLoweringContext<'a> {
                     lifetime,
                 })))
             }
-            TypeBound::Error => None,
+            TypeBound::Use(_) | TypeBound::Error => None,
         };
         clause.into_iter().chain(
             trait_ref
@@ -1079,14 +1139,15 @@ impl<'a> TyLoweringContext<'a> {
 
     fn assoc_type_bindings_from_type_bound(
         &'a self,
-        bound: &'a Interned<TypeBound>,
+        bound: &'a TypeBound,
         trait_ref: TraitRef,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'a {
-        let last_segment = match bound.as_ref() {
+        let last_segment = match bound {
             TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => {
                 path.segments().last()
             }
             TypeBound::Path(_, TraitBoundModifier::Maybe)
+            | TypeBound::Use(_)
             | TypeBound::Error
             | TypeBound::Lifetime(_) => None,
         };
@@ -1110,7 +1171,7 @@ impl<'a> TyLoweringContext<'a> {
                 // this point (`super_trait_ref.substitution`).
                 let substitution = self.substs_from_path_segment(
                     // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
-                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+                    PathSegment { name: &binding.name, args_and_bindings: binding.args.as_ref() },
                     Some(associated_ty.into()),
                     false, // this is not relevant
                     Some(super_trait_ref.self_type_parameter(Interner)),
@@ -1130,8 +1191,8 @@ impl<'a> TyLoweringContext<'a> {
                 let mut predicates: SmallVec<[_; 1]> = SmallVec::with_capacity(
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
-                if let Some(type_ref) = &binding.type_ref {
-                    match (type_ref, &self.impl_trait_mode) {
+                if let Some(type_ref) = binding.type_ref {
+                    match (&self.types_map[type_ref], &self.impl_trait_mode) {
                         (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
                         (
                             _,
@@ -1178,6 +1239,8 @@ impl<'a> TyLoweringContext<'a> {
                                 let mut ext = TyLoweringContext::new_maybe_unowned(
                                     self.db,
                                     self.resolver,
+                                    self.types_map,
+                                    self.types_source_map,
                                     self.owner,
                                 )
                                 .with_type_param_mode(self.type_param_mode);
@@ -1215,7 +1278,7 @@ impl<'a> TyLoweringContext<'a> {
             })
     }
 
-    fn lower_dyn_trait(&self, bounds: &[Interned<TypeBound>]) -> Ty {
+    fn lower_dyn_trait(&self, bounds: &[TypeBound]) -> Ty {
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         // INVARIANT: The principal trait bound, if present, must come first. Others may be in any
         // order but should be in the same order for the same set but possibly different order of
@@ -1313,7 +1376,7 @@ impl<'a> TyLoweringContext<'a> {
         }
     }
 
-    fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>], krate: CrateId) -> ImplTrait {
+    fn lower_impl_trait(&self, bounds: &[TypeBound], krate: CrateId) -> ImplTrait {
         cov_mark::hit!(lower_rpit);
         let self_ty = TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(Interner);
         let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
@@ -1365,6 +1428,17 @@ impl<'a> TyLoweringContext<'a> {
             None => error_lifetime(),
         }
     }
+
+    // FIXME: This does not handle macros!
+    fn count_impl_traits(&self, type_ref: TypeRefId) -> usize {
+        let mut count = 0;
+        TypeRef::walk(type_ref, self.types_map, &mut |type_ref| {
+            if matches!(type_ref, TypeRef::ImplTrait(_)) {
+                count += 1;
+            }
+        });
+        count
+    }
 }
 
 /// Build the signature of a callable item (function, struct or enum variant).
@@ -1385,17 +1459,6 @@ pub fn associated_type_shorthand_candidates<R>(
     named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
 }
 
-// FIXME: This does not handle macros!
-fn count_impl_traits(type_ref: &TypeRef) -> usize {
-    let mut count = 0;
-    type_ref.walk(&mut |type_ref| {
-        if matches!(type_ref, TypeRef::ImplTrait(_)) {
-            count += 1;
-        }
-    });
-    count
-}
-
 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
@@ -1499,10 +1562,10 @@ pub(crate) fn field_types_query(
     };
     let generics = generics(db.upcast(), def);
     let mut res = ArenaMap::default();
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, var_data.types_map(), def.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
+        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref)));
     }
     Arc::new(res)
 }
@@ -1522,38 +1585,38 @@ pub(crate) fn generic_predicates_for_param_query(
     assoc_name: Option<Name>,
 ) -> GenericPredicates {
     let resolver = def.resolver(db.upcast());
-    let ctx = if let GenericDefId::FunctionId(_) = def {
-        TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = if let GenericDefId::FunctionId(_) = def {
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
             .with_type_param_mode(ParamLoweringMode::Variable)
     } else {
-        TyLoweringContext::new(db, &resolver, def.into())
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_type_param_mode(ParamLoweringMode::Variable)
     };
     let generics = generics(db.upcast(), def);
 
     // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |(pred, &def): &(&_, _)| match pred {
+    let predicate = |pred: &_, def: &_, ctx: &TyLoweringContext<'_>| match pred {
         WherePredicate::ForLifetime { target, bound, .. }
         | WherePredicate::TypeBound { target, bound, .. } => {
             let invalid_target = match target {
                 WherePredicateTypeTarget::TypeRef(type_ref) => {
-                    ctx.lower_ty_only_param(type_ref) != Some(param_id)
+                    ctx.lower_ty_only_param(*type_ref) != Some(param_id)
                 }
                 &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
-                    let target_id = TypeOrConstParamId { parent: def, local_id };
+                    let target_id = TypeOrConstParamId { parent: *def, local_id };
                     target_id != param_id
                 }
             };
             if invalid_target {
                 // If this is filtered out without lowering, `?Sized` is not gathered into `ctx.unsized_types`
-                if let TypeBound::Path(_, TraitBoundModifier::Maybe) = &**bound {
-                    ctx.lower_where_predicate(pred, &def, true).for_each(drop);
+                if let TypeBound::Path(_, TraitBoundModifier::Maybe) = bound {
+                    ctx.lower_where_predicate(pred, def, true).for_each(drop);
                 }
                 return false;
             }
 
-            match &**bound {
+            match bound {
                 TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => {
                     // Only lower the bound if the trait could possibly define the associated
                     // type we're looking for.
@@ -1571,18 +1634,20 @@ pub(crate) fn generic_predicates_for_param_query(
                         })
                     })
                 }
-                TypeBound::Lifetime(_) | TypeBound::Error => false,
+                TypeBound::Use(_) | TypeBound::Lifetime(_) | TypeBound::Error => false,
             }
         }
         WherePredicate::Lifetime { .. } => false,
     };
-    let mut predicates: Vec<_> = resolver
-        .where_predicates_in_scope()
-        .filter(predicate)
-        .flat_map(|(pred, def)| {
-            ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
-        })
-        .collect();
+    let mut predicates = Vec::new();
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        predicates.extend(
+            params.where_predicates().filter(|pred| predicate(pred, def, &ctx)).flat_map(|pred| {
+                ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
+            }),
+        );
+    }
 
     let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
     if !subst.is_empty(Interner) {
@@ -1629,23 +1694,27 @@ pub(crate) fn trait_environment_query(
     def: GenericDefId,
 ) -> Arc<TraitEnvironment> {
     let resolver = def.resolver(db.upcast());
-    let ctx = if let GenericDefId::FunctionId(_) = def {
-        TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = if let GenericDefId::FunctionId(_) = def {
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_impl_trait_mode(ImplTraitLoweringMode::Param)
             .with_type_param_mode(ParamLoweringMode::Placeholder)
     } else {
-        TyLoweringContext::new(db, &resolver, def.into())
+        TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
             .with_type_param_mode(ParamLoweringMode::Placeholder)
     };
     let mut traits_in_scope = Vec::new();
     let mut clauses = Vec::new();
-    for (pred, def) in resolver.where_predicates_in_scope() {
-        for pred in ctx.lower_where_predicate(pred, def, false) {
-            if let WhereClause::Implemented(tr) = &pred.skip_binders() {
-                traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        for pred in params.where_predicates() {
+            for pred in ctx.lower_where_predicate(pred, def, 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: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
+                clauses.push(program_clause.into_from_env_clause(Interner));
             }
-            let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
-            clauses.push(program_clause.into_from_env_clause(Interner));
         }
     }
 
@@ -1724,18 +1793,20 @@ where
         }
         _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable),
     };
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
         .with_impl_trait_mode(impl_trait_lowering)
         .with_type_param_mode(param_lowering);
     let generics = generics(db.upcast(), def);
 
-    let mut predicates = resolver
-        .where_predicates_in_scope()
-        .filter(|(pred, def)| filter(pred, def))
-        .flat_map(|(pred, def)| {
-            ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
-        })
-        .collect::<Vec<_>>();
+    let mut predicates = Vec::new();
+    for (params, def) in resolver.all_generic_params() {
+        ctx.types_map = &params.types_map;
+        predicates.extend(params.where_predicates().filter(|pred| filter(pred, def)).flat_map(
+            |pred| {
+                ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
+            },
+        ));
+    }
 
     if generics.len() > 0 {
         let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
@@ -1811,18 +1882,19 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
     let resolver = def.resolver(db.upcast());
     let parent_start_idx = generic_params.len_self();
 
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map(
-        |(idx, (id, p))| {
+    GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map(
+        |(idx, ((id, p), types_map))| {
+            ctx.types_map = types_map;
             match p {
                 GenericParamDataRef::TypeParamData(p) => {
                     let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| {
                         // Each default can only refer to previous parameters.
                         // Type variable default referring to parameter coming
                         // after it is forbidden (FIXME: report diagnostic)
-                        fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx)
+                        fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx)
                     });
                     crate::make_binders(db, &generic_params, ty.cast(Interner))
                 }
@@ -1834,7 +1906,7 @@ pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) ->
                     let mut val = p.default.as_ref().map_or_else(
                         || unknown_const_as_generic(db.const_param_ty(id)),
                         |c| {
-                            let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+                            let c = ctx.lower_const(c, ctx.lower_ty(p.ty));
                             c.cast(Interner)
                         },
                     );
@@ -1874,14 +1946,14 @@ pub(crate) fn generic_defaults_recover(
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx_params = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx_params = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr));
-    let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+    let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr));
+    let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let ret = ctx_ret.lower_ty(&data.ret_type);
+    let ret = ctx_ret.lower_ty(data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let sig = CallableSig::from_params_and_return(
         params,
@@ -1910,28 +1982,33 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
     let data = db.const_data(def);
     let generics = generics(db.upcast(), def.into());
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
 
-    make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
+    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_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into());
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into());
 
-    Binders::empty(Interner, ctx.lower_ty(&data.type_ref))
+    Binders::empty(Interner, ctx.lower_ty(data.type_ref))
 }
 
 fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
     let struct_data = db.struct_data(def);
     let fields = struct_data.variant_data.fields();
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into())
-        .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        struct_data.variant_data.types_map(),
+        AdtId::from(def).into(),
+    )
+    .with_type_param_mode(ParamLoweringMode::Variable);
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
     Binders::new(
         binders,
@@ -1961,9 +2038,14 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let var_data = db.enum_variant_data(def);
     let fields = var_data.variant_data.fields();
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into())
-        .with_type_param_mode(ParamLoweringMode::Variable);
-    let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref));
+    let ctx = TyLoweringContext::new(
+        db,
+        &resolver,
+        var_data.variant_data.types_map(),
+        DefWithBodyId::VariantId(def).into(),
+    )
+    .with_type_param_mode(ParamLoweringMode::Variable);
+    let params = fields.iter().map(|(_, field)| ctx.lower_ty(field.type_ref));
     let (ret, binders) =
         type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders();
     Binders::new(
@@ -2004,15 +2086,17 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
 fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     let generics = generics(db.upcast(), t.into());
     let resolver = t.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, t.into())
+    let type_alias_data = db.type_alias_data(t);
+    let ctx = TyLoweringContext::new(db, &resolver, &type_alias_data.types_map, t.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let type_alias_data = db.type_alias_data(t);
     let inner = if type_alias_data.is_extern {
         TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)
     } else {
-        let type_ref = &type_alias_data.type_ref;
-        ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error))
+        type_alias_data
+            .type_ref
+            .map(|type_ref| ctx.lower_ty(type_ref))
+            .unwrap_or_else(|| TyKind::Error.intern(Interner))
     };
     make_binders(db, &generics, inner)
 }
@@ -2085,9 +2169,9 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
     let generics = generics(db.upcast(), impl_id.into());
-    let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .with_type_param_mode(ParamLoweringMode::Variable);
-    make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
+    make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty))
 }
 
 // returns None if def is a type arg
@@ -2095,13 +2179,13 @@ pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> T
     let parent_data = db.generic_params(def.parent());
     let data = &parent_data[def.local_id()];
     let resolver = def.parent().resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.parent().into());
+    let ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into());
     match data {
         TypeOrConstParamData::TypeParamData(_) => {
             never!();
             Ty::new(Interner, TyKind::Error)
         }
-        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
+        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty),
     }
 }
 
@@ -2117,7 +2201,7 @@ pub(crate) fn impl_self_ty_recover(
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
     let impl_data = db.impl_data(impl_id);
     let resolver = impl_id.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, impl_id.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into())
         .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()?;
@@ -2131,10 +2215,10 @@ pub(crate) fn return_type_impl_traits(
     // FIXME unify with fn_sig_for_fn instead of doing lowering twice, maybe
     let data = db.function_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx_ret = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx_ret = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    let _ret = ctx_ret.lower_ty(&data.ret_type);
+    let _ret = ctx_ret.lower_ty(data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let return_type_impl_traits = ImplTraits {
         impl_traits: match ctx_ret.impl_trait_mode {
@@ -2155,10 +2239,10 @@ pub(crate) fn type_alias_impl_traits(
 ) -> Option<Arc<Binders<ImplTraits>>> {
     let data = db.type_alias_data(def);
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver, def.into())
+    let ctx = TyLoweringContext::new(db, &resolver, &data.types_map, def.into())
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
         .with_type_param_mode(ParamLoweringMode::Variable);
-    if let Some(type_ref) = &data.type_ref {
+    if let Some(type_ref) = data.type_ref {
         let _ty = ctx.lower_ty(type_ref);
     }
     let type_alias_impl_traits = ImplTraits {
@@ -2190,7 +2274,8 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
     kind_id: GenericParamId,
     arg: &'a GenericArg,
     this: &mut T,
-    for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
+    types_map: &TypesMap,
+    for_type: impl FnOnce(&mut T, TypeRefId) -> Ty + 'a,
     for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
     for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
 ) -> crate::GenericArg {
@@ -2203,7 +2288,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
         GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
     };
     match (arg, kind) {
-        (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
+        (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, *type_ref).cast(Interner),
         (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
         (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
             for_lifetime(this, lifetime_ref).cast(Interner)
@@ -2214,7 +2299,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
             // We want to recover simple idents, which parser detects them
             // as types. Maybe here is not the best place to do it, but
             // it works.
-            if let TypeRef::Path(p) = t {
+            if let TypeRef::Path(p) = &types_map[*t] {
                 if let Some(p) = p.mod_path() {
                     if p.kind == PathKind::Plain {
                         if let [n] = p.segments() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
index 8e815aabf20..59c583afb2a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -879,7 +879,8 @@ pub enum Rvalue {
     ///
     /// **Needs clarification**: Are there weird additional semantics here related to the runtime
     /// nature of this operation?
-    //ThreadLocalRef(DefId),
+    // ThreadLocalRef(DefId),
+    ThreadLocalRef(std::convert::Infallible),
 
     /// Creates a pointer with the indicated mutability to the place.
     ///
@@ -888,7 +889,8 @@ pub enum Rvalue {
     ///
     /// Like with references, the semantics of this operation are heavily dependent on the aliasing
     /// model.
-    //AddressOf(Mutability, Place),
+    // AddressOf(Mutability, Place),
+    AddressOf(std::convert::Infallible),
 
     /// Yields the length of the place, as a `usize`.
     ///
@@ -906,19 +908,21 @@ pub enum Rvalue {
     Cast(CastKind, Operand, Ty),
 
     // FIXME link to `pointer::offset` when it hits stable.
-    // /// * `Offset` has the same semantics as `pointer::offset`, except that the second
-    // ///   parameter may be a `usize` as well.
-    // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
-    // ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
-    // ///   matching, up to the usual caveat of the lifetimes in function pointers.
-    // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
-    // ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
-    // ///   truncated as needed.
-    // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
-    // ///   types and return a value of that type.
-    // /// * The remaining operations accept signed integers, unsigned integers, or floats with
-    // ///   matching types and return a value of that type.
+    /// * `Offset` has the same semantics as `pointer::offset`, except that the second
+    ///   parameter may be a `usize` as well.
+    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+    ///   raw pointers, or function pointers and return a `bool`. The types of the operands must be
+    ///   matching, up to the usual caveat of the lifetimes in function pointers.
+    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+    ///   truncated as needed.
+    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+    ///   types and return a value of that type.
+    /// * The remaining operations accept signed integers, unsigned integers, or floats with
+    ///   matching types and return a value of that type.
     //BinaryOp(BinOp, Box<(Operand, Operand)>),
+    BinaryOp(std::convert::Infallible),
+
     /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
     ///
     /// When overflow checking is disabled and we are generating run-time code, the error condition
@@ -937,6 +941,7 @@ pub enum Rvalue {
 
     /// Computes a value as described by the operation.
     //NullaryOp(NullOp, Ty),
+    NullaryOp(std::convert::Infallible),
 
     /// Exactly like `BinaryOp`, but less operands.
     ///
@@ -1095,6 +1100,10 @@ impl MirBody {
                                     for_operand(op, &mut f, &mut self.projection_store);
                                 }
                             }
+                            Rvalue::ThreadLocalRef(n)
+                            | Rvalue::AddressOf(n)
+                            | Rvalue::BinaryOp(n)
+                            | Rvalue::NullaryOp(n) => match *n {},
                         }
                     }
                     StatementKind::FakeRead(p) | StatementKind::Deinit(p) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index 9830fa1ca7b..9c86d3b59f6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -167,6 +167,10 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
                             for_operand(op, statement.span);
                         }
                     }
+                    Rvalue::ThreadLocalRef(n)
+                    | Rvalue::AddressOf(n)
+                    | Rvalue::BinaryOp(n)
+                    | Rvalue::NullaryOp(n) => match *n {},
                 },
                 StatementKind::FakeRead(_)
                 | StatementKind::Deinit(_)
@@ -253,6 +257,10 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec<PartiallyMoved>
                             for_operand(op, statement.span);
                         }
                     }
+                    Rvalue::ThreadLocalRef(n)
+                    | Rvalue::AddressOf(n)
+                    | Rvalue::BinaryOp(n)
+                    | Rvalue::NullaryOp(n) => match *n {},
                 },
                 StatementKind::FakeRead(_)
                 | StatementKind::Deinit(_)
@@ -548,6 +556,10 @@ fn mutability_of_locals(
                             }
                         }
                         Rvalue::ShallowInitBox(_, _) | Rvalue::ShallowInitBoxWithAlloc(_) => (),
+                        Rvalue::ThreadLocalRef(n)
+                        | Rvalue::AddressOf(n)
+                        | Rvalue::BinaryOp(n)
+                        | Rvalue::NullaryOp(n) => match *n {},
                     }
                     if let Rvalue::Ref(
                         BorrowKind::Mut {
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 0d42617d185..e73b9dc27d1 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
@@ -6,6 +6,7 @@ use base_db::CrateId;
 use chalk_ir::{cast::Cast, Mutability};
 use either::Either;
 use hir_def::{
+    body::HygieneId,
     builtin_type::BuiltinType,
     data::adt::{StructFlags, VariantData},
     lang_item::LangItem,
@@ -1628,6 +1629,10 @@ impl Evaluator<'_> {
                 }
                 CastKind::FnPtrToPtr => not_supported!("fn ptr to ptr cast"),
             },
+            Rvalue::ThreadLocalRef(n)
+            | Rvalue::AddressOf(n)
+            | Rvalue::BinaryOp(n)
+            | Rvalue::NullaryOp(n) => match *n {},
         })
     }
 
@@ -2703,17 +2708,15 @@ impl Evaluator<'_> {
             TyKind::Function(_) => {
                 self.exec_fn_pointer(func_data, destination, &args[1..], locals, target_bb, span)
             }
-            TyKind::Closure(closure, subst) => {
-                return self.exec_closure(
-                    *closure,
-                    func_data,
-                    &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
-                    destination,
-                    &args[1..],
-                    locals,
-                    span,
-                );
-            }
+            TyKind::Closure(closure, subst) => self.exec_closure(
+                *closure,
+                func_data,
+                &Substitution::from_iter(Interner, ClosureSubst(subst).parent_subst()),
+                destination,
+                &args[1..],
+                locals,
+                span,
+            ),
             _ => {
                 // try to execute the manual impl of `FnTrait` for structs (nightly feature used in std)
                 let arg0 = func;
@@ -2846,7 +2849,8 @@ impl Evaluator<'_> {
                         }
                         let layout = self.layout_adt(id.0, subst.clone())?;
                         match data.variant_data.as_ref() {
-                            VariantData::Record(fields) | VariantData::Tuple(fields) => {
+                            VariantData::Record { fields, .. }
+                            | VariantData::Tuple { fields, .. } => {
                                 let field_types = self.db.field_types(s.into());
                                 for (field, _) in fields.iter() {
                                     let offset = layout
@@ -2951,6 +2955,7 @@ pub fn render_const_using_debug_impl(
     let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
         db.upcast(),
         &hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
+        HygieneId::ROOT,
     ) else {
         not_supported!("std::fmt::format not found");
     };
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 16994cdd0c6..c4e06400510 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
@@ -5,7 +5,7 @@ use std::{fmt::Write, iter, mem};
 use base_db::ra_salsa::Cycle;
 use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
 use hir_def::{
-    body::Body,
+    body::{Body, HygieneId},
     data::adt::{StructKind, VariantData},
     hir::{
         ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
@@ -13,7 +13,8 @@ use hir_def::{
     },
     lang_item::{LangItem, LangItemTarget},
     path::Path,
-    resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
+    resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
+    type_ref::TypesMap,
     AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
     Lookup, TraitId, TupleId, TypeOrConstParamId,
 };
@@ -28,7 +29,7 @@ use triomphe::Arc;
 use crate::{
     consteval::ConstEvalError,
     db::{HirDatabase, InternedClosure},
-    display::HirDisplay,
+    display::{hir_display_with_types_map, HirDisplay},
     error_lifetime,
     generics::generics,
     infer::{cast::CastTy, unify::InferenceTable, CaptureKind, CapturedItem, TypeMismatch},
@@ -76,6 +77,7 @@ struct MirLowerCtx<'a> {
     db: &'a dyn HirDatabase,
     body: &'a Body,
     infer: &'a InferenceResult,
+    resolver: Resolver,
     drop_scopes: Vec<DropScope>,
 }
 
@@ -246,8 +248,15 @@ impl From<LayoutError> for MirLowerError {
 }
 
 impl MirLowerError {
-    fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self {
-        Self::UnresolvedName(p.display(db, edition).to_string())
+    fn unresolved_path(
+        db: &dyn HirDatabase,
+        p: &Path,
+        edition: Edition,
+        types_map: &TypesMap,
+    ) -> Self {
+        Self::UnresolvedName(
+            hir_display_with_types_map(p, types_map).display(db, edition).to_string(),
+        )
     }
 }
 
@@ -278,6 +287,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             owner,
             closures: vec![],
         };
+        let resolver = owner.resolver(db.upcast());
 
         MirLowerCtx {
             result: mir,
@@ -285,6 +295,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             infer,
             body,
             owner,
+            resolver,
             current_loop_blocks: None,
             labeled_loop_blocks: Default::default(),
             discr_temp: None,
@@ -410,43 +421,54 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 Err(MirLowerError::IncompleteExpr)
             }
             Expr::Path(p) => {
-                let pr =
-                    if let Some((assoc, subst)) = self.infer.assoc_resolutions_for_expr(expr_id) {
-                        match assoc {
-                            hir_def::AssocItemId::ConstId(c) => {
-                                self.lower_const(
-                                    c.into(),
-                                    current,
-                                    place,
-                                    subst,
-                                    expr_id.into(),
-                                    self.expr_ty_without_adjust(expr_id),
-                                )?;
-                                return Ok(Some(current));
-                            }
-                            hir_def::AssocItemId::FunctionId(_) => {
-                                // FnDefs are zero sized, no action is needed.
-                                return Ok(Some(current));
-                            }
-                            hir_def::AssocItemId::TypeAliasId(_) => {
-                                // FIXME: If it is unreachable, use proper error instead of `not_supported`.
-                                not_supported!("associated functions and types")
-                            }
+                let pr = if let Some((assoc, subst)) =
+                    self.infer.assoc_resolutions_for_expr(expr_id)
+                {
+                    match assoc {
+                        hir_def::AssocItemId::ConstId(c) => {
+                            self.lower_const(
+                                c.into(),
+                                current,
+                                place,
+                                subst,
+                                expr_id.into(),
+                                self.expr_ty_without_adjust(expr_id),
+                            )?;
+                            return Ok(Some(current));
                         }
-                    } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
-                        match variant {
-                            VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
-                            VariantId::StructId(s) => ValueNs::StructId(s),
-                            VariantId::UnionId(_) => implementation_error!("Union variant as path"),
+                        hir_def::AssocItemId::FunctionId(_) => {
+                            // FnDefs are zero sized, no action is needed.
+                            return Ok(Some(current));
                         }
-                    } else {
-                        let unresolved_name =
-                            || MirLowerError::unresolved_path(self.db, p, self.edition());
-                        let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
-                        resolver
-                            .resolve_path_in_value_ns_fully(self.db.upcast(), p)
-                            .ok_or_else(unresolved_name)?
-                    };
+                        hir_def::AssocItemId::TypeAliasId(_) => {
+                            // FIXME: If it is unreachable, use proper error instead of `not_supported`.
+                            not_supported!("associated functions and types")
+                        }
+                    }
+                } else if let Some(variant) = self.infer.variant_resolution_for_expr(expr_id) {
+                    match variant {
+                        VariantId::EnumVariantId(e) => ValueNs::EnumVariantId(e),
+                        VariantId::StructId(s) => ValueNs::StructId(s),
+                        VariantId::UnionId(_) => implementation_error!("Union variant as path"),
+                    }
+                } else {
+                    let resolver_guard =
+                        self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+                    let hygiene = self.body.expr_path_hygiene(expr_id);
+                    let result = self
+                        .resolver
+                        .resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene)
+                        .ok_or_else(|| {
+                            MirLowerError::unresolved_path(
+                                self.db,
+                                p,
+                                self.edition(),
+                                &self.body.types,
+                            )
+                        })?;
+                    self.resolver.reset_to_guard(resolver_guard);
+                    result
+                };
                 match pr {
                     ValueNs::LocalBinding(_) | ValueNs::StaticId(_) => {
                         let Some((temp, current)) =
@@ -553,8 +575,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     return Ok(None);
                 };
                 self.push_fake_read(current, cond_place, expr_id.into());
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
                 let (then_target, else_target) =
                     self.pattern_match(current, None, cond_place, *pat)?;
+                self.resolver.reset_to_guard(resolver_guard);
                 self.write_bytes_to_place(
                     then_target,
                     place,
@@ -688,6 +713,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 };
                 self.push_fake_read(current, cond_place, expr_id.into());
                 let mut end = None;
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
                 for MatchArm { pat, guard, expr } in arms.iter() {
                     let (then, mut otherwise) =
                         self.pattern_match(current, None, cond_place, *pat)?;
@@ -721,6 +748,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         }
                     }
                 }
+                self.resolver.reset_to_guard(resolver_guard);
                 if self.is_unterminated(current) {
                     self.set_terminator(current, TerminatorKind::Unreachable, expr_id.into());
                 }
@@ -795,7 +823,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             }
             Expr::Become { .. } => not_supported!("tail-calls"),
             Expr::Yield { .. } => not_supported!("yield"),
-            Expr::RecordLit { fields, path, spread, ellipsis: _, is_assignee_expr: _ } => {
+            Expr::RecordLit { fields, path, spread } => {
                 let spread_place = match spread {
                     &Some(it) => {
                         let Some((p, c)) = self.lower_expr_as_place(current, it, true)? else {
@@ -809,7 +837,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 let variant_id =
                     self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path {
                         Some(p) => MirLowerError::UnresolvedName(
-                            p.display(self.db, self.edition()).to_string(),
+                            hir_display_with_types_map(&**p, &self.body.types)
+                                .display(self.db, self.edition())
+                                .to_string(),
                         ),
                         None => MirLowerError::RecordLiteralWithoutPath,
                     })?;
@@ -1010,35 +1040,28 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         );
                     }
                 }
-                if let hir_def::hir::BinaryOp::Assignment { op } = op {
-                    if let Some(op) = op {
-                        // last adjustment is `&mut` which we don't want it.
-                        let adjusts = self
-                            .infer
-                            .expr_adjustments
-                            .get(lhs)
-                            .and_then(|it| it.split_last())
-                            .map(|it| it.1)
-                            .ok_or(MirLowerError::TypeError(
-                                "adjustment of binary op was missing",
-                            ))?;
-                        let Some((lhs_place, current)) =
-                            self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
-                        else {
-                            return Ok(None);
-                        };
-                        let Some((rhs_op, current)) =
-                            self.lower_expr_to_some_operand(*rhs, current)?
-                        else {
-                            return Ok(None);
-                        };
-                        let r_value =
-                            Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
-                        self.push_assignment(current, lhs_place, r_value, expr_id.into());
-                        return Ok(Some(current));
-                    } else {
-                        return self.lower_assignment(current, *lhs, *rhs, expr_id.into());
-                    }
+                if let hir_def::hir::BinaryOp::Assignment { op: Some(op) } = op {
+                    // last adjustment is `&mut` which we don't want it.
+                    let adjusts = self
+                        .infer
+                        .expr_adjustments
+                        .get(lhs)
+                        .and_then(|it| it.split_last())
+                        .map(|it| it.1)
+                        .ok_or(MirLowerError::TypeError("adjustment of binary op was missing"))?;
+                    let Some((lhs_place, current)) =
+                        self.lower_expr_as_place_with_adjust(current, *lhs, false, adjusts)?
+                    else {
+                        return Ok(None);
+                    };
+                    let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)?
+                    else {
+                        return Ok(None);
+                    };
+                    let r_value =
+                        Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op);
+                    self.push_assignment(current, lhs_place, r_value, expr_id.into());
+                    return Ok(Some(current));
                 }
                 let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)?
                 else {
@@ -1097,6 +1120,18 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 );
                 Ok(Some(current))
             }
+            &Expr::Assignment { target, value } => {
+                let Some((value, mut current)) = self.lower_expr_as_place(current, value, true)?
+                else {
+                    return Ok(None);
+                };
+                self.push_fake_read(current, value, expr_id.into());
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+                current = self.pattern_match_assignment(current, value, target)?;
+                self.resolver.reset_to_guard(resolver_guard);
+                Ok(Some(current))
+            }
             &Expr::Range { lhs, rhs, range_type: _ } => {
                 let ty = self.expr_ty_without_adjust(expr_id);
                 let Some((adt, subst)) = ty.as_adt() else {
@@ -1213,7 +1248,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 );
                 Ok(Some(current))
             }
-            Expr::Tuple { exprs, is_assignee_expr: _ } => {
+            Expr::Tuple { exprs } => {
                 let Some(values) = exprs
                     .iter()
                     .map(|it| {
@@ -1291,73 +1326,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
         }
     }
 
-    fn lower_destructing_assignment(
-        &mut self,
-        mut current: BasicBlockId,
-        lhs: ExprId,
-        rhs: Place,
-        span: MirSpan,
-    ) -> Result<Option<BasicBlockId>> {
-        match &self.body.exprs[lhs] {
-            Expr::Tuple { exprs, is_assignee_expr: _ } => {
-                for (i, expr) in exprs.iter().enumerate() {
-                    let rhs = rhs.project(
-                        ProjectionElem::Field(Either::Right(TupleFieldId {
-                            tuple: TupleId(!0), // Dummy this as its unused
-                            index: i as u32,
-                        })),
-                        &mut self.result.projection_store,
-                    );
-                    let Some(c) = self.lower_destructing_assignment(current, *expr, rhs, span)?
-                    else {
-                        return Ok(None);
-                    };
-                    current = c;
-                }
-                Ok(Some(current))
-            }
-            Expr::Underscore => Ok(Some(current)),
-            _ => {
-                let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)?
-                else {
-                    return Ok(None);
-                };
-                self.push_assignment(current, lhs_place, Operand::Copy(rhs).into(), span);
-                Ok(Some(current))
-            }
-        }
-    }
-
-    fn lower_assignment(
-        &mut self,
-        current: BasicBlockId,
-        lhs: ExprId,
-        rhs: ExprId,
-        span: MirSpan,
-    ) -> Result<Option<BasicBlockId>> {
-        let Some((rhs_op, current)) = self.lower_expr_to_some_operand(rhs, current)? else {
-            return Ok(None);
-        };
-        if matches!(&self.body.exprs[lhs], Expr::Underscore) {
-            self.push_fake_read_for_operand(current, rhs_op, span);
-            return Ok(Some(current));
-        }
-        if matches!(
-            &self.body.exprs[lhs],
-            Expr::Tuple { .. } | Expr::RecordLit { .. } | Expr::Call { .. }
-        ) {
-            let temp = self.temp(self.expr_ty_after_adjustments(rhs), current, rhs.into())?;
-            let temp = Place::from(temp);
-            self.push_assignment(current, temp, rhs_op.into(), span);
-            return self.lower_destructing_assignment(current, lhs, temp, span);
-        }
-        let Some((lhs_place, current)) = self.lower_expr_as_place(current, lhs, false)? else {
-            return Ok(None);
-        };
-        self.push_assignment(current, lhs_place, rhs_op.into(), span);
-        Ok(Some(current))
-    }
-
     fn placeholder_subst(&mut self) -> Substitution {
         match self.owner.as_generic_def_id(self.db.upcast()) {
             Some(it) => TyBuilder::placeholder_subst(self.db, it),
@@ -1406,10 +1374,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 };
                 let edition = self.edition();
                 let unresolved_name =
-                    || MirLowerError::unresolved_path(self.db, c.as_ref(), edition);
-                let resolver = self.owner.resolver(self.db.upcast());
-                let pr = resolver
-                    .resolve_path_in_value_ns(self.db.upcast(), c.as_ref())
+                    || MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
+                let pr = self
+                    .resolver
+                    .resolve_path_in_value_ns(self.db.upcast(), c, HygieneId::ROOT)
                     .ok_or_else(unresolved_name)?;
                 match pr {
                     ResolveValueResult::ValueNs(v, _) => {
@@ -1632,12 +1600,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
         self.push_statement(block, StatementKind::FakeRead(p).with_span(span));
     }
 
-    fn push_fake_read_for_operand(&mut self, block: BasicBlockId, operand: Operand, span: MirSpan) {
-        if let Operand::Move(p) | Operand::Copy(p) = operand {
-            self.push_fake_read(block, p, span);
-        }
-    }
-
     fn push_assignment(
         &mut self,
         block: BasicBlockId,
@@ -1791,8 +1753,16 @@ impl<'ctx> MirLowerCtx<'ctx> {
                         };
                         current = c;
                         self.push_fake_read(current, init_place, span);
+                        // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations
+                        // and has all declarations of the `let`.
+                        let resolver_guard = self.resolver.update_to_inner_scope(
+                            self.db.upcast(),
+                            self.owner,
+                            *expr_id,
+                        );
                         (current, else_block) =
                             self.pattern_match(current, None, init_place, *pat)?;
+                        self.resolver.reset_to_guard(resolver_guard);
                         match (else_block, else_branch) {
                             (None, _) => (),
                             (Some(else_block), None) => {
@@ -1828,7 +1798,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     self.push_fake_read(c, p, expr.into());
                     current = scope2.pop_and_drop(self, c, expr.into());
                 }
-                hir_def::hir::Statement::Item => (),
+                hir_def::hir::Statement::Item(_) => (),
             }
         }
         if let Some(tail) = tail {
@@ -2066,11 +2036,13 @@ pub fn mir_body_for_closure_query(
     let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else {
         implementation_error!("closure has not callable sig");
     };
+    let resolver_guard = ctx.resolver.update_to_inner_scope(db.upcast(), owner, expr);
     let current = ctx.lower_params_and_bindings(
         args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())),
         None,
         |_| true,
     )?;
+    ctx.resolver.reset_to_guard(resolver_guard);
     if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? {
         let current = ctx.pop_drop_scope_assert_finished(current, root.into())?;
         ctx.set_terminator(current, TerminatorKind::Return, (*root).into());
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index 424ee1160c8..420f2aaff46 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -135,8 +135,13 @@ impl MirLowerCtx<'_> {
         };
         match &self.body.exprs[expr_id] {
             Expr::Path(p) => {
-                let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
-                let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else {
+                let resolver_guard =
+                    self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr_id);
+                let hygiene = self.body.expr_path_hygiene(expr_id);
+                let resolved =
+                    self.resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p, hygiene);
+                self.resolver.reset_to_guard(resolver_guard);
+                let Some(pr) = resolved else {
                     return try_rvalue(self);
                 };
                 match pr {
@@ -216,7 +221,7 @@ impl MirLowerCtx<'_> {
                 self.push_field_projection(&mut r, expr_id)?;
                 Ok(Some((r, current)))
             }
-            Expr::Index { base, index, is_assignee_expr: _ } => {
+            Expr::Index { base, index } => {
                 let base_ty = self.expr_ty_after_adjustments(*base);
                 let index_ty = self.expr_ty_after_adjustments(*index);
                 if index_ty != TyBuilder::usize()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
index b1c0d1f2b39..2ffea34c85a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,6 +1,6 @@
 //! MIR lowering for patterns
 
-use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
+use hir_def::{hir::LiteralOrConst, AssocItemId};
 
 use crate::{
     mir::{
@@ -46,6 +46,8 @@ enum MatchingMode {
     Check,
     /// Assume that this pattern matches, fill bindings
     Bind,
+    /// Assume that this pattern matches, assign to existing variables.
+    Assign,
 }
 
 impl MirLowerCtx<'_> {
@@ -82,6 +84,17 @@ impl MirLowerCtx<'_> {
         Ok((current, current_else))
     }
 
+    pub(super) fn pattern_match_assignment(
+        &mut self,
+        current: BasicBlockId,
+        value: Place,
+        pattern: PatId,
+    ) -> Result<BasicBlockId> {
+        let (current, _) =
+            self.pattern_match_inner(current, None, value, pattern, MatchingMode::Assign)?;
+        Ok(current)
+    }
+
     pub(super) fn match_self_param(
         &mut self,
         id: BindingId,
@@ -155,14 +168,8 @@ impl MirLowerCtx<'_> {
                         *pat,
                         MatchingMode::Check,
                     )?;
-                    if mode == MatchingMode::Bind {
-                        (next, _) = self.pattern_match_inner(
-                            next,
-                            None,
-                            cond_place,
-                            *pat,
-                            MatchingMode::Bind,
-                        )?;
+                    if mode != MatchingMode::Check {
+                        (next, _) = self.pattern_match_inner(next, None, cond_place, *pat, mode)?;
                     }
                     self.set_goto(next, then_target, pattern.into());
                     match next_else {
@@ -176,11 +183,11 @@ impl MirLowerCtx<'_> {
                     }
                 }
                 if !finished {
-                    if mode == MatchingMode::Bind {
-                        self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
-                    } else {
+                    if mode == MatchingMode::Check {
                         let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
                         self.set_goto(current, ce, pattern.into());
+                    } else {
+                        self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
                     }
                 }
                 (then_target, current_else)
@@ -300,7 +307,7 @@ impl MirLowerCtx<'_> {
                         self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
                 }
                 if let &Some(slice) = slice {
-                    if mode == MatchingMode::Bind {
+                    if mode != MatchingMode::Check {
                         if let Pat::Bind { id, subpat: _ } = self.body[slice] {
                             let next_place = cond_place.project(
                                 ProjectionElem::Subslice {
@@ -342,17 +349,36 @@ impl MirLowerCtx<'_> {
                     mode,
                 )?,
                 None => {
-                    // The path is not a variant, so it is a const
+                    let unresolved_name = || {
+                        MirLowerError::unresolved_path(self.db, p, self.edition(), &self.body.types)
+                    };
+                    let hygiene = self.body.pat_path_hygiene(pattern);
+                    let pr = self
+                        .resolver
+                        .resolve_path_in_value_ns(self.db.upcast(), p, hygiene)
+                        .ok_or_else(unresolved_name)?;
+
+                    if let (
+                        MatchingMode::Assign,
+                        ResolveValueResult::ValueNs(ValueNs::LocalBinding(binding), _),
+                    ) = (mode, &pr)
+                    {
+                        let local = self.binding_local(*binding)?;
+                        self.push_match_assignment(
+                            current,
+                            local,
+                            BindingMode::Move,
+                            cond_place,
+                            pattern.into(),
+                        );
+                        return Ok((current, current_else));
+                    }
+
+                    // The path is not a variant or a local, so it is a const
                     if mode != MatchingMode::Check {
                         // A const don't bind anything. Only needs check.
                         return Ok((current, current_else));
                     }
-                    let unresolved_name =
-                        || MirLowerError::unresolved_path(self.db, p, self.edition());
-                    let resolver = self.owner.resolver(self.db.upcast());
-                    let pr = resolver
-                        .resolve_path_in_value_ns(self.db.upcast(), p)
-                        .ok_or_else(unresolved_name)?;
                     let (c, subst) = 'b: {
                         if let Some(x) = self.infer.assoc_resolutions_for_pat(pattern) {
                             if let AssocItemId::ConstId(c) = x.0 {
@@ -415,7 +441,7 @@ impl MirLowerCtx<'_> {
                     (current, current_else) =
                         self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)?
                 }
-                if mode == MatchingMode::Bind {
+                if mode != MatchingMode::Check {
                     let mode = self.infer.binding_modes[pattern];
                     self.pattern_match_binding(
                         *id,
@@ -448,6 +474,23 @@ impl MirLowerCtx<'_> {
                     cond_place.project(ProjectionElem::Deref, &mut self.result.projection_store);
                 self.pattern_match_inner(current, current_else, cond_place, *pat, mode)?
             }
+            &Pat::Expr(expr) => {
+                stdx::always!(
+                    mode == MatchingMode::Assign,
+                    "Pat::Expr can only come in destructuring assignments"
+                );
+                let Some((lhs_place, current)) = self.lower_expr_as_place(current, expr, false)?
+                else {
+                    return Ok((current, current_else));
+                };
+                self.push_assignment(
+                    current,
+                    lhs_place,
+                    Operand::Copy(cond_place).into(),
+                    expr.into(),
+                );
+                (current, current_else)
+            }
             Pat::Box { .. } => not_supported!("box pattern"),
             Pat::ConstBlock(_) => not_supported!("const block pattern"),
         })
@@ -464,6 +507,18 @@ impl MirLowerCtx<'_> {
     ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
         let target_place = self.binding_local(id)?;
         self.push_storage_live(id, current)?;
+        self.push_match_assignment(current, target_place, mode, cond_place, span);
+        Ok((current, current_else))
+    }
+
+    fn push_match_assignment(
+        &mut self,
+        current: BasicBlockId,
+        target_place: LocalId,
+        mode: BindingMode,
+        cond_place: Place,
+        span: MirSpan,
+    ) {
         self.push_assignment(
             current,
             target_place.into(),
@@ -476,7 +531,6 @@ impl MirLowerCtx<'_> {
             },
             span,
         );
-        Ok((current, current_else))
     }
 
     fn pattern_match_const(
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 4c6bc376e2b..92132fa0473 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
@@ -258,6 +258,10 @@ impl Filler<'_> {
                         | Rvalue::UnaryOp(_, _)
                         | Rvalue::Discriminant(_)
                         | Rvalue::CopyForDeref(_) => (),
+                        Rvalue::ThreadLocalRef(n)
+                        | Rvalue::AddressOf(n)
+                        | Rvalue::BinaryOp(n)
+                        | Rvalue::NullaryOp(n) => match *n {},
                     },
                     StatementKind::Deinit(_)
                     | StatementKind::FakeRead(_)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index df56071aa9a..06765a104cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -459,6 +459,10 @@ impl<'a> MirPrettyCtx<'a> {
                 self.place(p);
                 w!(self, ")");
             }
+            Rvalue::ThreadLocalRef(n)
+            | Rvalue::AddressOf(n)
+            | Rvalue::BinaryOp(n)
+            | Rvalue::NullaryOp(n) => match *n {},
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index a8170b60606..5f0f341f393 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3418,11 +3418,11 @@ struct TS(usize);
 fn main() {
     let x;
     [x,] = &[1,];
-  //^^^^expected &'? [i32; 1], got [{unknown}; _]
+  //^^^^expected &'? [i32; 1], got [{unknown}]
 
     let x;
     [(x,),] = &[(1,),];
-  //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
+  //^^^^^^^expected &'? [(i32,); 1], got [{unknown}]
 
     let x;
     ((x,),) = &((1,),);
@@ -3720,3 +3720,85 @@ fn test() -> bool {
         "#]],
     );
 }
+
+#[test]
+fn macro_semitransparent_hygiene() {
+    check_types(
+        r#"
+macro_rules! m {
+    () => { let bar: i32; };
+}
+fn foo() {
+    let bar: bool;
+    m!();
+    bar;
+ // ^^^ bool
+}
+        "#,
+    );
+}
+
+#[test]
+fn macro_expansion_can_refer_variables_defined_before_macro_definition() {
+    check_types(
+        r#"
+fn foo() {
+    let v: i32 = 0;
+    macro_rules! m {
+        () => { v };
+    }
+    let v: bool = true;
+    m!();
+ // ^^^^ i32
+}
+        "#,
+    );
+}
+
+#[test]
+fn macro_rules_shadowing_works_with_hygiene() {
+    check_types(
+        r#"
+fn foo() {
+    let v: bool;
+    macro_rules! m { () => { v } }
+    m!();
+ // ^^^^ bool
+
+    let v: char;
+    macro_rules! m { () => { v } }
+    m!();
+ // ^^^^ char
+
+    {
+        let v: u8;
+        macro_rules! m { () => { v } }
+        m!();
+     // ^^^^ u8
+
+        let v: i8;
+        macro_rules! m { () => { v } }
+        m!();
+     // ^^^^ i8
+
+        let v: i16;
+        macro_rules! m { () => { v } }
+        m!();
+     // ^^^^ i16
+
+        {
+            let v: u32;
+            macro_rules! m { () => { v } }
+            m!();
+         // ^^^^ u32
+
+            let v: u64;
+            macro_rules! m { () => { v } }
+            m!();
+         // ^^^^ u64
+        }
+    }
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 620bba2d75c..0a436ff2b41 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -123,7 +123,7 @@ pub(super) struct ClauseElaborator<'a> {
     seen: FxHashSet<WhereClause>,
 }
 
-impl<'a> ClauseElaborator<'a> {
+impl ClauseElaborator<'_> {
     fn extend_deduped(&mut self, clauses: impl IntoIterator<Item = WhereClause>) {
         self.stack.extend(clauses.into_iter().filter(|c| self.seen.insert(c.clone())))
     }
@@ -163,10 +163,12 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
                 let is_trait = match target {
-                    WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
-                        TypeRef::Path(p) => p.is_self_type(),
-                        _ => false,
-                    },
+                    WherePredicateTypeTarget::TypeRef(type_ref) => {
+                        match &generic_params.types_map[*type_ref] {
+                            TypeRef::Path(p) => p.is_self_type(),
+                            _ => false,
+                        }
+                    }
                     WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
                         Some(*local_id) == trait_self
                     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/db.rs b/src/tools/rust-analyzer/crates/hir/src/db.rs
index cb5f5b06aef..22760c41aae 100644
--- a/src/tools/rust-analyzer/crates/hir/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/db.rs
@@ -4,35 +4,43 @@
 //!
 //! But we need this for at least LRU caching at the query level.
 pub use hir_def::db::{
-    AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BodyQuery, BodyWithSourceMapQuery,
-    ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery, CrateLangItemsQuery,
-    CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase, DefDatabaseStorage,
-    EnumDataQuery, EnumVariantDataWithDiagnosticsQuery, ExprScopesQuery, ExternCrateDeclDataQuery,
-    FieldVisibilitiesQuery, FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery,
-    FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery, ImplDataWithDiagnosticsQuery,
-    ImportMapQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery, InternDatabase,
-    InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery, InternExternCrateQuery,
-    InternFunctionQuery, InternImplQuery, InternInTypeConstQuery, InternMacro2Query,
-    InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery, InternStructQuery,
-    InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery, InternUnionQuery,
-    InternUseQuery, LangItemQuery, Macro2DataQuery, MacroRulesDataQuery, ProcMacroDataQuery,
-    StaticDataQuery, StructDataWithDiagnosticsQuery, TraitAliasDataQuery,
-    TraitDataWithDiagnosticsQuery, TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
+    AttrsQuery, BlockDefMapQuery, BlockItemTreeQuery, BlockItemTreeWithSourceMapQuery, BodyQuery,
+    BodyWithSourceMapQuery, ConstDataQuery, ConstVisibilityQuery, CrateDefMapQuery,
+    CrateLangItemsQuery, CrateNotableTraitsQuery, CrateSupportsNoStdQuery, DefDatabase,
+    DefDatabaseStorage, EnumDataQuery, EnumVariantDataWithDiagnosticsQuery,
+    ExpandProcAttrMacrosQuery, ExprScopesQuery, ExternCrateDeclDataQuery, FieldVisibilitiesQuery,
+    FieldsAttrsQuery, FieldsAttrsSourceMapQuery, FileItemTreeQuery, FileItemTreeWithSourceMapQuery,
+    FunctionDataQuery, FunctionVisibilityQuery, GenericParamsQuery,
+    GenericParamsWithSourceMapQuery, ImplDataWithDiagnosticsQuery, ImportMapQuery,
+    IncludeMacroInvocQuery, InternAnonymousConstQuery, InternBlockQuery, InternConstQuery,
+    InternDatabase, InternDatabaseStorage, InternEnumQuery, InternExternBlockQuery,
+    InternExternCrateQuery, InternFunctionQuery, InternImplQuery, InternInTypeConstQuery,
+    InternMacro2Query, InternMacroRulesQuery, InternProcMacroQuery, InternStaticQuery,
+    InternStructQuery, InternTraitAliasQuery, InternTraitQuery, InternTypeAliasQuery,
+    InternUnionQuery, InternUseQuery, LangItemQuery, Macro2DataQuery, MacroDefQuery,
+    MacroRulesDataQuery, NotableTraitsInDepsQuery, ProcMacroDataQuery, StaticDataQuery,
+    StructDataWithDiagnosticsQuery, TraitAliasDataQuery, TraitDataWithDiagnosticsQuery,
+    TypeAliasDataQuery, UnionDataWithDiagnosticsQuery,
 };
 pub use hir_expand::db::{
     AstIdMapQuery, DeclMacroExpanderQuery, ExpandDatabase, ExpandDatabaseStorage,
     ExpandProcMacroQuery, InternMacroCallQuery, InternSyntaxContextQuery, MacroArgQuery,
-    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacrosQuery, RealSpanMapQuery,
+    ParseMacroExpansionErrorQuery, ParseMacroExpansionQuery, ProcMacroSpanQuery, ProcMacrosQuery,
+    RealSpanMapQuery,
 };
 pub use hir_ty::db::{
     AdtDatumQuery, AdtVarianceQuery, AssociatedTyDataQuery, AssociatedTyValueQuery, BorrowckQuery,
     CallableItemSignatureQuery, ConstEvalDiscriminantQuery, ConstEvalQuery, ConstEvalStaticQuery,
-    ConstParamTyQuery, FieldTypesQuery, FnDefDatumQuery, FnDefVarianceQuery, GenericDefaultsQuery,
-    GenericPredicatesForParamQuery, GenericPredicatesQuery, HirDatabase, HirDatabaseStorage,
-    ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery,
+    ConstParamTyQuery, DynCompatibilityOfTraitQuery, FieldTypesQuery, FnDefDatumQuery,
+    FnDefVarianceQuery, GenericDefaultsQuery, GenericPredicatesForParamQuery,
+    GenericPredicatesQuery, GenericPredicatesWithoutParentQuery, HirDatabase, HirDatabaseStorage,
+    ImplDatumQuery, ImplSelfTyQuery, ImplTraitQuery, IncoherentInherentImplCratesQuery, InferQuery,
     InherentImplsInBlockQuery, InherentImplsInCrateQuery, InternCallableDefQuery,
     InternClosureQuery, InternCoroutineQuery, InternImplTraitIdQuery, InternLifetimeParamIdQuery,
-    InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, MirBodyQuery, ProgramClausesForChalkEnvQuery,
-    ReturnTypeImplTraitsQuery, TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery,
-    TraitImplsInBlockQuery, TraitImplsInCrateQuery, TraitImplsInDepsQuery, TyQuery, ValueTyQuery,
+    InternTypeOrConstParamIdQuery, LayoutOfAdtQuery, LayoutOfTyQuery, LookupImplMethodQuery,
+    MirBodyForClosureQuery, MirBodyQuery, MonomorphizedMirBodyForClosureQuery,
+    MonomorphizedMirBodyQuery, ProgramClausesForChalkEnvQuery, ReturnTypeImplTraitsQuery,
+    TargetDataLayoutQuery, TraitDatumQuery, TraitEnvironmentQuery, TraitImplsInBlockQuery,
+    TraitImplsInCrateQuery, TraitImplsInDepsQuery, TraitSolveQuery, TyQuery,
+    TypeAliasImplTraitsQuery, ValueTyQuery,
 };
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 0b3cdb2f379..8297acde857 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -165,6 +165,7 @@ pub struct MacroError {
     pub precise_location: Option<TextRange>,
     pub message: String,
     pub error: bool,
+    pub kind: &'static str,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -246,7 +247,7 @@ pub struct UnresolvedAssocItem {
 
 #[derive(Debug)]
 pub struct UnresolvedIdent {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
 }
 
 #[derive(Debug)]
@@ -257,7 +258,7 @@ pub struct PrivateField {
 
 #[derive(Debug)]
 pub struct MissingUnsafe {
-    pub expr: InFile<AstPtr<ast::Expr>>,
+    pub expr: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
     /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error.
     pub only_lint: bool,
 }
@@ -398,56 +399,46 @@ impl AnyDiagnostic {
                     .map(|idx| variant_data.fields()[idx].name.clone())
                     .collect();
 
-                match record {
-                    Either::Left(record_expr) => match source_map.expr_syntax(record_expr) {
-                        Ok(source_ptr) => {
-                            let root = source_ptr.file_syntax(db.upcast());
-                            if let ast::Expr::RecordExpr(record_expr) =
-                                source_ptr.value.to_node(&root)
-                            {
-                                if record_expr.record_expr_field_list().is_some() {
-                                    let field_list_parent_path =
-                                        record_expr.path().map(|path| AstPtr::new(&path));
-                                    return Some(
-                                        MissingFields {
-                                            file: source_ptr.file_id,
-                                            field_list_parent: AstPtr::new(&Either::Left(
-                                                record_expr,
-                                            )),
-                                            field_list_parent_path,
-                                            missed_fields,
-                                        }
-                                        .into(),
-                                    );
+                let record = match record {
+                    Either::Left(record_expr) => {
+                        source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left)
+                    }
+                    Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
+                };
+                let file = record.file_id;
+                let root = record.file_syntax(db.upcast());
+                match record.value.to_node(&root) {
+                    Either::Left(ast::Expr::RecordExpr(record_expr)) => {
+                        if record_expr.record_expr_field_list().is_some() {
+                            let field_list_parent_path =
+                                record_expr.path().map(|path| AstPtr::new(&path));
+                            return Some(
+                                MissingFields {
+                                    file,
+                                    field_list_parent: AstPtr::new(&Either::Left(record_expr)),
+                                    field_list_parent_path,
+                                    missed_fields,
                                 }
-                            }
+                                .into(),
+                            );
                         }
-                        Err(SyntheticSyntax) => (),
-                    },
-                    Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
-                        Ok(source_ptr) => {
-                            if let Some(ptr) = source_ptr.value.cast::<ast::RecordPat>() {
-                                let root = source_ptr.file_syntax(db.upcast());
-                                let record_pat = ptr.to_node(&root);
-                                if record_pat.record_pat_field_list().is_some() {
-                                    let field_list_parent_path =
-                                        record_pat.path().map(|path| AstPtr::new(&path));
-                                    return Some(
-                                        MissingFields {
-                                            file: source_ptr.file_id,
-                                            field_list_parent: AstPtr::new(&Either::Right(
-                                                record_pat,
-                                            )),
-                                            field_list_parent_path,
-                                            missed_fields,
-                                        }
-                                        .into(),
-                                    );
+                    }
+                    Either::Right(ast::Pat::RecordPat(record_pat)) => {
+                        if record_pat.record_pat_field_list().is_some() {
+                            let field_list_parent_path =
+                                record_pat.path().map(|path| AstPtr::new(&path));
+                            return Some(
+                                MissingFields {
+                                    file,
+                                    field_list_parent: AstPtr::new(&Either::Right(record_pat)),
+                                    field_list_parent_path,
+                                    missed_fields,
                                 }
-                            }
+                                .into(),
+                            );
                         }
-                        Err(SyntheticSyntax) => (),
-                    },
+                    }
+                    _ => {}
                 }
             }
             BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => {
@@ -541,15 +532,17 @@ impl AnyDiagnostic {
         let pat_syntax = |pat| {
             source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
         };
+        let expr_or_pat_syntax = |id| match id {
+            ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
+            ExprOrPatId::PatId(pat) => pat_syntax(pat),
+        };
         Some(match d {
             &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
                 let expr_or_pat = match expr {
                     ExprOrPatId::ExprId(expr) => {
                         source_map.field_syntax(expr).map(AstPtr::wrap_left)
                     }
-                    ExprOrPatId::PatId(pat) => {
-                        source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
-                    }
+                    ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
                 };
                 NoSuchField { field: expr_or_pat, private, variant }.into()
             }
@@ -562,10 +555,7 @@ impl AnyDiagnostic {
                 PrivateField { expr, field }.into()
             }
             &InferenceDiagnostic::PrivateAssocItem { id, item } => {
-                let expr_or_pat = match id {
-                    ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
-                    ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
-                };
+                let expr_or_pat = expr_or_pat_syntax(id)?;
                 let item = item.into();
                 PrivateAssocItem { expr_or_pat, item }.into()
             }
@@ -609,15 +599,12 @@ impl AnyDiagnostic {
                 .into()
             }
             &InferenceDiagnostic::UnresolvedAssocItem { id } => {
-                let expr_or_pat = match id {
-                    ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
-                    ExprOrPatId::PatId(pat) => pat_syntax(pat)?.map(AstPtr::wrap_right),
-                };
+                let expr_or_pat = expr_or_pat_syntax(id)?;
                 UnresolvedAssocItem { expr_or_pat }.into()
             }
-            &InferenceDiagnostic::UnresolvedIdent { expr } => {
-                let expr = expr_syntax(expr)?;
-                UnresolvedIdent { expr }.into()
+            &InferenceDiagnostic::UnresolvedIdent { id } => {
+                let expr_or_pat = expr_or_pat_syntax(id)?;
+                UnresolvedIdent { expr_or_pat }.into()
             }
             &InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
                 let expr = expr_syntax(expr)?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index c2b2fbef751..9275f45d881 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -12,12 +12,11 @@ use hir_def::{
 };
 use hir_ty::{
     display::{
-        write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
-        HirFormatter, SizedByDefault,
+        hir_display_with_types_map, write_bounds_like_dyn_trait_with_prefix, write_visibility,
+        HirDisplay, HirDisplayError, HirDisplayWithTypesMap, HirFormatter, SizedByDefault,
     },
     AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
 };
-use intern::Interned;
 use itertools::Itertools;
 
 use crate::{
@@ -113,7 +112,7 @@ impl HirDisplay for Function {
             f.write_str(&pat_str)?;
 
             f.write_str(": ")?;
-            type_ref.hir_fmt(f)?;
+            type_ref.hir_fmt(f, &data.types_map)?;
         }
 
         if data.is_varargs() {
@@ -129,28 +128,30 @@ impl HirDisplay for Function {
         // Use ugly pattern match to strip the Future trait.
         // Better way?
         let ret_type = if !data.is_async() {
-            &data.ret_type
+            Some(data.ret_type)
         } else {
-            match &*data.ret_type {
-                TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
-                    TypeBound::Path(path, _) => {
-                        path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
+            match &data.types_map[data.ret_type] {
+                TypeRef::ImplTrait(bounds) => match &bounds[0] {
+                    TypeBound::Path(path, _) => Some(
+                        *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
                             [0]
                         .type_ref
                         .as_ref()
-                        .unwrap()
-                    }
-                    _ => &TypeRef::Error,
+                        .unwrap(),
+                    ),
+                    _ => None,
                 },
-                _ => &TypeRef::Error,
+                _ => None,
             }
         };
 
-        match ret_type {
-            TypeRef::Tuple(tup) if tup.is_empty() => {}
-            ty => {
-                f.write_str(" -> ")?;
-                ty.hir_fmt(f)?;
+        if let Some(ret_type) = ret_type {
+            match &data.types_map[ret_type] {
+                TypeRef::Tuple(tup) if tup.is_empty() => {}
+                _ => {
+                    f.write_str(" -> ")?;
+                    ret_type.hir_fmt(f, &data.types_map)?;
+                }
             }
         }
 
@@ -192,23 +193,23 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi
 impl HirDisplay for SelfParam {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         let data = f.db.function_data(self.func);
-        let param = data.params.first().unwrap();
-        match &**param {
+        let param = *data.params.first().unwrap();
+        match &data.types_map[param] {
             TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
-            TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
+            TypeRef::Reference(ref_) if matches!(&data.types_map[ref_.ty], TypeRef::Path(p) if p.is_self_type()) =>
             {
                 f.write_char('&')?;
-                if let Some(lifetime) = lifetime {
+                if let Some(lifetime) = &ref_.lifetime {
                     write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?;
                 }
-                if let hir_def::type_ref::Mutability::Mut = mut_ {
+                if let hir_def::type_ref::Mutability::Mut = ref_.mutability {
                     f.write_str("mut ")?;
                 }
                 f.write_str("self")
             }
-            ty => {
+            _ => {
                 f.write_str("self: ")?;
-                ty.hir_fmt(f)
+                param.hir_fmt(f, &data.types_map)
             }
         }
     }
@@ -393,7 +394,7 @@ impl HirDisplay for Variant {
         let data = self.variant_data(f.db);
         match &*data {
             VariantData::Unit => {}
-            VariantData::Tuple(fields) => {
+            VariantData::Tuple { fields, types_map } => {
                 f.write_char('(')?;
                 let mut first = true;
                 for (_, field) in fields.iter() {
@@ -403,11 +404,11 @@ impl HirDisplay for Variant {
                         f.write_str(", ")?;
                     }
                     // Enum variant fields must be pub.
-                    field.type_ref.hir_fmt(f)?;
+                    field.type_ref.hir_fmt(f, types_map)?;
                 }
                 f.write_char(')')?;
             }
-            VariantData::Record(_) => {
+            VariantData::Record { .. } => {
                 if let Some(limit) = f.entity_limit {
                     write_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
@@ -579,13 +580,13 @@ fn write_generic_params(
                     write!(f, "{}", name.display(f.db.upcast(), f.edition()))?;
                     if let Some(default) = &ty.default {
                         f.write_str(" = ")?;
-                        default.hir_fmt(f)?;
+                        default.hir_fmt(f, &params.types_map)?;
                     }
                 }
                 TypeOrConstParamData::ConstParamData(c) => {
                     delim(f)?;
                     write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?;
-                    c.ty.hir_fmt(f)?;
+                    c.ty.hir_fmt(f, &params.types_map)?;
 
                     if let Some(default) = &c.default {
                         f.write_str(" = ")?;
@@ -615,7 +616,7 @@ fn write_where_clause(
     Ok(true)
 }
 
-fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
+fn has_disaplayable_predicates(params: &GenericParams) -> bool {
     params.where_predicates().any(|pred| {
         !matches!(
             pred,
@@ -626,21 +627,20 @@ fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
 }
 
 fn write_where_predicates(
-    params: &Interned<GenericParams>,
+    params: &GenericParams,
     f: &mut HirFormatter<'_>,
 ) -> Result<(), HirDisplayError> {
     use WherePredicate::*;
 
     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
-    let is_unnamed_type_target =
-        |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
-            matches!(target,
-                WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
-            )
-        };
+    let is_unnamed_type_target = |params: &GenericParams, target: &WherePredicateTypeTarget| {
+        matches!(target,
+            WherePredicateTypeTarget::TypeOrConstParam(id) if params[*id].name().is_none()
+        )
+    };
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
-        WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
+        WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f, &params.types_map),
         WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() {
             Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())),
             None => f.write_str("{unnamed}"),
@@ -668,7 +668,7 @@ fn write_where_predicates(
             TypeBound { target, bound } => {
                 write_target(target, f)?;
                 f.write_str(": ")?;
-                bound.hir_fmt(f)?;
+                bound.hir_fmt(f, &params.types_map)?;
             }
             Lifetime { target, bound } => {
                 let target = target.name.display(f.db.upcast(), f.edition());
@@ -681,14 +681,16 @@ fn write_where_predicates(
                 write!(f, "for<{lifetimes}> ")?;
                 write_target(target, f)?;
                 f.write_str(": ")?;
-                bound.hir_fmt(f)?;
+                bound.hir_fmt(f, &params.types_map)?;
             }
         }
 
         while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
             f.write_str(" + ")?;
             match nxt {
-                TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
+                TypeBound { bound, .. } | ForLifetime { bound, .. } => {
+                    bound.hir_fmt(f, &params.types_map)?
+                }
                 Lifetime { bound, .. } => {
                     write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))?
                 }
@@ -716,7 +718,7 @@ impl HirDisplay for Const {
             Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?,
             None => f.write_str("_: ")?,
         }
-        data.type_ref.hir_fmt(f)?;
+        data.type_ref.hir_fmt(f, &data.types_map)?;
         Ok(())
     }
 }
@@ -730,7 +732,7 @@ impl HirDisplay for Static {
             f.write_str("mut ")?;
         }
         write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?;
-        data.type_ref.hir_fmt(f)?;
+        data.type_ref.hir_fmt(f, &data.types_map)?;
         Ok(())
     }
 }
@@ -813,11 +815,14 @@ impl HirDisplay for TypeAlias {
         write_generic_params(def_id, f)?;
         if !data.bounds.is_empty() {
             f.write_str(": ")?;
-            f.write_joined(data.bounds.iter(), " + ")?;
+            f.write_joined(
+                data.bounds.iter().map(|bound| hir_display_with_types_map(bound, &data.types_map)),
+                " + ",
+            )?;
         }
-        if let Some(ty) = &data.type_ref {
+        if let Some(ty) = data.type_ref {
             f.write_str(" = ")?;
-            ty.hir_fmt(f)?;
+            ty.hir_fmt(f, &data.types_map)?;
         }
         write_where_clause(def_id, f)?;
         Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 30e023e1a47..88eb3b127e0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -58,7 +58,8 @@ use hir_def::{
     TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{
-    attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
+    attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError,
+    ValueResult,
 };
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
@@ -838,7 +839,7 @@ fn macro_call_diagnostics(
         let file_id = loc.kind.file_id();
         let node =
             InFile::new(file_id, db.ast_id_map(file_id).get_erased(loc.kind.erased_ast_id()));
-        let (message, error) = err.render_to_string(db.upcast());
+        let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
         let precise_location = if err.span().anchor.file_id == file_id {
             Some(
                 err.span().range
@@ -850,7 +851,7 @@ fn macro_call_diagnostics(
         } else {
             None
         };
-        acc.push(MacroError { node, precise_location, message, error }.into());
+        acc.push(MacroError { node, precise_location, message, error, kind }.into());
     }
 
     if !parse_errors.is_empty() {
@@ -916,13 +917,14 @@ fn emit_def_diagnostic_(
 
         DefDiagnosticKind::MacroError { ast, path, err } => {
             let item = ast.to_ptr(db.upcast());
-            let (message, error) = err.render_to_string(db.upcast());
+            let RenderedExpandError { message, error, kind } = err.render_to_string(db.upcast());
             acc.push(
                 MacroError {
                     node: InFile::new(ast.file_id, item.syntax_node_ptr()),
                     precise_location: None,
                     message: format!("{}: {message}", path.display(db.upcast(), edition)),
                     error,
+                    kind,
                 }
                 .into(),
             )
@@ -1811,7 +1813,8 @@ impl DefWithBody {
                     InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
                 }
                 BodyDiagnostic::MacroError { node, err } => {
-                    let (message, error) = err.render_to_string(db.upcast());
+                    let RenderedExpandError { message, error, kind } =
+                        err.render_to_string(db.upcast());
 
                     let precise_location = if err.span().anchor.file_id == node.file_id {
                         Some(
@@ -1829,6 +1832,7 @@ impl DefWithBody {
                         precise_location,
                         message,
                         error,
+                        kind,
                     }
                     .into()
                 }
@@ -1885,7 +1889,7 @@ impl DefWithBody {
 
         let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into());
         for expr in unafe_exprs {
-            match source_map.expr_syntax(expr) {
+            match source_map.expr_or_pat_syntax(expr) {
                 Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()),
                 Err(SyntheticSyntax) => {
                     // FIXME: Here and elsewhere in this file, the `expr` was
@@ -2420,8 +2424,8 @@ impl SelfParam {
         func_data
             .params
             .first()
-            .map(|param| match &**param {
-                TypeRef::Reference(.., mutability) => match mutability {
+            .map(|&param| match &func_data.types_map[param] {
+                TypeRef::Reference(ref_) => match ref_.mutability {
                     hir_def::type_ref::Mutability::Shared => Access::Shared,
                     hir_def::type_ref::Mutability::Mut => Access::Exclusive,
                 },
@@ -2747,10 +2751,6 @@ impl TypeAlias {
         Module { id: self.id.module(db.upcast()) }
     }
 
-    pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
-        db.type_alias_data(self.id).type_ref.as_deref().cloned()
-    }
-
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         Type::from_def(db, self.id)
     }
@@ -3481,7 +3481,7 @@ impl Local {
                     LocalSource {
                         local: self,
                         source: src.map(|ast| match ast.to_node(&root) {
-                            ast::Pat::IdentPat(it) => Either::Left(it),
+                            Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
                             _ => unreachable!("local with non ident-pattern"),
                         }),
                     }
@@ -3510,7 +3510,7 @@ impl Local {
                     LocalSource {
                         local: self,
                         source: src.map(|ast| match ast.to_node(&root) {
-                            ast::Pat::IdentPat(it) => Either::Left(it),
+                            Either::Right(ast::Pat::IdentPat(it)) => Either::Left(it),
                             _ => unreachable!("local with non ident-pattern"),
                         }),
                     }
@@ -4235,10 +4235,7 @@ impl CaptureUsages {
                 }
                 mir::MirSpan::PatId(pat) => {
                     if let Ok(pat) = source_map.pat_syntax(pat) {
-                        result.push(CaptureUsageSource {
-                            is_ref,
-                            source: pat.map(AstPtr::wrap_right),
-                        });
+                        result.push(CaptureUsageSource { is_ref, source: pat });
                     }
                 }
                 mir::MirSpan::BindingId(binding) => result.extend(
@@ -4246,10 +4243,7 @@ impl CaptureUsages {
                         .patterns_for_binding(binding)
                         .iter()
                         .filter_map(|&pat| source_map.pat_syntax(pat).ok())
-                        .map(|pat| CaptureUsageSource {
-                            is_ref,
-                            source: pat.map(AstPtr::wrap_right),
-                        }),
+                        .map(|pat| CaptureUsageSource { is_ref, source: pat }),
                 ),
                 mir::MirSpan::SelfParam | mir::MirSpan::Unknown => {
                     unreachable!("invalid capture usage span")
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 3eac33ce990..feb9a344d8a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -11,13 +11,13 @@ use std::{
 
 use either::Either;
 use hir_def::{
-    hir::Expr,
+    hir::{Expr, ExprOrPatId},
     lower::LowerCtx,
     nameres::{MacroSubNs, ModuleOrigin},
     path::ModPath,
     resolver::{self, HasResolver, Resolver, TypeNs},
-    type_ref::Mutability,
-    AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId,
+    type_ref::{Mutability, TypesMap, TypesSourceMap},
+    AsMacroCall, DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
 };
 use hir_expand::{
     attrs::collect_attrs,
@@ -45,7 +45,7 @@ use syntax::{
 use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
-    source_analyzer::{resolve_hir_path, SourceAnalyzer},
+    source_analyzer::{name_hygiene, resolve_hir_path, SourceAnalyzer},
     Access, Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
     ConstParam, Crate, DeriveHelper, Enum, Field, Function, HasSource, HirFileId, Impl, InFile,
     InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name,
@@ -154,7 +154,7 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
     }
 }
 
-impl<'db, DB: HirDatabase> Semantics<'db, DB> {
+impl<DB: HirDatabase> Semantics<'_, DB> {
     pub fn new(db: &DB) -> Semantics<'_, DB> {
         let impl_ = SemanticsImpl::new(db);
         Semantics { db, imp: impl_ }
@@ -203,6 +203,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
     }
 
+    pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
+        self.imp.resolve_range_pat(range_pat).map(Struct::from)
+    }
+
+    pub fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<Struct> {
+        self.imp.resolve_range_expr(range_expr).map(Struct::from)
+    }
+
     pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
         self.imp.resolve_await_to_poll(await_expr).map(Function::from)
     }
@@ -928,16 +936,7 @@ impl<'db> SemanticsImpl<'db> {
             }
         }
 
-        let (file_id, tokens) = stack.first()?;
-        // make sure we pick the token in the expanded include if we encountered an include,
-        // otherwise we'll get the wrong semantics
-        let sa =
-            tokens.first()?.0.parent().and_then(|parent| {
-                self.analyze_impl(InFile::new(*file_id, &parent), None, false)
-            })?;
-
         let mut m_cache = self.macro_call_cache.borrow_mut();
-        let def_map = sa.resolver.def_map();
 
         // Filters out all tokens that contain the given range (usually the macro call), any such
         // token is redundant as the corresponding macro call has already been processed
@@ -946,6 +945,10 @@ impl<'db> SemanticsImpl<'db> {
         };
 
         while let Some((expansion, ref mut tokens)) = stack.pop() {
+            // Reverse the tokens so we prefer first tokens (to accommodate for popping from the
+            // back)
+            // alternatively we could pop from the front but that would shift the content on every pop
+            tokens.reverse();
             while let Some((token, ctx)) = tokens.pop() {
                 let was_not_remapped = (|| {
                     // First expand into attribute invocations
@@ -1016,8 +1019,16 @@ impl<'db> SemanticsImpl<'db> {
                                         ) {
                                         call.as_macro_file()
                                     } else {
-                                        // FIXME: This is wrong, the SourceAnalyzer might be invalid here
-                                        sa.expand(self.db, mcall.as_ref())?
+                                        token
+                                            .parent()
+                                            .and_then(|parent| {
+                                                self.analyze_impl(
+                                                    InFile::new(expansion, &parent),
+                                                    None,
+                                                    false,
+                                                )
+                                            })?
+                                            .expand(self.db, mcall.as_ref())?
                                     };
                                     m_cache.insert(mcall, it);
                                     it
@@ -1087,9 +1098,16 @@ impl<'db> SemanticsImpl<'db> {
                                 attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
                             // Not an attribute, nor a derive, so it's either an intert attribute or a derive helper
                             // Try to resolve to a derive helper and downmap
+                            let resolver = &token
+                                .parent()
+                                .and_then(|parent| {
+                                    self.analyze_impl(InFile::new(expansion, &parent), None, false)
+                                })?
+                                .resolver;
                             let id = self.db.ast_id_map(expansion).ast_id(&adt);
-                            let helpers =
-                                def_map.derive_helpers_in_scope(InFile::new(expansion, id))?;
+                            let helpers = resolver
+                                .def_map()
+                                .derive_helpers_in_scope(InFile::new(expansion, id))?;
 
                             if !helpers.is_empty() {
                                 let text_range = attr.syntax().text_range();
@@ -1251,19 +1269,28 @@ impl<'db> SemanticsImpl<'db> {
 
     pub fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
         let analyze = self.analyze(ty.syntax())?;
-        let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
+        let type_ref = crate::TypeRef::from_ast(&ctx, ty.clone());
         let ty = hir_ty::TyLoweringContext::new_maybe_unowned(
             self.db,
             &analyze.resolver,
+            &types_map,
+            None,
             analyze.resolver.type_owner(),
         )
-        .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
+        .lower_ty(type_ref);
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
     pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
         let analyze = self.analyze(path.syntax())?;
-        let ctx = LowerCtx::new(self.db.upcast(), analyze.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), analyze.file_id, &mut types_map, &mut types_source_map);
         let hir_path = Path::from_src(&ctx, path.clone())?;
         match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
             TypeNs::TraitId(id) => Some(Trait { id }),
@@ -1363,6 +1390,14 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
+    fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
+        self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat)
+    }
+
+    fn resolve_range_expr(&self, range_expr: &ast::RangeExpr) -> Option<StructId> {
+        self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
+    }
+
     fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
         self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
     }
@@ -1761,7 +1796,9 @@ impl<'db> SemanticsImpl<'db> {
             }
 
             if let Some(parent) = ast::Expr::cast(parent.clone()) {
-                if let Some(expr_id) = source_map.node_expr(InFile { file_id, value: &parent }) {
+                if let Some(ExprOrPatId::ExprId(expr_id)) =
+                    source_map.node_expr(InFile { file_id, value: &parent })
+                {
                     if let Expr::Unsafe { .. } = body[expr_id] {
                         break true;
                     }
@@ -1934,10 +1971,19 @@ impl SemanticsScope<'_> {
 
     /// Resolve a path as-if it was written at the given scope. This is
     /// necessary a heuristic, as it doesn't take hygiene into account.
-    pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
-        let ctx = LowerCtx::new(self.db.upcast(), self.file_id);
-        let path = Path::from_src(&ctx, path.clone())?;
-        resolve_hir_path(self.db, &self.resolver, &path)
+    pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
+        let path = Path::from_src(&ctx, ast_path.clone())?;
+        resolve_hir_path(
+            self.db,
+            &self.resolver,
+            &path,
+            name_hygiene(self.db, InFile::new(self.file_id, ast_path.syntax())),
+            &types_map,
+        )
     }
 
     /// Iterates over associated types that may be specified after the given path (using
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 389778b44ed..5357e824d09 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -328,7 +328,7 @@ impl SourceToDefCtx<'_, '_> {
             .position(|it| it == *src.value)?;
         let container = self.find_pat_or_label_container(src.syntax_ref())?;
         let (_, source_map) = self.db.body_with_source_map(container);
-        let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?;
+        let expr = source_map.node_expr(src.with_value(&ast::Expr::AsmExpr(asm)))?.as_expr()?;
         Some(InlineAsmOperand { owner: container, expr, index })
     }
 
@@ -372,7 +372,8 @@ impl SourceToDefCtx<'_, '_> {
         let break_or_continue = ast::Expr::cast(src.value.syntax().parent()?)?;
         let container = self.find_pat_or_label_container(src.syntax_ref())?;
         let (body, source_map) = self.db.body_with_source_map(container);
-        let break_or_continue = source_map.node_expr(src.with_value(&break_or_continue))?;
+        let break_or_continue =
+            source_map.node_expr(src.with_value(&break_or_continue))?.as_expr()?;
         let (Expr::Break { label, .. } | Expr::Continue { label }) = body[break_or_continue] else {
             return None;
         };
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 3da67ae23f8..8d6e228e14c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -7,21 +7,26 @@
 //! purely for "IDE needs".
 use std::iter::{self, once};
 
+use crate::{
+    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
+    BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
+    Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
+};
 use either::Either;
 use hir_def::{
     body::{
         scope::{ExprScopes, ScopeId},
-        Body, BodySourceMap,
+        Body, BodySourceMap, HygieneId,
     },
-    hir::{BindingId, ExprId, Pat, PatId},
+    hir::{BindingId, ExprId, ExprOrPatId, Pat, PatId},
     lang_item::LangItem,
     lower::LowerCtx,
     nameres::MacroSubNs,
     path::{ModPath, Path, PathKind},
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
-    type_ref::Mutability,
+    type_ref::{Mutability, TypesMap, TypesSourceMap},
     AsMacroCall, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, ItemContainerId,
-    LocalFieldId, Lookup, ModuleDefId, TraitId, VariantId,
+    LocalFieldId, Lookup, ModuleDefId, StructId, TraitId, VariantId,
 };
 use hir_expand::{
     mod_path::path,
@@ -40,18 +45,13 @@ use hir_ty::{
 use intern::sym;
 use itertools::Itertools;
 use smallvec::SmallVec;
+use syntax::ast::{RangeItem, RangeOp};
 use syntax::{
     ast::{self, AstNode},
     SyntaxKind, SyntaxNode, TextRange, TextSize,
 };
 use triomphe::Arc;
 
-use crate::{
-    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
-    BuiltinType, Callable, Const, DeriveHelper, Field, Function, Local, Macro, ModuleDef, Static,
-    Struct, ToolModule, Trait, TraitAlias, TupleField, Type, TypeAlias, Variant,
-};
-
 /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
 /// original source files. It should not be used inside the HIR itself.
 #[derive(Debug)]
@@ -120,7 +120,7 @@ impl SourceAnalyzer {
         self.def.as_ref().map(|(_, body, _)| &**body)
     }
 
-    fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
+    fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprOrPatId> {
         let src = match expr {
             ast::Expr::MacroExpr(expr) => {
                 self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
@@ -174,7 +174,9 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         expr: &ast::Expr,
     ) -> Option<&[Adjustment]> {
-        let expr_id = self.expr_id(db, expr)?;
+        // It is safe to omit destructuring assignments here because they have no adjustments (neither
+        // expressions nor patterns).
+        let expr_id = self.expr_id(db, expr)?.as_expr()?;
         let infer = self.infer.as_ref()?;
         infer.expr_adjustments.get(&expr_id).map(|v| &**v)
     }
@@ -186,9 +188,9 @@ impl SourceAnalyzer {
     ) -> Option<(Type, Option<Type>)> {
         let expr_id = self.expr_id(db, expr)?;
         let infer = self.infer.as_ref()?;
-        let coerced = infer
-            .expr_adjustments
-            .get(&expr_id)
+        let coerced = expr_id
+            .as_expr()
+            .and_then(|expr_id| infer.expr_adjustments.get(&expr_id))
             .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
         let ty = infer[expr_id].clone();
         let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
@@ -268,7 +270,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<Callable> {
-        let expr_id = self.expr_id(db, &call.clone().into())?;
+        let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
         let (func, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
         let ty = db.value_ty(func.into())?.substitute(Interner, &substs);
         let ty = Type::new_with_resolver(db, &self.resolver, ty);
@@ -282,7 +284,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<Function> {
-        let expr_id = self.expr_id(db, &call.clone().into())?;
+        let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
         let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
 
         Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
@@ -293,7 +295,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         call: &ast::MethodCallExpr,
     ) -> Option<Either<Function, Field>> {
-        let expr_id = self.expr_id(db, &call.clone().into())?;
+        let expr_id = self.expr_id(db, &call.clone().into())?.as_expr()?;
         let inference_result = self.infer.as_ref()?;
         match inference_result.method_resolution(expr_id) {
             Some((f_in_trait, substs)) => Some(Either::Left(
@@ -322,7 +324,7 @@ impl SourceAnalyzer {
         field: &ast::FieldExpr,
     ) -> Option<Either<Field, TupleField>> {
         let &(def, ..) = self.def.as_ref()?;
-        let expr_id = self.expr_id(db, &field.clone().into())?;
+        let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
         self.infer.as_ref()?.field_resolution(expr_id).map(|it| {
             it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index })
         })
@@ -334,7 +336,7 @@ impl SourceAnalyzer {
         field: &ast::FieldExpr,
     ) -> Option<Either<Either<Field, TupleField>, Function>> {
         let &(def, ..) = self.def.as_ref()?;
-        let expr_id = self.expr_id(db, &field.clone().into())?;
+        let expr_id = self.expr_id(db, &field.clone().into())?.as_expr()?;
         let inference_result = self.infer.as_ref()?;
         match inference_result.field_resolution(expr_id) {
             Some(field) => Some(Either::Left(field.map_either(Into::into, |f| TupleField {
@@ -348,6 +350,45 @@ impl SourceAnalyzer {
         }
     }
 
+    pub(crate) fn resolve_range_pat(
+        &self,
+        db: &dyn HirDatabase,
+        range_pat: &ast::RangePat,
+    ) -> Option<StructId> {
+        let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
+            (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
+            (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
+            (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
+            (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
+            (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+
+            (RangeOp::Exclusive, None, None) => return None,
+            (RangeOp::Inclusive, None, None) => return None,
+            (RangeOp::Inclusive, Some(_), None) => return None,
+        };
+        self.resolver.resolve_known_struct(db.upcast(), &path)
+    }
+
+    pub(crate) fn resolve_range_expr(
+        &self,
+        db: &dyn HirDatabase,
+        range_expr: &ast::RangeExpr,
+    ) -> Option<StructId> {
+        let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
+            (RangeOp::Exclusive, None, None) => path![core::ops::RangeFull],
+            (RangeOp::Exclusive, None, Some(_)) => path![core::ops::RangeTo],
+            (RangeOp::Exclusive, Some(_), None) => path![core::ops::RangeFrom],
+            (RangeOp::Exclusive, Some(_), Some(_)) => path![core::ops::Range],
+            (RangeOp::Inclusive, None, Some(_)) => path![core::ops::RangeToInclusive],
+            (RangeOp::Inclusive, Some(_), Some(_)) => path![core::ops::RangeInclusive],
+
+            // [E0586] inclusive ranges must be bounded at the end
+            (RangeOp::Inclusive, None, None) => return None,
+            (RangeOp::Inclusive, Some(_), None) => return None,
+        };
+        self.resolver.resolve_known_struct(db.upcast(), &path)
+    }
+
     pub(crate) fn resolve_await_to_poll(
         &self,
         db: &dyn HirDatabase,
@@ -403,7 +444,7 @@ impl SourceAnalyzer {
                 self.infer
                     .as_ref()
                     .and_then(|infer| {
-                        let expr = self.expr_id(db, &prefix_expr.clone().into())?;
+                        let expr = self.expr_id(db, &prefix_expr.clone().into())?.as_expr()?;
                         let (func, _) = infer.method_resolution(expr)?;
                         let (deref_mut_trait, deref_mut) = self.lang_trait_fn(
                             db,
@@ -449,7 +490,7 @@ impl SourceAnalyzer {
             .infer
             .as_ref()
             .and_then(|infer| {
-                let expr = self.expr_id(db, &index_expr.clone().into())?;
+                let expr = self.expr_id(db, &index_expr.clone().into())?.as_expr()?;
                 let (func, _) = infer.method_resolution(expr)?;
                 let (index_mut_trait, index_mut_fn) = self.lang_trait_fn(
                     db,
@@ -521,7 +562,8 @@ impl SourceAnalyzer {
         let expr = ast::Expr::from(record_expr);
         let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
 
-        let local_name = field.field_name()?.as_name();
+        let ast_name = field.field_name()?;
+        let local_name = ast_name.as_name();
         let local = if field.name_ref().is_some() {
             None
         } else {
@@ -530,15 +572,19 @@ impl SourceAnalyzer {
                 PathKind::Plain,
                 once(local_name.clone()),
             ));
-            match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
+            match self.resolver.resolve_path_in_value_ns_fully(
+                db.upcast(),
+                &path,
+                name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())),
+            ) {
                 Some(ValueNs::LocalBinding(binding_id)) => {
                     Some(Local { binding_id, parent: self.resolver.body_owner()? })
                 }
                 _ => None,
             }
         };
-        let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
-        let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
+        let (_, subst) = self.infer.as_ref()?.type_of_expr_or_pat(expr_id)?.as_adt()?;
+        let variant = self.infer.as_ref()?.variant_resolution_for_expr_or_pat(expr_id)?;
         let variant_data = variant.variant_data(db.upcast());
         let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
         let field_ty =
@@ -568,7 +614,10 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<Macro> {
-        let ctx = LowerCtx::new(db.upcast(), macro_call.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx =
+            LowerCtx::new(db.upcast(), macro_call.file_id, &mut types_map, &mut types_source_map);
         let path = macro_call.value.path().and_then(|ast| Path::from_src(&ctx, ast))?;
         self.resolver
             .resolve_path_as_macro(db.upcast(), path.mod_path()?, Some(MacroSubNs::Bang))
@@ -586,7 +635,7 @@ impl SourceAnalyzer {
             Pat::Path(path) => path,
             _ => return None,
         };
-        let res = resolve_hir_path(db, &self.resolver, path)?;
+        let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
         match res {
             PathResolution::Def(def) => Some(def),
             _ => None,
@@ -606,10 +655,10 @@ impl SourceAnalyzer {
             let infer = self.infer.as_deref()?;
             if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
                 let expr_id = self.expr_id(db, &path_expr.into())?;
-                if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr(expr_id) {
+                if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_id) {
                     let assoc = match assoc {
                         AssocItemId::FunctionId(f_in_trait) => {
-                            match infer.type_of_expr.get(expr_id) {
+                            match infer.type_of_expr_or_pat(expr_id) {
                                 None => assoc,
                                 Some(func_ty) => {
                                     if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
@@ -634,7 +683,7 @@ impl SourceAnalyzer {
                     return Some(PathResolution::Def(AssocItem::from(assoc).into()));
                 }
                 if let Some(VariantId::EnumVariantId(variant)) =
-                    infer.variant_resolution_for_expr(expr_id)
+                    infer.variant_resolution_for_expr_or_pat(expr_id)
                 {
                     return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
                 }
@@ -658,7 +707,7 @@ impl SourceAnalyzer {
             } else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
                 let expr_id = self.expr_id(db, &rec_lit.into())?;
                 if let Some(VariantId::EnumVariantId(variant)) =
-                    infer.variant_resolution_for_expr(expr_id)
+                    infer.variant_resolution_for_expr_or_pat(expr_id)
                 {
                     return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
                 }
@@ -680,14 +729,16 @@ impl SourceAnalyzer {
             return resolved;
         }
 
-        let ctx = LowerCtx::new(db.upcast(), self.file_id);
+        let (mut types_map, mut types_source_map) =
+            (TypesMap::default(), TypesSourceMap::default());
+        let ctx = LowerCtx::new(db.upcast(), self.file_id, &mut types_map, &mut types_source_map);
         let hir_path = Path::from_src(&ctx, path.clone())?;
 
         // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
         // trying to resolve foo::bar.
         if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
             if use_tree.coloncolon_token().is_some() {
-                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
+                return resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map);
             }
         }
 
@@ -704,7 +755,7 @@ impl SourceAnalyzer {
         // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
         // trying to resolve foo::bar.
         if path.parent_path().is_some() {
-            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
+            return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map) {
                 None if meta_path.is_some() => {
                     path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
                         ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
@@ -775,9 +826,16 @@ impl SourceAnalyzer {
             };
         }
         if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
-            resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
+            resolve_hir_path_qualifier(db, &self.resolver, &hir_path, &types_map)
         } else {
-            resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
+            resolve_hir_path_(
+                db,
+                &self.resolver,
+                &hir_path,
+                prefer_value_ns,
+                name_hygiene(db, InFile::new(self.file_id, path.syntax())),
+                &types_map,
+            )
         }
     }
 
@@ -790,10 +848,16 @@ impl SourceAnalyzer {
         let infer = self.infer.as_ref()?;
 
         let expr_id = self.expr_id(db, &literal.clone().into())?;
-        let substs = infer.type_of_expr[expr_id].as_adt()?.1;
+        let substs = infer[expr_id].as_adt()?.1;
 
-        let (variant, missing_fields, _exhaustive) =
-            record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
+        let (variant, missing_fields, _exhaustive) = match expr_id {
+            ExprOrPatId::ExprId(expr_id) => {
+                record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?
+            }
+            ExprOrPatId::PatId(pat_id) => {
+                record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?
+            }
+        };
         let res = self.missing_fields(db, substs, variant, missing_fields);
         Some(res)
     }
@@ -856,7 +920,7 @@ impl SourceAnalyzer {
     ) -> Option<VariantId> {
         let infer = self.infer.as_ref()?;
         let expr_id = self.expr_id(db, &record_lit.into())?;
-        infer.variant_resolution_for_expr(expr_id)
+        infer.variant_resolution_for_expr_or_pat(expr_id)
     }
 
     pub(crate) fn is_unsafe_macro_call_expr(
@@ -867,14 +931,24 @@ impl SourceAnalyzer {
         if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
             if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
                 let mut is_unsafe = false;
-                unsafe_expressions(
-                    db,
-                    infer,
-                    *def,
-                    body,
-                    expanded_expr,
-                    &mut |UnsafeExpr { inside_unsafe_block, .. }| is_unsafe |= !inside_unsafe_block,
-                );
+                let mut walk_expr = |expr_id| {
+                    unsafe_expressions(
+                        db,
+                        infer,
+                        *def,
+                        body,
+                        expr_id,
+                        &mut |UnsafeExpr { inside_unsafe_block, .. }| {
+                            is_unsafe |= !inside_unsafe_block
+                        },
+                    )
+                };
+                match expanded_expr {
+                    ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
+                    ExprOrPatId::PatId(expanded_pat) => {
+                        body.walk_exprs_in_pat(expanded_pat, &mut walk_expr)
+                    }
+                }
                 return is_unsafe;
             }
         }
@@ -887,7 +961,7 @@ impl SourceAnalyzer {
         format_args: InFile<&ast::FormatArgsExpr>,
         offset: TextSize,
     ) -> Option<(TextRange, Option<PathResolution>)> {
-        let implicits = self.body_source_map()?.implicit_format_args(format_args)?;
+        let (hygiene, implicits) = self.body_source_map()?.implicit_format_args(format_args)?;
         implicits.iter().find(|(range, _)| range.contains_inclusive(offset)).map(|(range, name)| {
             (
                 *range,
@@ -899,6 +973,7 @@ impl SourceAnalyzer {
                         PathKind::Plain,
                         Some(name.clone()),
                     )),
+                    hygiene,
                 ),
             )
         })
@@ -925,22 +1000,22 @@ impl SourceAnalyzer {
         db: &'a dyn HirDatabase,
         format_args: InFile<&ast::FormatArgsExpr>,
     ) -> Option<impl Iterator<Item = (TextRange, Option<PathResolution>)> + 'a> {
-        Some(self.body_source_map()?.implicit_format_args(format_args)?.iter().map(
-            move |(range, name)| {
-                (
-                    *range,
-                    resolve_hir_value_path(
-                        db,
-                        &self.resolver,
-                        self.resolver.body_owner(),
-                        &Path::from_known_path_with_no_generic(ModPath::from_segments(
-                            PathKind::Plain,
-                            Some(name.clone()),
-                        )),
-                    ),
-                )
-            },
-        ))
+        let (hygiene, names) = self.body_source_map()?.implicit_format_args(format_args)?;
+        Some(names.iter().map(move |(range, name)| {
+            (
+                *range,
+                resolve_hir_value_path(
+                    db,
+                    &self.resolver,
+                    self.resolver.body_owner(),
+                    &Path::from_known_path_with_no_generic(ModPath::from_segments(
+                        PathKind::Plain,
+                        Some(name.clone()),
+                    )),
+                    hygiene,
+                ),
+            )
+        }))
     }
 
     pub(crate) fn as_asm_parts(
@@ -991,7 +1066,7 @@ impl SourceAnalyzer {
     }
 
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
-        self.infer.as_ref()?.type_of_expr.get(self.expr_id(db, expr)?)
+        self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
     }
 }
 
@@ -1004,7 +1079,7 @@ fn scope_for(
     node.ancestors_with_macros(db.upcast())
         .take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
         .filter_map(|it| it.map(ast::Expr::cast).transpose())
-        .filter_map(|it| source_map.node_expr(it.as_ref()))
+        .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
         .find_map(|it| scopes.scope_for(it))
 }
 
@@ -1086,8 +1161,10 @@ pub(crate) fn resolve_hir_path(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
+    hygiene: HygieneId,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
-    resolve_hir_path_(db, resolver, path, false)
+    resolve_hir_path_(db, resolver, path, false, hygiene, types_map)
 }
 
 #[inline]
@@ -1107,13 +1184,20 @@ fn resolve_hir_path_(
     resolver: &Resolver,
     path: &Path,
     prefer_value_ns: bool,
+    hygiene: HygieneId,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
     let types = || {
         let (ty, unresolved) = match path.type_anchor() {
             Some(type_ref) => {
-                let (_, res) =
-                    TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
-                        .lower_ty_ext(type_ref);
+                let (_, res) = TyLoweringContext::new_maybe_unowned(
+                    db,
+                    resolver,
+                    types_map,
+                    None,
+                    resolver.type_owner(),
+                )
+                .lower_ty_ext(type_ref);
                 res.map(|ty_ns| (ty_ns, path.segments().first()))
             }
             None => {
@@ -1172,7 +1256,7 @@ fn resolve_hir_path_(
     };
 
     let body_owner = resolver.body_owner();
-    let values = || resolve_hir_value_path(db, resolver, body_owner, path);
+    let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene);
 
     let items = || {
         resolver
@@ -1197,8 +1281,9 @@ fn resolve_hir_value_path(
     resolver: &Resolver,
     body_owner: Option<DefWithBodyId>,
     path: &Path,
+    hygiene: HygieneId,
 ) -> Option<PathResolution> {
-    resolver.resolve_path_in_value_ns_fully(db.upcast(), path).and_then(|val| {
+    resolver.resolve_path_in_value_ns_fully(db.upcast(), path, hygiene).and_then(|val| {
         let res = match val {
             ValueNs::LocalBinding(binding_id) => {
                 let var = Local { parent: body_owner?, binding_id };
@@ -1233,13 +1318,19 @@ fn resolve_hir_path_qualifier(
     db: &dyn HirDatabase,
     resolver: &Resolver,
     path: &Path,
+    types_map: &TypesMap,
 ) -> Option<PathResolution> {
     (|| {
         let (ty, unresolved) = match path.type_anchor() {
             Some(type_ref) => {
-                let (_, res) =
-                    TyLoweringContext::new_maybe_unowned(db, resolver, resolver.type_owner())
-                        .lower_ty_ext(type_ref);
+                let (_, res) = TyLoweringContext::new_maybe_unowned(
+                    db,
+                    resolver,
+                    types_map,
+                    None,
+                    resolver.type_owner(),
+                )
+                .lower_ty_ext(type_ref);
                 res.map(|ty_ns| (ty_ns, path.segments().first()))
             }
             None => {
@@ -1303,3 +1394,13 @@ fn resolve_hir_path_qualifier(
             .map(|it| PathResolution::Def(it.into()))
     })
 }
+
+pub(crate) fn name_hygiene(db: &dyn HirDatabase, name: InFile<&SyntaxNode>) -> HygieneId {
+    let Some(macro_file) = name.file_id.macro_file() else {
+        return HygieneId::ROOT;
+    };
+    let span_map = db.expansion_span_map(macro_file);
+    let ctx = span_map.span_at(name.value.text_range().start()).ctx;
+    let ctx = db.lookup_intern_syntax_context(ctx);
+    HygieneId::new(ctx.opaque_and_semitransparent)
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index cabb7e3db3d..f8416f86bf9 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -8,7 +8,10 @@ use hir_def::{
     TraitId,
 };
 use hir_expand::HirFileId;
-use hir_ty::{db::HirDatabase, display::HirDisplay};
+use hir_ty::{
+    db::HirDatabase,
+    display::{hir_display_with_types_map, HirDisplay},
+};
 use span::Edition;
 use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr};
 
@@ -214,8 +217,11 @@ impl<'a> SymbolCollector<'a> {
 
     fn collect_from_impl(&mut self, impl_id: ImplId) {
         let impl_data = self.db.impl_data(impl_id);
-        let impl_name =
-            Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string()));
+        let impl_name = Some(
+            hir_display_with_types_map(impl_data.self_ty, &impl_data.types_map)
+                .display(self.db, self.edition)
+                .to_smolstr(),
+        );
         self.with_container_name(impl_name, |s| {
             for &assoc_item_id in impl_data.items.iter() {
                 s.push_assoc_item(assoc_item_id)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index 2a14fbe1e0a..ba215868710 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -23,7 +23,6 @@ tracing.workspace = true
 # local deps
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 ide-db.workspace = true
 hir.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
index c035c59ffca..605fd140523 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use hir::ModuleDef;
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -19,7 +20,6 @@ use syntax::{
     },
     AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T,
 };
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists},
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 b229b750e88..22a1efdbea7 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
@@ -1,4 +1,5 @@
 use hir::{sym, HasVisibility};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -8,7 +9,6 @@ use ide_db::{
 };
 use itertools::Itertools;
 use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr};
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index 9ecfb83ed53..3f0d5cf152c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -1,3 +1,4 @@
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -8,7 +9,6 @@ use syntax::{
     ast::{self, make, AstNode, FieldExpr, HasName, IdentPat},
     ted,
 };
-use text_edit::TextRange;
 
 use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
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 0e9c463e024..94274f6d17c 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
@@ -41,7 +41,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
 
     acc.add(
-        AssistId("remove_dbg", AssistKind::Refactor),
+        AssistId("remove_dbg", AssistKind::QuickFix),
         "Remove dbg!()",
         replacements.iter().map(|&(range, _)| range).reduce(|acc, range| acc.cover(range))?,
         |builder| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index c6f99d68748..0570b447782 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,6 +1,7 @@
 use std::collections::hash_map::Entry;
 
 use hir::{FileRange, HirFileIdExt, InFile, InRealFile, Module, ModuleSource};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     defs::Definition,
     search::{FileReference, ReferenceCategory, SearchScope},
@@ -10,7 +11,6 @@ use syntax::{
     ast::{self, Rename},
     AstNode,
 };
-use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
index 8a6c2937d90..26fd887cc99 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs
@@ -1,4 +1,5 @@
 use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     defs::Definition,
     search::{SearchScope, UsageSearchResult},
@@ -11,7 +12,6 @@ use syntax::{
     },
     match_ast, ted, AstNode,
 };
-use text_edit::TextRange;
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
index db789cfa334..648bf358b4b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs
@@ -34,6 +34,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let pipe_token = ctx.find_token_syntax_at_offset(T![|])?;
     let or_pat = ast::OrPat::cast(pipe_token.parent()?)?.clone_for_update();
+    if or_pat.leading_pipe().is_some_and(|it| it == pipe_token) {
+        return None;
+    }
     let match_arm = ast::MatchArm::cast(or_pat.syntax().parent()?)?;
     let match_arm_body = match_arm.expr()?;
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 22620816d50..8aaf5d6fff2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -301,6 +301,7 @@ mod handlers {
             inline_call::inline_into_callers,
             inline_const_as_literal::inline_const_as_literal,
             inline_local_variable::inline_local_variable,
+            inline_macro::inline_macro,
             inline_type_alias::inline_type_alias,
             inline_type_alias::inline_type_alias_uses,
             into_to_qualified_from::into_to_qualified_from,
@@ -326,6 +327,7 @@ mod handlers {
             raw_string::add_hash,
             raw_string::make_usual_string,
             raw_string::remove_hash,
+            remove_dbg::remove_dbg,
             remove_mut::remove_mut,
             remove_unused_imports::remove_unused_imports,
             remove_unused_param::remove_unused_param,
@@ -381,9 +383,6 @@ mod handlers {
             generate_getter_or_setter::generate_setter,
             generate_delegate_methods::generate_delegate_methods,
             generate_deref::generate_deref,
-            //
-            remove_dbg::remove_dbg,
-            inline_macro::inline_macro,
             // Are you sure you want to add new assist here, and not to the
             // sorted list above?
         ]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 614465b4d06..1bef82af5ac 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -25,7 +25,6 @@ base-db.workspace = true
 ide-db.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 # completions crate should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 672e1796d1e..c38a8ef29bb 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -32,6 +32,7 @@
 //! ```
 
 use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
     syntax_helpers::prettify_macro_expansion, traits::get_missing_assoc_items, SymbolKind,
@@ -40,7 +41,6 @@ use syntax::{
     ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds},
     format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
 };
-use text_edit::TextEdit;
 
 use crate::{
     context::PathCompletionCtx, CompletionContext, CompletionItem, CompletionItemKind,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index 05e2892fdc8..f12f011a6bd 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -7,7 +7,6 @@ use ide_db::{
     base_db::{SourceRootDatabase, VfsPath},
     FxHashSet, RootDatabase, SymbolKind,
 };
-use stdx::IsNoneOr;
 use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
 
 use crate::{context::CompletionContext, CompletionItem, Completions};
@@ -66,7 +65,7 @@ pub(crate) fn complete_mod(
         .iter()
         .filter(|&submodule_candidate_file| submodule_candidate_file != module_definition_file)
         .filter(|&submodule_candidate_file| {
-            IsNoneOr::is_none_or(module_declaration_file, |it| it != submodule_candidate_file)
+            module_declaration_file.is_none_or(|it| it != submodule_candidate_file)
         })
         .filter_map(|submodule_file| {
             let submodule_path = source_root.path_for_file(&submodule_file)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index d3579fd8cc6..495f82da866 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -3,6 +3,7 @@
 mod format_like;
 
 use hir::ItemInNs;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::{Documentation, HasDocs},
     imports::insert_use::ImportScope,
@@ -15,7 +16,6 @@ use syntax::{
     SyntaxKind::{BLOCK_EXPR, EXPR_STMT, FOR_EXPR, IF_EXPR, LOOP_EXPR, STMT_LIST, WHILE_EXPR},
     TextRange, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{
     completions::postfix::format_like::add_format_like_completions,
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 0e1302ff2ef..efbee39a2d4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -20,7 +20,6 @@ use syntax::{
     SyntaxKind::{self, *},
     SyntaxToken, TextRange, TextSize, T,
 };
-use text_edit::Indel;
 
 use crate::{
     context::analysis::{expand_and_analyze, AnalysisResult},
@@ -684,8 +683,7 @@ impl<'a> CompletionContext<'a> {
         // actual completion.
         let file_with_fake_ident = {
             let parse = db.parse(file_id);
-            let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned());
-            parse.reparse(&edit, file_id.edition()).tree()
+            parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, file_id.edition()).tree()
         };
 
         // always pick the token to the immediate left of the cursor, as that is what we are actually
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index 8c97ebd5500..52f6bedaaa9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -3,6 +3,7 @@
 use std::{fmt, mem};
 
 use hir::Mutability;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::Documentation, imports::import_assets::LocatedImport, RootDatabase, SnippetCap,
     SymbolKind,
@@ -11,7 +12,6 @@ use itertools::Itertools;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize};
-use text_edit::TextEdit;
 
 use crate::{
     context::{CompletionContext, PathCompletionCtx},
@@ -426,7 +426,7 @@ impl CompletionItem {
         self.lookup.as_str()
     }
 
-    pub fn ref_match(&self) -> Option<(String, text_edit::Indel, CompletionRelevance)> {
+    pub fn ref_match(&self) -> Option<(String, ide_db::text_edit::Indel, CompletionRelevance)> {
         // Relevance of the ref match should be the same as the original
         // match, but with exact type match set because self.ref_match
         // is only set if there is an exact type match.
@@ -436,7 +436,10 @@ impl CompletionItem {
         self.ref_match.map(|(mutability, offset)| {
             (
                 format!("&{}{}", mutability.as_keyword_for_ref(), self.label),
-                text_edit::Indel::insert(offset, format!("&{}", mutability.as_keyword_for_ref())),
+                ide_db::text_edit::Indel::insert(
+                    offset,
+                    format!("&{}", mutability.as_keyword_for_ref()),
+                ),
                 relevance,
             )
         })
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index a78976d3fd8..dfee01b187e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,16 +10,17 @@ mod snippet;
 #[cfg(test)]
 mod tests;
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::{
         import_assets::NameToImport,
         insert_use::{self, ImportScope},
     },
-    items_locator, FilePosition, RootDatabase,
+    items_locator,
+    syntax_helpers::tree_diff::diff,
+    FilePosition, RootDatabase,
 };
-use syntax::algo;
-use text_edit::TextEdit;
 
 use crate::{
     completions::Completions,
@@ -297,6 +298,6 @@ pub fn resolve_completion_edits(
         }
     });
 
-    algo::diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
+    diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
     Some(vec![import_insert.finish()])
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 4dd171142f9..ec3c2fe3556 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -11,6 +11,7 @@ pub(crate) mod union_literal;
 pub(crate) mod variant;
 
 use hir::{sym, AsAssocItem, HasAttrs, HirDisplay, ModuleDef, ScopeDef, Type};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::{Documentation, HasDocs},
     helpers::item_name,
@@ -18,7 +19,6 @@ use ide_db::{
     RootDatabase, SnippetCap, SymbolKind,
 };
 use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr};
-use text_edit::TextEdit;
 
 use crate::{
     context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext},
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 1bbe097cc6c..45679355b42 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
@@ -663,6 +663,7 @@ mod cfg {
                 ba dbg
                 ba opt_level
                 ba test
+                ba true
             "#]],
         );
         check(
@@ -674,6 +675,7 @@ mod cfg {
                 ba dbg
                 ba opt_level
                 ba test
+                ba true
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index c078188d6d3..17f0e69bde4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -35,7 +35,6 @@ parser.workspace = true
 profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 span.workspace = true
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 7474d7bc54d..35e3a8d9bf7 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -100,16 +100,19 @@ impl RootDatabase {
             hir::db::ConstEvalQuery
             hir::db::ConstEvalStaticQuery
             hir::db::ConstParamTyQuery
+            hir::db::DynCompatibilityOfTraitQuery
             hir::db::FieldTypesQuery
             hir::db::FnDefDatumQuery
             hir::db::FnDefVarianceQuery
             hir::db::GenericDefaultsQuery
             hir::db::GenericPredicatesForParamQuery
             hir::db::GenericPredicatesQuery
+            hir::db::GenericPredicatesWithoutParentQuery
             hir::db::ImplDatumQuery
             hir::db::ImplSelfTyQuery
             hir::db::ImplTraitQuery
             hir::db::IncoherentInherentImplCratesQuery
+            hir::db::InferQuery
             hir::db::InherentImplsInBlockQuery
             hir::db::InherentImplsInCrateQuery
             hir::db::InternCallableDefQuery
@@ -119,7 +122,12 @@ impl RootDatabase {
             hir::db::InternLifetimeParamIdQuery
             hir::db::InternTypeOrConstParamIdQuery
             hir::db::LayoutOfAdtQuery
+            hir::db::LayoutOfTyQuery
+            hir::db::LookupImplMethodQuery
+            hir::db::MirBodyForClosureQuery
             hir::db::MirBodyQuery
+            hir::db::MonomorphizedMirBodyForClosureQuery
+            hir::db::MonomorphizedMirBodyQuery
             hir::db::ProgramClausesForChalkEnvQuery
             hir::db::ReturnTypeImplTraitsQuery
             hir::db::TargetDataLayoutQuery
@@ -128,13 +136,16 @@ impl RootDatabase {
             hir::db::TraitImplsInBlockQuery
             hir::db::TraitImplsInCrateQuery
             hir::db::TraitImplsInDepsQuery
+            hir::db::TraitSolveQuery
             hir::db::TyQuery
+            hir::db::TypeAliasImplTraitsQuery
             hir::db::ValueTyQuery
 
             // DefDatabase
             hir::db::AttrsQuery
             hir::db::BlockDefMapQuery
             hir::db::BlockItemTreeQuery
+            hir::db::BlockItemTreeWithSourceMapQuery
             hir::db::BodyQuery
             hir::db::BodyWithSourceMapQuery
             hir::db::ConstDataQuery
@@ -145,17 +156,21 @@ impl RootDatabase {
             hir::db::CrateSupportsNoStdQuery
             hir::db::EnumDataQuery
             hir::db::EnumVariantDataWithDiagnosticsQuery
+            hir::db::ExpandProcAttrMacrosQuery
             hir::db::ExprScopesQuery
             hir::db::ExternCrateDeclDataQuery
             hir::db::FieldVisibilitiesQuery
             hir::db::FieldsAttrsQuery
             hir::db::FieldsAttrsSourceMapQuery
             hir::db::FileItemTreeQuery
+            hir::db::FileItemTreeWithSourceMapQuery
             hir::db::FunctionDataQuery
             hir::db::FunctionVisibilityQuery
             hir::db::GenericParamsQuery
+            hir::db::GenericParamsWithSourceMapQuery
             hir::db::ImplDataWithDiagnosticsQuery
             hir::db::ImportMapQuery
+            hir::db::IncludeMacroInvocQuery
             hir::db::InternAnonymousConstQuery
             hir::db::InternBlockQuery
             hir::db::InternConstQuery
@@ -177,7 +192,9 @@ impl RootDatabase {
             hir::db::InternUseQuery
             hir::db::LangItemQuery
             hir::db::Macro2DataQuery
+            hir::db::MacroDefQuery
             hir::db::MacroRulesDataQuery
+            hir::db::NotableTraitsInDepsQuery
             hir::db::ProcMacroDataQuery
             hir::db::StaticDataQuery
             hir::db::StructDataWithDiagnosticsQuery
@@ -212,6 +229,7 @@ impl RootDatabase {
             hir::db::MacroArgQuery
             hir::db::ParseMacroExpansionErrorQuery
             hir::db::ParseMacroExpansionQuery
+            hir::db::ProcMacroSpanQuery
             hir::db::ProcMacrosQuery
             hir::db::RealSpanMapQuery
 
@@ -220,7 +238,9 @@ impl RootDatabase {
 
             // SourceDatabase
             base_db::ParseQuery
+            base_db::ParseErrorsQuery
             base_db::CrateGraphQuery
+            base_db::CrateWorkspaceDataQuery
 
             // SourceDatabaseExt
             base_db::FileTextQuery
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 099f26eba78..fdac4dd2efb 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -5,14 +5,17 @@
 
 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 
+use crate::documentation::{Documentation, HasDocs};
+use crate::famous_defs::FamousDefs;
+use crate::RootDatabase;
 use arrayvec::ArrayVec;
 use either::Either;
 use hir::{
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
     Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
     Function, GenericParam, HasVisibility, HirDisplay, Impl, InlineAsmOperand, Label, Local, Macro,
-    Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
-    TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
+    Module, ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule,
+    Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
 };
 use span::Edition;
 use stdx::{format_to, impl_from};
@@ -21,10 +24,6 @@ use syntax::{
     match_ast, SyntaxKind, SyntaxNode, SyntaxToken,
 };
 
-use crate::documentation::{Documentation, HasDocs};
-use crate::famous_defs::FamousDefs;
-use crate::RootDatabase;
-
 // FIXME: a more precise name would probably be `Symbol`?
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 pub enum Definition {
@@ -179,7 +178,19 @@ impl Definition {
             Definition::Static(it) => it.docs(db),
             Definition::Trait(it) => it.docs(db),
             Definition::TraitAlias(it) => it.docs(db),
-            Definition::TypeAlias(it) => it.docs(db),
+            Definition::TypeAlias(it) => {
+                it.docs(db).or_else(|| {
+                    // docs are missing, try to fall back to the docs of the aliased item.
+                    let adt = it.ty(db).as_adt()?;
+                    let docs = adt.docs(db)?;
+                    let docs = format!(
+                        "*This is the documentation for* `{}`\n\n{}",
+                        adt.display(db, edition),
+                        docs.as_str()
+                    );
+                    Some(Documentation::new(docs))
+                })
+            }
             Definition::BuiltinType(it) => {
                 famous_defs.and_then(|fd| {
                     // std exposes prim_{} modules with docstrings on the root to document the builtins
@@ -319,6 +330,8 @@ impl IdentClass {
                         .map(IdentClass::NameClass)
                         .or_else(|| NameRefClass::classify_lifetime(sema, &lifetime).map(IdentClass::NameRefClass))
                 },
+                ast::RangePat(range_pat) => OperatorClass::classify_range_pat(sema, &range_pat).map(IdentClass::Operator),
+                ast::RangeExpr(range_expr) => OperatorClass::classify_range_expr(sema, &range_expr).map(IdentClass::Operator),
                 ast::AwaitExpr(await_expr) => OperatorClass::classify_await(sema, &await_expr).map(IdentClass::Operator),
                 ast::BinExpr(bin_expr) => OperatorClass::classify_bin(sema, &bin_expr).map(IdentClass::Operator),
                 ast::IndexExpr(index_expr) => OperatorClass::classify_index(sema, &index_expr).map(IdentClass::Operator),
@@ -372,6 +385,9 @@ impl IdentClass {
                 | OperatorClass::Index(func)
                 | OperatorClass::Try(func),
             ) => res.push(Definition::Function(func)),
+            IdentClass::Operator(OperatorClass::Range(struct0)) => {
+                res.push(Definition::Adt(Adt::Struct(struct0)))
+            }
         }
         res
     }
@@ -546,6 +562,7 @@ impl NameClass {
 
 #[derive(Debug)]
 pub enum OperatorClass {
+    Range(Struct),
     Await(Function),
     Prefix(Function),
     Index(Function),
@@ -554,6 +571,20 @@ pub enum OperatorClass {
 }
 
 impl OperatorClass {
+    pub fn classify_range_pat(
+        sema: &Semantics<'_, RootDatabase>,
+        range_pat: &ast::RangePat,
+    ) -> Option<OperatorClass> {
+        sema.resolve_range_pat(range_pat).map(OperatorClass::Range)
+    }
+
+    pub fn classify_range_expr(
+        sema: &Semantics<'_, RootDatabase>,
+        range_expr: &ast::RangeExpr,
+    ) -> Option<OperatorClass> {
+        sema.resolve_range_expr(range_expr).map(OperatorClass::Range)
+    }
+
     pub fn classify_await(
         sema: &Semantics<'_, RootDatabase>,
         await_expr: &ast::AwaitExpr,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
index 5e443badf9e..b52a325790b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs
@@ -5,11 +5,11 @@ use hir::{
     resolve_doc_path_on, sym, AttrId, AttrSourceMap, AttrsWithOwner, HasAttrs, InFile,
 };
 use itertools::Itertools;
+use span::{TextRange, TextSize};
 use syntax::{
     ast::{self, IsString},
     AstToken,
 };
-use text_edit::{TextRange, TextSize};
 
 /// Holds documentation
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index aed093f0ebf..81260c3e080 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -19,6 +19,7 @@ pub mod rust_doc;
 pub mod search;
 pub mod source_change;
 pub mod symbol_index;
+pub mod text_edit;
 pub mod traits;
 pub mod ty_filter;
 pub mod use_trivial_constructor;
@@ -36,6 +37,7 @@ pub mod generated {
 pub mod syntax_helpers {
     pub mod format_string;
     pub mod format_string_exprs;
+    pub mod tree_diff;
     pub use hir::prettify_macro_expansion;
     pub mod node_ext;
     pub mod suggest_name;
@@ -293,3 +295,35 @@ impl SnippetCap {
         }
     }
 }
+
+pub struct Ranker<'a> {
+    pub kind: parser::SyntaxKind,
+    pub text: &'a str,
+    pub ident_kind: bool,
+}
+
+impl<'a> Ranker<'a> {
+    pub const MAX_RANK: usize = 0b1110;
+
+    pub fn from_token(token: &'a syntax::SyntaxToken) -> Self {
+        let kind = token.kind();
+        Ranker { kind, text: token.text(), ident_kind: kind.is_any_identifier() }
+    }
+
+    /// A utility function that ranks a token again a given kind and text, returning a number that
+    /// represents how close the token is to the given kind and text.
+    pub fn rank_token(&self, tok: &syntax::SyntaxToken) -> usize {
+        let tok_kind = tok.kind();
+
+        let exact_same_kind = tok_kind == self.kind;
+        let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && self.ident_kind);
+        let same_text = tok.text() == self.text;
+        // anything that mapped into a token tree has likely no semantic information
+        let no_tt_parent =
+            tok.parent().map_or(false, |it| it.kind() != parser::SyntaxKind::TOKEN_TREE);
+        (both_idents as usize)
+            | ((exact_same_kind as usize) << 1)
+            | ((same_text as usize) << 2)
+            | ((no_tt_parent as usize) << 3)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index f1404ed9f22..1d1679c3ff8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -22,6 +22,7 @@
 //! Our current behavior is ¯\_(ツ)_/¯.
 use std::fmt;
 
+use crate::text_edit::{TextEdit, TextEditBuilder};
 use base_db::AnchoredPathBuf;
 use either::Either;
 use hir::{FieldSource, FileRange, HirFileIdExt, InFile, ModuleSource, Semantics};
@@ -32,7 +33,6 @@ use syntax::{
     utils::is_raw_identifier,
     AstNode, SyntaxKind, TextRange, T,
 };
-use text_edit::{TextEdit, TextEditBuilder};
 
 use crate::{
     defs::Definition,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
index 73073e92f78..27ff91dc19d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/source_change.rs
@@ -5,7 +5,8 @@
 
 use std::{collections::hash_map::Entry, iter, mem};
 
-use crate::{assists::Command, SnippetCap};
+use crate::text_edit::{TextEdit, TextEditBuilder};
+use crate::{assists::Command, syntax_helpers::tree_diff::diff, SnippetCap};
 use base_db::AnchoredPathBuf;
 use itertools::Itertools;
 use nohash_hasher::IntMap;
@@ -13,11 +14,9 @@ use rustc_hash::FxHashMap;
 use span::FileId;
 use stdx::never;
 use syntax::{
-    algo,
     syntax_editor::{SyntaxAnnotation, SyntaxEditor},
     AstNode, SyntaxElement, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize,
 };
-use text_edit::{TextEdit, TextEditBuilder};
 
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
@@ -315,7 +314,7 @@ impl SourceChangeBuilder {
             }
 
             let mut edit = TextEdit::builder();
-            algo::diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
+            diff(edit_result.old_root(), edit_result.new_root()).into_text_edit(&mut edit);
             let edit = edit.finish();
 
             let snippet_edit =
@@ -334,7 +333,7 @@ impl SourceChangeBuilder {
         });
 
         if let Some(tm) = self.mutated_tree.take() {
-            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
+            diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit);
         }
 
         let edit = mem::take(&mut self.edit).finish();
@@ -373,7 +372,7 @@ impl SourceChangeBuilder {
         self.edit.replace(range, replace_with.into())
     }
     pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
-        algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
+        diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
     }
     pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
         let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
new file mode 100644
index 00000000000..02e24c47761
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/tree_diff.rs
@@ -0,0 +1,559 @@
+//! Basic tree diffing functionality.
+use rustc_hash::FxHashMap;
+use syntax::{NodeOrToken, SyntaxElement, SyntaxNode};
+
+use crate::{text_edit::TextEditBuilder, FxIndexMap};
+
+#[derive(Debug, Hash, PartialEq, Eq)]
+enum TreeDiffInsertPos {
+    After(SyntaxElement),
+    AsFirstChild(SyntaxElement),
+}
+
+#[derive(Debug)]
+pub struct TreeDiff {
+    replacements: FxHashMap<SyntaxElement, SyntaxElement>,
+    deletions: Vec<SyntaxElement>,
+    // the vec as well as the indexmap are both here to preserve order
+    insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
+}
+
+impl TreeDiff {
+    pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
+        let _p = tracing::info_span!("into_text_edit").entered();
+
+        for (anchor, to) in &self.insertions {
+            let offset = match anchor {
+                TreeDiffInsertPos::After(it) => it.text_range().end(),
+                TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
+            };
+            to.iter().for_each(|to| builder.insert(offset, to.to_string()));
+        }
+        for (from, to) in &self.replacements {
+            builder.replace(from.text_range(), to.to_string());
+        }
+        for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
+            builder.delete(text_range);
+        }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
+    }
+}
+
+/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
+///
+/// Specifically, returns a structure that consists of a replacements, insertions and deletions
+/// such that applying this map on `from` will result in `to`.
+///
+/// This function tries to find a fine-grained diff.
+pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
+    let _p = tracing::info_span!("diff").entered();
+
+    let mut diff = TreeDiff {
+        replacements: FxHashMap::default(),
+        insertions: FxIndexMap::default(),
+        deletions: Vec::new(),
+    };
+    let (from, to) = (from.clone().into(), to.clone().into());
+
+    if !syntax_element_eq(&from, &to) {
+        go(&mut diff, from, to);
+    }
+    return diff;
+
+    fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
+        lhs.kind() == rhs.kind()
+            && lhs.text_range().len() == rhs.text_range().len()
+            && match (&lhs, &rhs) {
+                (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
+                    lhs == rhs || lhs.text() == rhs.text()
+                }
+                (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
+                _ => false,
+            }
+    }
+
+    // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
+    fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
+        let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
+            Some((lhs, rhs)) => (lhs, rhs),
+            _ => {
+                cov_mark::hit!(diff_node_token_replace);
+                diff.replacements.insert(lhs, rhs);
+                return;
+            }
+        };
+
+        let mut look_ahead_scratch = Vec::default();
+
+        let mut rhs_children = rhs.children_with_tokens();
+        let mut lhs_children = lhs.children_with_tokens();
+        let mut last_lhs = None;
+        loop {
+            let lhs_child = lhs_children.next();
+            match (lhs_child.clone(), rhs_children.next()) {
+                (None, None) => break,
+                (None, Some(element)) => {
+                    let insert_pos = match last_lhs.clone() {
+                        Some(prev) => {
+                            cov_mark::hit!(diff_insert);
+                            TreeDiffInsertPos::After(prev)
+                        }
+                        // first iteration, insert into out parent as the first child
+                        None => {
+                            cov_mark::hit!(diff_insert_as_first_child);
+                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+                        }
+                    };
+                    diff.insertions.entry(insert_pos).or_default().push(element);
+                }
+                (Some(element), None) => {
+                    cov_mark::hit!(diff_delete);
+                    diff.deletions.push(element);
+                }
+                (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
+                (Some(lhs_ele), Some(rhs_ele)) => {
+                    // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
+                    // until that element as insertions. This is important to keep the diff minimal
+                    // in regards to insertions that have been actually done, this is important for
+                    // use insertions as we do not want to replace the entire module node.
+                    look_ahead_scratch.push(rhs_ele.clone());
+                    let mut rhs_children_clone = rhs_children.clone();
+                    let mut insert = false;
+                    for rhs_child in &mut rhs_children_clone {
+                        if syntax_element_eq(&lhs_ele, &rhs_child) {
+                            cov_mark::hit!(diff_insertions);
+                            insert = true;
+                            break;
+                        }
+                        look_ahead_scratch.push(rhs_child);
+                    }
+                    let drain = look_ahead_scratch.drain(..);
+                    if insert {
+                        let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
+                            TreeDiffInsertPos::After(prev)
+                        } else {
+                            cov_mark::hit!(insert_first_child);
+                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
+                        };
+
+                        diff.insertions.entry(insert_pos).or_default().extend(drain);
+                        rhs_children = rhs_children_clone;
+                    } else {
+                        go(diff, lhs_ele, rhs_ele);
+                    }
+                }
+            }
+            last_lhs = lhs_child.or(last_lhs);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use expect_test::{expect, Expect};
+    use itertools::Itertools;
+    use parser::{Edition, SyntaxKind};
+    use syntax::{AstNode, SourceFile, SyntaxElement};
+
+    use crate::text_edit::TextEdit;
+
+    #[test]
+    fn replace_node_token() {
+        cov_mark::check!(diff_node_token_replace);
+        check_diff(
+            r#"use node;"#,
+            r#"ident"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+                Line 0: Token(USE_KW@0..3 "use") -> ident
+
+                deletions:
+
+                Line 1: " "
+                Line 1: node
+                Line 1: ;
+            "#]],
+        );
+    }
+
+    #[test]
+    fn replace_parent() {
+        cov_mark::check!(diff_insert_as_first_child);
+        check_diff(
+            r#""#,
+            r#"use foo::bar;"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
+                -> use foo::bar;
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn insert_last() {
+        cov_mark::check!(diff_insert);
+        check_diff(
+            r#"
+use foo;
+use bar;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Node(USE@10..18))
+                -> "\n"
+                -> use baz;
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn insert_middle() {
+        check_diff(
+            r#"
+use foo;
+use baz;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Token(WHITESPACE@9..10 "\n"))
+                -> use bar;
+                -> "\n"
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        )
+    }
+
+    #[test]
+    fn insert_first() {
+        check_diff(
+            r#"
+use bar;
+use baz;"#,
+            r#"
+use foo;
+use bar;
+use baz;"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: After(Token(WHITESPACE@0..1 "\n"))
+                -> use foo;
+                -> "\n"
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        )
+    }
+
+    #[test]
+    fn first_child_insertion() {
+        cov_mark::check!(insert_first_child);
+        check_diff(
+            r#"fn main() {
+        stdi
+    }"#,
+            r#"use foo::bar;
+
+    fn main() {
+        stdi
+    }"#,
+            expect![[r#"
+                insertions:
+
+                Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
+                -> use foo::bar;
+                -> "\n\n    "
+
+                replacements:
+
+
+
+                deletions:
+
+
+            "#]],
+        );
+    }
+
+    #[test]
+    fn delete_last() {
+        cov_mark::check!(diff_delete);
+        check_diff(
+            r#"use foo;
+            use bar;"#,
+            r#"use foo;"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+
+
+                deletions:
+
+                Line 1: "\n            "
+                Line 2: use bar;
+            "#]],
+        );
+    }
+
+    #[test]
+    fn delete_middle() {
+        cov_mark::check!(diff_insertions);
+        check_diff(
+            r#"
+use expect_test::{expect, Expect};
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+            r#"
+use expect_test::{expect, Expect};
+
+use crate::AstNode;
+"#,
+            expect![[r#"
+                insertions:
+
+                Line 1: After(Node(USE@1..35))
+                -> "\n\n"
+                -> use crate::AstNode;
+
+                replacements:
+
+
+
+                deletions:
+
+                Line 2: use text_edit::TextEdit;
+                Line 3: "\n\n"
+                Line 4: use crate::AstNode;
+                Line 5: "\n"
+            "#]],
+        )
+    }
+
+    #[test]
+    fn delete_first() {
+        check_diff(
+            r#"
+use text_edit::TextEdit;
+
+use crate::AstNode;
+"#,
+            r#"
+use crate::AstNode;
+"#,
+            expect![[r#"
+                insertions:
+
+
+
+                replacements:
+
+                Line 2: Token(IDENT@5..14 "text_edit") -> crate
+                Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
+                Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
+
+                deletions:
+
+                Line 3: use crate::AstNode;
+                Line 4: "\n"
+            "#]],
+        )
+    }
+
+    #[test]
+    fn merge_use() {
+        check_diff(
+            r#"
+use std::{
+    fmt,
+    hash::BuildHasherDefault,
+    ops::{self, RangeInclusive},
+};
+"#,
+            r#"
+use std::fmt;
+use std::hash::BuildHasherDefault;
+use std::ops::{self, RangeInclusive};
+"#,
+            expect![[r#"
+                insertions:
+
+                Line 2: After(Node(PATH_SEGMENT@5..8))
+                -> ::
+                -> fmt
+                Line 6: After(Token(WHITESPACE@86..87 "\n"))
+                -> use std::hash::BuildHasherDefault;
+                -> "\n"
+                -> use std::ops::{self, RangeInclusive};
+                -> "\n"
+
+                replacements:
+
+                Line 2: Token(IDENT@5..8 "std") -> std
+
+                deletions:
+
+                Line 2: ::
+                Line 2: {
+                    fmt,
+                    hash::BuildHasherDefault,
+                    ops::{self, RangeInclusive},
+                }
+            "#]],
+        )
+    }
+
+    #[test]
+    fn early_return_assist() {
+        check_diff(
+            r#"
+fn main() {
+    if let Ok(x) = Err(92) {
+        foo(x);
+    }
+}
+            "#,
+            r#"
+fn main() {
+    let x = match Err(92) {
+        Ok(it) => it,
+        _ => return,
+    };
+    foo(x);
+}
+            "#,
+            expect![[r#"
+                insertions:
+
+                Line 3: After(Node(BLOCK_EXPR@40..63))
+                -> " "
+                -> match Err(92) {
+                        Ok(it) => it,
+                        _ => return,
+                    }
+                -> ;
+                Line 3: After(Node(IF_EXPR@17..63))
+                -> "\n    "
+                -> foo(x);
+
+                replacements:
+
+                Line 3: Token(IF_KW@17..19 "if") -> let
+                Line 3: Token(LET_KW@20..23 "let") -> x
+                Line 3: Node(BLOCK_EXPR@40..63) -> =
+
+                deletions:
+
+                Line 3: " "
+                Line 3: Ok(x)
+                Line 3: " "
+                Line 3: =
+                Line 3: " "
+                Line 3: Err(92)
+            "#]],
+        )
+    }
+
+    fn check_diff(from: &str, to: &str, expected_diff: Expect) {
+        let from_node = SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
+        let to_node = SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
+        let diff = super::diff(&from_node, &to_node);
+
+        let line_number =
+            |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
+
+        let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
+            SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
+            _ => format!("{syn}"),
+        };
+
+        let insertions =
+            diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
+                f(&format!(
+                    "Line {}: {:?}\n-> {}",
+                    line_number(match k {
+                        super::TreeDiffInsertPos::After(syn) => syn,
+                        super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
+                    }),
+                    k,
+                    v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
+                ))
+            });
+
+        let replacements = diff
+            .replacements
+            .iter()
+            .sorted_by_key(|(syntax, _)| syntax.text_range().start())
+            .format_with("\n", |(k, v), f| {
+                f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
+            });
+
+        let deletions = diff
+            .deletions
+            .iter()
+            .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
+
+        let actual = format!(
+            "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
+        );
+        expected_diff.assert_eq(&actual);
+
+        let mut from = from.to_owned();
+        let mut text_edit = TextEdit::builder();
+        diff.into_text_edit(&mut text_edit);
+        text_edit.finish().apply(&mut from);
+        assert_eq!(&*from, to, "diff did not turn `from` to `to`");
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
index 3efe0850d88..0c675f0619f 100644
--- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/text_edit.rs
@@ -5,8 +5,8 @@
 //! rust-analyzer.
 
 use itertools::Itertools;
+pub use span::{TextRange, TextSize};
 use std::cmp::max;
-pub use text_size::{TextRange, TextSize};
 
 /// `InsertDelete` -- a single "atomic" change to text
 ///
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index bf54f4ab322..281a08e5429 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -22,7 +22,6 @@ tracing.workspace = true
 # local deps
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 cfg.workspace = true
 hir.workspace = true
 ide-db.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
index c7071d1ce47..876c2ccd49d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/field_shorthand.rs
@@ -1,9 +1,9 @@
 //! Suggests shortening `Foo { field: field }` to `Foo { field }` in both
 //! expressions and patterns.
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
 use syntax::{ast, match_ast, AstNode, SyntaxNode};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 1f8f805a1e2..4c0c685e550 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -195,4 +195,20 @@ union FooBar {
 "#,
         );
     }
+
+    #[test]
+    fn cfg_true_false() {
+        check(
+            r#"
+  #[cfg(false)] fn inactive() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: false is disabled
+
+  #[cfg(true)] fn active() {}
+
+  #[cfg(any(not(true)), false)] fn inactive2() {}
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: true is enabled
+
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index ccb33fed100..dca889d1a8e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -2,6 +2,7 @@
 //! example.
 
 use hir::{ImportPathConfig, PathResolution, Semantics};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
@@ -14,7 +15,6 @@ use syntax::{
     ast::{self, make},
     Edition, SyntaxKind, SyntaxNode,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 6a976697c80..e177b72e4d4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -3,14 +3,19 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
 // Diagnostic: macro-error
 //
 // This diagnostic is shown for macro expansion errors.
+
+// Diagnostic: proc-macros-disabled
+//
+// This diagnostic is shown for proc macros where proc macros have been disabled.
+
+// Diagnostic: proc-macro-disabled
+//
+// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`.
 pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
     // Use more accurate position if available.
     let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
     Diagnostic::new(
-        DiagnosticCode::Ra(
-            "macro-error",
-            if d.error { Severity::Error } else { Severity::WeakWarning },
-        ),
+        DiagnosticCode::Ra(d.kind, if d.error { Severity::Error } else { Severity::WeakWarning }),
         d.message.clone(),
         display_range,
     )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 86c237f7b5e..fd1044e51bc 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -5,15 +5,14 @@ use hir::{
 };
 use ide_db::{
     assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search,
-    source_change::SourceChange, use_trivial_constructor::use_trivial_constructor, FxHashMap,
+    source_change::SourceChange, syntax_helpers::tree_diff::diff, text_edit::TextEdit,
+    use_trivial_constructor::use_trivial_constructor, FxHashMap,
 };
 use stdx::format_to;
 use syntax::{
-    algo,
     ast::{self, make},
     AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -77,7 +76,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 // FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here
                 builder.replace(old_range.range, new_syntax.to_string());
             } else {
-                algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder);
+                diff(old_syntax, new_syntax).into_text_edit(&mut builder);
             }
             builder.finish()
         };
@@ -308,22 +307,27 @@ struct T(S);
 fn regular(a: S) {
     let s;
     S { s, .. } = a;
+    _ = s;
 }
 fn nested(a: S2) {
     let s;
     S2 { s: S { s, .. }, .. } = a;
+    _ = s;
 }
 fn in_tuple(a: (S,)) {
     let s;
     (S { s, .. },) = a;
+    _ = s;
 }
 fn in_array(a: [S;1]) {
     let s;
     [S { s, .. },] = a;
+    _ = s;
 }
 fn in_tuple_struct(a: T) {
     let s;
     T(S { s, .. }) = a;
+    _ = s;
 }
             ",
         );
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 44be53b87ca..a630d3c7c36 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
@@ -1,9 +1,9 @@
 use hir::db::ExpandDatabase;
 use hir::HirFileIdExt;
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use syntax::{ast, SyntaxNode};
 use syntax::{match_ast, AstNode};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -32,7 +32,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Ass
     }
 
     let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
-    let expr = d.expr.value.to_node(&root);
+    let node = d.expr.value.to_node(&root);
+    let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?;
 
     let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 6fa0e7a5a89..13979791444 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -1,6 +1,7 @@
+use hir::db::ExpandDatabase;
 use ide_db::source_change::SourceChange;
-use syntax::{AstNode, SyntaxKind, SyntaxNode, SyntaxToken, T};
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
+use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, T};
 
 use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
@@ -8,18 +9,27 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 //
 // This diagnostic is triggered on mutating an immutable variable.
 pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option<Diagnostic> {
-    if d.span.file_id.macro_file().is_some() {
-        // FIXME: Our infra can't handle allow from within macro expansions rn
-        return None;
-    }
+    let root = ctx.sema.db.parse_or_expand(d.span.file_id);
+    let node = d.span.value.to_node(&root);
+    let mut span = d.span;
+    if let Some(parent) = node.parent() {
+        if ast::BinExpr::can_cast(parent.kind()) {
+            // In case of an assignment, the diagnostic is provided on the variable name.
+            // We want to expand it to include the whole assignment, but only when this
+            // is an ordinary assignment, not a destructuring assignment. So, the direct
+            // parent is an assignment expression.
+            span = d.span.with_value(SyntaxNodePtr::new(&parent));
+        }
+    };
+
     let fixes = (|| {
         if d.local.is_ref(ctx.sema.db) {
             // There is no simple way to add `mut` to `ref x` and `ref mut x`
             return None;
         }
-        let file_id = d.span.file_id.file_id()?;
+        let file_id = span.file_id.file_id()?;
         let mut edit_builder = TextEdit::builder();
-        let use_range = d.span.value.text_range();
+        let use_range = span.value.text_range();
         for source in d.local.sources(ctx.sema.db) {
             let Some(ast) = source.name() else { continue };
             // FIXME: macros
@@ -33,6 +43,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
             use_range,
         )])
     })();
+
     Some(
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
@@ -42,7 +53,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
                 "cannot mutate immutable variable `{}`",
                 d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition)
             ),
-            d.span,
+            span,
         )
         .with_fixes(fixes),
     )
@@ -53,10 +64,6 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
 // This diagnostic is triggered when a mutable variable isn't actually mutated.
 pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Option<Diagnostic> {
     let ast = d.local.primary_source(ctx.sema.db).syntax_ptr();
-    if ast.file_id.macro_file().is_some() {
-        // FIXME: Our infra can't handle allow from within macro expansions rn
-        return None;
-    }
     let fixes = (|| {
         let file_id = ast.file_id.file_id()?;
         let mut edit_builder = TextEdit::builder();
@@ -937,7 +944,6 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
 
     #[test]
     fn closure() {
-        // FIXME: Diagnostic spans are inconsistent inside and outside closure
         check_diagnostics(
             r#"
         //- minicore: copy, fn
@@ -950,11 +956,11 @@ fn fn_once(mut x: impl FnOnce(u8) -> u8) -> u8 {
         fn f() {
             let x = 5;
             let closure1 = || { x = 2; };
-                              //^ 💡 error: cannot mutate immutable variable `x`
+                              //^^^^^ 💡 error: cannot mutate immutable variable `x`
             let _ = closure1();
                   //^^^^^^^^ 💡 error: cannot mutate immutable variable `closure1`
             let closure2 = || { x = x; };
-                              //^ 💡 error: cannot mutate immutable variable `x`
+                              //^^^^^ 💡 error: cannot mutate immutable variable `x`
             let closure3 = || {
                 let x = 2;
                 x = 5;
@@ -996,7 +1002,7 @@ fn f() {
             || {
                 let x = 2;
                 || { || { x = 5; } }
-                        //^ 💡 error: cannot mutate immutable variable `x`
+                        //^^^^^ 💡 error: cannot mutate immutable variable `x`
             }
         }
     };
@@ -1283,4 +1289,19 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn destructuring_assignment_needs_mut() {
+        check_diagnostics(
+            r#"
+//- minicore: fn
+
+fn main() {
+	let mut var = 1;
+	let mut func = || (var,) = (2,);
+	func();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index dfadef11fde..e5d871975b6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,11 +1,11 @@
 use either::Either;
 use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, RootDatabase};
 use syntax::{
     ast::{self, edit::IndentLevel, make},
     AstNode,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
index 62bc1f3d06f..c8e3cff364a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -1,7 +1,7 @@
 use hir::{db::ExpandDatabase, diagnostics::RemoveTrailingReturn, FileRange};
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use syntax::{ast, AstNode};
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
index 448df1ca163..a46c48608f7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -1,4 +1,5 @@
 use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt};
+use ide_db::text_edit::TextEdit;
 use ide_db::{assists::Assist, source_change::SourceChange};
 use itertools::Itertools;
 use syntax::{
@@ -8,7 +9,6 @@ use syntax::{
     },
     AstNode, SyntaxToken, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{
     adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 18647206236..f481365f2a5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -1,10 +1,10 @@
 use hir::{db::ExpandDatabase, HirFileIdExt, InFile};
 use ide_db::source_change::SourceChange;
+use ide_db::text_edit::TextEdit;
 use syntax::{
     ast::{self, HasArgList},
     AstNode, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index 3de51ca4a30..1363a8ff0dd 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -1,11 +1,11 @@
 use hir::{db::ExpandDatabase, HasSource, HirDisplay};
+use ide_db::text_edit::TextRange;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
     source_change::SourceChangeBuilder,
 };
 use syntax::ToSmolStr;
-use text_edit::TextRange;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 90f88d6705b..93fe9374a3e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,6 @@
 use either::Either;
 use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
 use syntax::{
     ast::{
@@ -9,7 +10,6 @@ use syntax::{
     },
     AstNode, AstPtr, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 6994a7ed146..3ad84f7bda2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -3,13 +3,13 @@ use hir::{
     term_search::{term_search, TermSearchConfig, TermSearchCtx},
     ClosureStyle, HirDisplay, ImportPathConfig,
 };
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, GroupLabel},
     label::Label,
     source_change::SourceChange,
 };
 use itertools::Itertools;
-use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
index 6af36fb9e73..d16bfb80024 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs
@@ -107,4 +107,34 @@ async fn foo() {
 "#,
         );
     }
+
+    #[test]
+    fn macro_expansion_can_refer_label_defined_before_macro_definition() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    'bar: loop {
+        macro_rules! m {
+            () => { break 'bar };
+        }
+        m!();
+    }
+}
+"#,
+        );
+        check_diagnostics(
+            r#"
+fn foo() {
+    'bar: loop {
+        macro_rules! m {
+            () => { break 'bar };
+        }
+        'bar: loop {
+            m!();
+        }
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index e0822fc5b33..13591dfb2ee 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -3,6 +3,7 @@
 use std::iter;
 
 use hir::{db::DefDatabase, DefMap, InFile, ModuleSource};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     base_db::{FileLoader, SourceDatabase, SourceRootDatabase},
     source_change::SourceChange,
@@ -13,7 +14,6 @@ use syntax::{
     ast::{self, edit::IndentLevel, HasModuleItem, HasName},
     AstNode, TextRange,
 };
-use text_edit::TextEdit;
 
 use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 76d624c47ab..656bedff1a8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     helpers::is_editable_crate,
@@ -16,7 +17,6 @@ use syntax::{
     ast::{edit::AstNodeEdit, Type},
     SyntaxNode,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
index 9a81682aaeb..68f14a97f59 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_ident.rs
@@ -11,7 +11,7 @@ pub(crate) fn unresolved_ident(
         ctx,
         DiagnosticCode::RustcHardError("E0425"),
         "no such value in this scope",
-        d.expr.map(Into::into),
+        d.expr_or_pat.map(Into::into),
     )
     .experimental()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 5b596123e75..0d1c9775062 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -82,4 +82,29 @@ self::m!(); self::m2!();
 "#,
         );
     }
+
+    #[test]
+    fn no_unresolved_panic_inside_mod_inside_fn() {
+        check_diagnostics(
+            r#"
+//- /core.rs library crate:core
+#[macro_export]
+macro_rules! panic {
+    () => {};
+}
+
+//- /lib.rs crate:foo deps:core
+#[macro_use]
+extern crate core;
+
+fn foo() {
+    mod init {
+        pub fn init() {
+            panic!();
+        }
+    }
+}
+    "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index c0d038a238b..81cb4521218 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -1,4 +1,5 @@
 use hir::{db::ExpandDatabase, AssocItem, FileRange, HirDisplay, InFile};
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
@@ -8,7 +9,6 @@ use syntax::{
     ast::{self, make, HasArgList},
     format_smolstr, AstNode, SmolStr, TextRange, ToSmolStr,
 };
-use text_edit::TextEdit;
 
 use crate::{adjusted_display_range, Diagnostic, DiagnosticCode, DiagnosticsContext};
 
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 84007b16aa6..67ece566941 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
@@ -1,4 +1,5 @@
 use hir::Name;
+use ide_db::text_edit::TextEdit;
 use ide_db::{
     assists::{Assist, AssistId, AssistKind},
     label::Label,
@@ -6,7 +7,6 @@ use ide_db::{
     FileRange, RootDatabase,
 };
 use syntax::{Edition, TextRange};
-use text_edit::TextEdit;
 
 use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 2d380ae0457..e5c2eca171a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -1,8 +1,8 @@
 use hir::InFile;
+use ide_db::text_edit::TextEdit;
 use ide_db::{source_change::SourceChange, EditionedFileId, FileRange};
 use itertools::Itertools;
 use syntax::{ast, AstNode, SyntaxNode, SyntaxNodePtr};
-use text_edit::TextEdit;
 
 use crate::{fix, Diagnostic, DiagnosticCode};
 
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index fad62fa3b96..25614676288 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -24,7 +24,6 @@ ide-db.workspace = true
 parser.workspace = true
 stdx.workspace = true
 syntax.workspace = true
-text-edit.workspace = true
 
 [dev-dependencies]
 expect-test = "1.4.0"
@@ -34,4 +33,4 @@ test-utils.workspace = true
 test-fixture.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 54236ea8bc4..eaca95d98c2 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -84,10 +84,10 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc
 
 use crate::{errors::bail, matching::MatchFailureReason};
 use hir::{FileRange, Semantics};
+use ide_db::text_edit::TextEdit;
 use ide_db::{base_db::SourceDatabase, EditionedFileId, FileId, FxHashMap, RootDatabase};
 use resolving::ResolvedRule;
 use syntax::{ast, AstNode, SyntaxNode, TextRange};
-use text_edit::TextEdit;
 
 // A structured search replace rule. Create by calling `parse` on a str.
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
index e752ee3d775..ea40d5b815e 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
@@ -190,7 +190,7 @@ impl RawPattern {
         let mut res = FxHashMap::default();
         for t in &self.tokens {
             if let PatternElement::Placeholder(placeholder) = t {
-                res.insert(SmolStr::new(placeholder.stand_in_name.clone()), placeholder.clone());
+                res.insert(SmolStr::new(&placeholder.stand_in_name), placeholder.clone());
             }
         }
         res
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
index 65756601f66..11c1615a560 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs
@@ -1,5 +1,6 @@
 //! Code for applying replacement templates for matches that have previously been found.
 
+use ide_db::text_edit::TextEdit;
 use ide_db::{FxHashMap, FxHashSet};
 use itertools::Itertools;
 use parser::Edition;
@@ -7,7 +8,6 @@ use syntax::{
     ast::{self, AstNode, AstToken},
     SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize,
 };
-use text_edit::TextEdit;
 
 use crate::{fragments, resolving::ResolvedRule, Match, SsrMatches};
 
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index d976d604f1a..7c66b36dc8e 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -39,7 +39,6 @@ profile.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 span.workspace = true
-text-edit.workspace = true
 # ide should depend only on the top-level `hir` package. if you need
 # something from some `hir-xxx` subpackage, reexport the API via `hir`.
 hir.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
index 1b82c00d1dc..e5b4ed17b2a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs
@@ -510,6 +510,7 @@ fn caller$0() {
             expect![[]],
         );
     }
+
     #[test]
     fn test_call_hierarchy_in_macros_incoming_different_files() {
         check_hierarchy(
@@ -591,9 +592,9 @@ macro_rules! call {
 "#,
             expect!["callee Function FileId(0) 22..37 30..36"],
             expect![[r#"
-                callee Function FileId(0) 38..52 44..50 : FileId(0):44..50
                 caller Function FileId(0) 38..52 : FileId(0):44..50
-                caller Function FileId(1) 130..136 130..136 : FileId(0):44..50"#]],
+                caller Function FileId(1) 130..136 130..136 : FileId(0):44..50
+                callee Function FileId(0) 38..52 44..50 : FileId(0):44..50"#]],
             expect![[]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 92458185849..055080ad17b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -187,6 +187,24 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
                 };
                 Some(node)
             },
+            ast::LetStmt(it) => {
+                let pat = it.pat()?;
+
+                let mut label = String::new();
+                collapse_ws(pat.syntax(), &mut label);
+
+                let node = StructureNode {
+                    parent: None,
+                    label,
+                    navigation_range: pat.syntax().text_range(),
+                    node_range: it.syntax().text_range(),
+                    kind: StructureNodeKind::SymbolKind(SymbolKind::Local),
+                    detail: it.ty().map(|ty| ty.to_string()),
+                    deprecated: false,
+                };
+
+                Some(node)
+            },
             ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
             _ => None,
         }
@@ -308,6 +326,17 @@ fn f() {}
 // endregion
 fn g() {}
 }
+
+fn let_statements() {
+    let x = 42;
+    let mut y = x;
+    let Foo {
+        ..
+    } = Foo { x };
+    if let None = Some(x) {}
+    _ = ();
+    let _ = g();
+}
 "#,
             expect![[r#"
                 [
@@ -633,6 +662,71 @@ fn g() {}
                         ),
                         deprecated: false,
                     },
+                    StructureNode {
+                        parent: None,
+                        label: "let_statements",
+                        navigation_range: 641..655,
+                        node_range: 638..798,
+                        kind: SymbolKind(
+                            Function,
+                        ),
+                        detail: Some(
+                            "fn()",
+                        ),
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "x",
+                        navigation_range: 668..669,
+                        node_range: 664..675,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "mut y",
+                        navigation_range: 684..689,
+                        node_range: 680..694,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "Foo { .. }",
+                        navigation_range: 703..725,
+                        node_range: 699..738,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: Some(
+                            26,
+                        ),
+                        label: "_",
+                        navigation_range: 788..789,
+                        node_range: 784..796,
+                        kind: SymbolKind(
+                            Local,
+                        ),
+                        detail: None,
+                        deprecated: false,
+                    },
                 ]
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 4cbcb6ed050..363f852e0e4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -13,7 +13,6 @@ use ide_db::{
     RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
-
 use span::{Edition, FileId};
 use syntax::{
     ast::{self, HasLoopBody},
@@ -99,6 +98,7 @@ pub(crate) fn goto_definition(
                     return Some(vec![x]);
                 }
             }
+
             Some(
                 IdentClass::classify_node(sema, &parent)?
                     .definitions()
@@ -418,10 +418,10 @@ fn expr_to_nav(
 
 #[cfg(test)]
 mod tests {
+    use crate::fixture;
     use ide_db::FileRange;
     use itertools::Itertools;
-
-    use crate::fixture;
+    use syntax::SmolStr;
 
     #[track_caller]
     fn check(ra_fixture: &str) {
@@ -450,6 +450,170 @@ mod tests {
         assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}")
     }
 
+    fn check_name(expected_name: &str, ra_fixture: &str) {
+        let (analysis, position, _) = fixture::annotations(ra_fixture);
+        let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len());
+        let Some(target) = navs.into_iter().next() else {
+            panic!("expected single navigation target but encountered none");
+        };
+        assert_eq!(target.name, SmolStr::new_inline(expected_name));
+    }
+
+    #[test]
+    fn goto_def_pat_range_to_inclusive() {
+        check_name(
+            "RangeToInclusive",
+            r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+    match ch {
+        ..$0='z' => true,
+        _ => false
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_pat_range_to() {
+        check_name(
+            "RangeTo",
+            r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+    match ch {
+        .$0.'z' => true,
+        _ => false
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_pat_range() {
+        check_name(
+            "Range",
+            r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+    match ch {
+        'a'.$0.'z' => true,
+        _ => false
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_pat_range_inclusive() {
+        check_name(
+            "RangeInclusive",
+            r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+    match ch {
+        'a'..$0='z' => true,
+        _ => false
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_pat_range_from() {
+        check_name(
+            "RangeFrom",
+            r#"
+//- minicore: range
+fn f(ch: char) -> bool {
+    match ch {
+        'a'..$0 => true,
+        _ => false
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range() {
+        check_name(
+            "Range",
+            r#"
+//- minicore: range
+let x = 0.$0.1;
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range_from() {
+        check_name(
+            "RangeFrom",
+            r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+    &arr[0.$0.]
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range_inclusive() {
+        check_name(
+            "RangeInclusive",
+            r#"
+//- minicore: range
+let x = 0.$0.=1;
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range_full() {
+        check_name(
+            "RangeFull",
+            r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+    &arr[.$0.]
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range_to() {
+        check_name(
+            "RangeTo",
+            r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+    &arr[.$0.10]
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_expr_range_to_inclusive() {
+        check_name(
+            "RangeToInclusive",
+            r#"
+//- minicore: range
+fn f(arr: &[i32]) -> &[i32] {
+    &arr[.$0.=10]
+}
+"#,
+        );
+    }
+
     #[test]
     fn goto_def_in_included_file() {
         check(
@@ -2838,4 +3002,24 @@ use foo::m;
 "#,
         );
     }
+
+    #[test]
+    fn macro_label_hygiene() {
+        check(
+            r#"
+macro_rules! m {
+    ($x:stmt) => {
+        'bar: loop { $x }
+    };
+}
+
+fn foo() {
+    'bar: loop {
+ // ^^^^
+        m!(continue 'bar$0);
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 124db2985bf..6cac4f1ee48 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -11,7 +11,7 @@ use ide_db::{
     defs::{Definition, IdentClass, NameRefClass, OperatorClass},
     famous_defs::FamousDefs,
     helpers::pick_best_token,
-    FileRange, FxIndexSet, RootDatabase,
+    FileRange, FxIndexSet, Ranker, RootDatabase,
 };
 use itertools::{multizip, Itertools};
 use span::Edition;
@@ -182,27 +182,13 @@ fn hover_offset(
     // equivalency is more important
     let mut descended = sema.descend_into_macros(original_token.clone());
 
-    let kind = original_token.kind();
-    let text = original_token.text();
-    let ident_kind = kind.is_any_identifier();
-
-    descended.sort_by_cached_key(|tok| {
-        let tok_kind = tok.kind();
-
-        let exact_same_kind = tok_kind == kind;
-        let both_idents = exact_same_kind || (tok_kind.is_any_identifier() && ident_kind);
-        let same_text = tok.text() == text;
-        // anything that mapped into a token tree has likely no semantic information
-        let no_tt_parent = tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE);
-        !((both_idents as usize)
-            | ((exact_same_kind as usize) << 1)
-            | ((same_text as usize) << 2)
-            | ((no_tt_parent as usize) << 3))
-    });
+    let ranker = Ranker::from_token(&original_token);
+
+    descended.sort_by_cached_key(|tok| !ranker.rank_token(tok));
 
     let mut res = vec![];
     for token in descended {
-        let is_same_kind = token.kind() == kind;
+        let is_same_kind = token.kind() == ranker.kind;
         let lint_hover = (|| {
             // FIXME: Definition should include known lints and the like instead of having this special case here
             let attr = token.parent_ancestors().find_map(ast::Attr::cast)?;
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 01fa316d5fc..a31b14dbd3e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1042,7 +1042,7 @@ fn render_dyn_compatibility(
         }
         DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
             let name = hir::Trait::from(super_trait).name(db);
-            format_to!(buf, "has a object unsafe supertrait `{}`", name.as_str());
+            format_to!(buf, "has a dyn incompatible supertrait `{}`", name.as_str());
         }
     }
 }
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 81397b07855..3e402630419 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -289,7 +289,7 @@ m!(ab$0c);
             *abc*
 
             ```rust
-            test::module
+            test
             ```
 
             ```rust
@@ -298,11 +298,11 @@ m!(ab$0c);
 
             ---
 
-            Inner
+            Outer
             ---
 
             ```rust
-            test
+            test::module
             ```
 
             ```rust
@@ -311,7 +311,7 @@ m!(ab$0c);
 
             ---
 
-            Outer
+            Inner
         "#]],
     );
 }
@@ -9018,3 +9018,156 @@ foo!(BAR_$0);
         "#]],
     );
 }
+
+#[test]
+fn type_alias_without_docs() {
+    // Simple.
+    check(
+        r#"
+/// Docs for B
+struct B;
+
+type A$0 = B;
+"#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            type A = B
+            ```
+
+            ---
+
+            *This is the documentation for* `struct B`
+
+            Docs for B
+        "#]],
+    );
+
+    // Nested.
+    check(
+        r#"
+/// Docs for C
+struct C;
+
+type B = C;
+
+type A$0 = B;
+"#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            type A = B
+            ```
+
+            ---
+
+            *This is the documentation for* `struct C`
+
+            Docs for C
+        "#]],
+    );
+
+    // Showing the docs for aliased struct instead of intermediate type.
+    check(
+        r#"
+/// Docs for C
+struct C;
+
+/// Docs for B
+type B = C;
+
+type A$0 = B;
+"#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            type A = B
+            ```
+
+            ---
+
+            *This is the documentation for* `struct C`
+
+            Docs for C
+        "#]],
+    );
+
+    // No docs found.
+    check(
+        r#"
+struct C;
+
+type B = C;
+
+type A$0 = B;
+"#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            type A = B
+            ```
+        "#]],
+    );
+
+    // Multiple nested crate.
+    check(
+        r#"
+//- /lib.rs crate:c
+/// Docs for C
+pub struct C;
+
+//- /lib.rs crate:b deps:c
+pub use c::C;
+pub type B = C;
+
+//- /lib.rs crate:a deps:b
+pub use b::B;
+pub type A = B;
+
+//- /main.rs crate:main deps:a
+use a::A$0;
+"#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            a
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            pub type A = B
+            ```
+
+            ---
+
+            *This is the documentation for* `pub struct C`
+
+            Docs for C
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 97e712356b5..c58ca0f01cd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -8,6 +8,7 @@ use hir::{
     sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef,
     ModuleDefId, Semantics,
 };
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase};
 use itertools::Itertools;
 use smallvec::{smallvec, SmallVec};
@@ -17,7 +18,6 @@ use syntax::{
     ast::{self, AstNode, HasGenericParams},
     format_smolstr, match_ast, SmolStr, SyntaxNode, TextRange, TextSize, WalkEvent,
 };
-use text_edit::TextEdit;
 
 use crate::{navigation_target::TryToNav, FileId};
 
@@ -410,19 +410,6 @@ impl InlayHint {
         }
     }
 
-    fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
-        InlayHint {
-            range,
-            kind,
-            label: InlayHintLabel::from("("),
-            text_edit: None,
-            position: InlayHintPosition::Before,
-            pad_left: false,
-            pad_right: false,
-            resolve_parent: None,
-        }
-    }
-
     pub fn needs_resolve(&self) -> Option<TextRange> {
         self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve())
     }
@@ -475,6 +462,18 @@ impl InlayHintLabel {
         }
     }
 
+    pub fn append_part(&mut self, part: InlayHintLabelPart) {
+        if part.linked_location.is_none() && part.tooltip.is_none() {
+            if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) =
+                self.parts.last_mut()
+            {
+                text.push_str(&part.text);
+                return;
+            }
+        }
+        self.parts.push(part);
+    }
+
     pub fn needs_resolve(&self) -> bool {
         self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some())
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index c37c469dff4..4d7d6e270e0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,12 +3,15 @@
 //! let _: u32  = /* <never-to-any> */ loop {};
 //! let _: &u32 = /* &* */ &mut 0;
 //! ```
+use std::ops::Not;
+
 use either::Either;
 use hir::{
     Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
 };
 use ide_db::famous_defs::FamousDefs;
 
+use ide_db::text_edit::TextEditBuilder;
 use span::EditionedFileId;
 use stdx::never;
 use syntax::{
@@ -17,8 +20,8 @@ use syntax::{
 };
 
 use crate::{
-    AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
-    InlayHintsConfig, InlayKind, InlayTooltip,
+    AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
+    InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip,
 };
 
 pub(super) fn hints(
@@ -51,32 +54,47 @@ pub(super) fn hints(
     let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
 
     if let ast::Expr::BlockExpr(_) | ast::Expr::IfExpr(_) | ast::Expr::MatchExpr(_) = desc_expr {
-        if let [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), source: _, target }] =
-            &*adjustments
-        {
-            // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
-            if source == target {
-                return None;
-            }
+        // Don't show unnecessary reborrows for these, they will just repeat the inner ones again
+        if matches!(
+            &*adjustments,
+            [Adjustment { kind: Adjust::Deref(_), source, .. }, Adjustment { kind: Adjust::Borrow(_), target, .. }]
+            if source == target
+        ) {
+            return None;
         }
     }
 
     let (postfix, needs_outer_parens, needs_inner_parens) =
         mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
 
-    if needs_outer_parens {
-        acc.push(InlayHint::opening_paren_before(
-            InlayKind::Adjustment,
-            expr.syntax().text_range(),
-        ));
+    let range = expr.syntax().text_range();
+    let mut pre = InlayHint {
+        range,
+        position: InlayHintPosition::Before,
+        pad_left: false,
+        pad_right: false,
+        kind: InlayKind::Adjustment,
+        label: InlayHintLabel::default(),
+        text_edit: None,
+        resolve_parent: Some(range),
+    };
+    let mut post = InlayHint {
+        range,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: false,
+        kind: InlayKind::Adjustment,
+        label: InlayHintLabel::default(),
+        text_edit: None,
+        resolve_parent: Some(range),
+    };
+
+    if needs_outer_parens || (postfix && needs_inner_parens) {
+        pre.label.append_str("(");
     }
 
     if postfix && needs_inner_parens {
-        acc.push(InlayHint::opening_paren_before(
-            InlayKind::Adjustment,
-            expr.syntax().text_range(),
-        ));
-        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+        post.label.append_str(")");
     }
 
     let mut iter = if postfix {
@@ -86,6 +104,7 @@ pub(super) fn hints(
     };
     let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
 
+    let mut allow_edit = !postfix;
     for Adjustment { source, target, kind } in iter {
         if source == target {
             cov_mark::hit!(same_type_adjustment);
@@ -95,6 +114,7 @@ pub(super) fn hints(
         // FIXME: Add some nicer tooltips to each of these
         let (text, coercion) = match kind {
             Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+                allow_edit = false;
                 ("<never-to-any>", "never to any")
             }
             Adjust::Deref(None) => ("*", "dereference"),
@@ -115,6 +135,7 @@ pub(super) fn hints(
             // some of these could be represented via `as` casts, but that's not too nice and
             // handling everything as a prefix expr makes the `(` and `)` insertion easier
             Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+                allow_edit = false;
                 match cast {
                     PointerCast::ReifyFnPointer => {
                         ("<fn-item-to-fn-pointer>", "fn item to fn pointer")
@@ -138,36 +159,58 @@ pub(super) fn hints(
             }
             _ => continue,
         };
-        let label = InlayHintLabel::simple(
-            if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
-            Some(InlayTooltip::Markdown(format!(
+        let label = InlayHintLabelPart {
+            text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
+            linked_location: None,
+            tooltip: Some(InlayTooltip::Markdown(format!(
                 "`{}` → `{}` ({coercion} coercion)",
                 source.display(sema.db, file_id.edition()),
                 target.display(sema.db, file_id.edition()),
             ))),
-            None,
-        );
-        acc.push(InlayHint {
-            range: expr.syntax().text_range(),
-            pad_left: false,
-            pad_right: false,
-            position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
-            kind: InlayKind::Adjustment,
-            label,
-            text_edit: None,
-            resolve_parent: Some(expr.syntax().text_range()),
-        });
+        };
+        if postfix { &mut post } else { &mut pre }.label.append_part(label);
     }
     if !postfix && needs_inner_parens {
-        acc.push(InlayHint::opening_paren_before(
-            InlayKind::Adjustment,
-            expr.syntax().text_range(),
-        ));
-        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+        pre.label.append_str("(");
+    }
+    if needs_outer_parens || (!postfix && needs_inner_parens) {
+        post.label.append_str(")");
     }
-    if needs_outer_parens {
-        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
+
+    let mut pre = pre.label.parts.is_empty().not().then_some(pre);
+    let mut post = post.label.parts.is_empty().not().then_some(post);
+    if pre.is_none() && post.is_none() {
+        return None;
     }
+    if allow_edit {
+        let edit = {
+            let mut b = TextEditBuilder::default();
+            if let Some(pre) = &pre {
+                b.insert(
+                    pre.range.start(),
+                    pre.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+                );
+            }
+            if let Some(post) = &post {
+                b.insert(
+                    post.range.end(),
+                    post.label.parts.iter().map(|part| &*part.text).collect::<String>(),
+                );
+            }
+            b.finish()
+        };
+        match (&mut pre, &mut post) {
+            (Some(pre), Some(post)) => {
+                pre.text_edit = Some(edit.clone());
+                post.text_edit = Some(edit);
+            }
+            (Some(pre), None) => pre.text_edit = Some(edit),
+            (None, Some(post)) => post.text_edit = Some(edit),
+            (None, None) => (),
+        }
+    }
+    acc.extend(pre);
+    acc.extend(post);
     Some(())
 }
 
@@ -293,25 +336,19 @@ fn main() {
     let _: u32         = loop {};
                        //^^^^^^^<never-to-any>
     let _: &u32        = &mut 0;
-                       //^^^^^^&
-                       //^^^^^^*
+                       //^^^^^^&*
     let _: &mut u32    = &mut 0;
-                       //^^^^^^&mut $
-                       //^^^^^^*
+                       //^^^^^^&mut *
     let _: *const u32  = &mut 0;
-                       //^^^^^^&raw const $
-                       //^^^^^^*
+                       //^^^^^^&raw const *
     let _: *mut u32    = &mut 0;
-                       //^^^^^^&raw mut $
-                       //^^^^^^*
+                       //^^^^^^&raw mut *
     let _: fn()        = main;
                        //^^^^<fn-item-to-fn-pointer>
     let _: unsafe fn() = main;
-                       //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
-                       //^^^^<fn-item-to-fn-pointer>
+                       //^^^^<safe-fn-pointer-to-unsafe-fn-pointer><fn-item-to-fn-pointer>
     let _: unsafe fn() = main as fn();
-                       //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
-                       //^^^^^^^^^^^^(
+                       //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>(
                        //^^^^^^^^^^^^)
                        //^^^^<fn-item-to-fn-pointer>
     let _: fn()        = || {};
@@ -319,72 +356,51 @@ fn main() {
     let _: unsafe fn() = || {};
                        //^^^^^<closure-to-unsafe-fn-pointer>
     let _: *const u32  = &mut 0u32 as *mut u32;
-                       //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
-                       //^^^^^^^^^^^^^^^^^^^^^(
+                       //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>(
                        //^^^^^^^^^^^^^^^^^^^^^)
-                       //^^^^^^^^^&raw mut $
-                       //^^^^^^^^^*
+                       //^^^^^^^^^&raw mut *
     let _: &mut [_]    = &mut [0; 0];
-                       //^^^^^^^^^^^<unsize>
-                       //^^^^^^^^^^^&mut $
-                       //^^^^^^^^^^^*
+                       //^^^^^^^^^^^<unsize>&mut *
 
     Struct.consume();
     Struct.by_ref();
-  //^^^^^^(
-  //^^^^^^&
+  //^^^^^^(&
   //^^^^^^)
     Struct.by_ref_mut();
-  //^^^^^^(
-  //^^^^^^&mut $
+  //^^^^^^(&mut $
   //^^^^^^)
 
     (&Struct).consume();
    //^^^^^^^*
     (&Struct).by_ref();
-   //^^^^^^^&
-   //^^^^^^^*
+   //^^^^^^^&*
 
     (&mut Struct).consume();
    //^^^^^^^^^^^*
     (&mut Struct).by_ref();
-   //^^^^^^^^^^^&
-   //^^^^^^^^^^^*
+   //^^^^^^^^^^^&*
     (&mut Struct).by_ref_mut();
-   //^^^^^^^^^^^&mut $
-   //^^^^^^^^^^^*
+   //^^^^^^^^^^^&mut *
 
     // Check that block-like expressions don't duplicate hints
     let _: &mut [u32] = (&mut []);
-                       //^^^^^^^<unsize>
-                       //^^^^^^^&mut $
-                       //^^^^^^^*
+                       //^^^^^^^<unsize>&mut *
     let _: &mut [u32] = { &mut [] };
-                        //^^^^^^^<unsize>
-                        //^^^^^^^&mut $
-                        //^^^^^^^*
+                        //^^^^^^^<unsize>&mut *
     let _: &mut [u32] = unsafe { &mut [] };
-                               //^^^^^^^<unsize>
-                               //^^^^^^^&mut $
-                               //^^^^^^^*
+                               //^^^^^^^<unsize>&mut *
     let _: &mut [u32] = if true {
         &mut []
-      //^^^^^^^<unsize>
-      //^^^^^^^&mut $
-      //^^^^^^^*
+      //^^^^^^^<unsize>&mut *
     } else {
         loop {}
       //^^^^^^^<never-to-any>
     };
     let _: &mut [u32] = match () { () => &mut [] };
-                                       //^^^^^^^<unsize>
-                                       //^^^^^^^&mut $
-                                       //^^^^^^^*
+                                       //^^^^^^^<unsize>&mut *
 
     let _: &mut dyn Fn() = &mut || ();
-                         //^^^^^^^^^^<unsize>
-                         //^^^^^^^^^^&mut $
-                         //^^^^^^^^^^*
+                         //^^^^^^^^^^<unsize>&mut *
     () == ();
  // ^^&
        // ^^&
@@ -393,16 +409,13 @@ fn main() {
          // ^^^^&
     let closure: dyn Fn = || ();
     closure();
-  //^^^^^^^(
-  //^^^^^^^&
+  //^^^^^^^(&
   //^^^^^^^)
     Struct[0];
-  //^^^^^^(
-  //^^^^^^&
+  //^^^^^^(&
   //^^^^^^)
     &mut Struct[0];
-       //^^^^^^(
-       //^^^^^^&mut $
+       //^^^^^^(&mut $
        //^^^^^^)
 }
 
@@ -442,72 +455,46 @@ fn main() {
 
     (&Struct).consume();
    //^^^^^^^(
-   //^^^^^^^)
-   //^^^^^^^.*
+   //^^^^^^^).*
     (&Struct).by_ref();
    //^^^^^^^(
-   //^^^^^^^)
-   //^^^^^^^.*
-   //^^^^^^^.&
+   //^^^^^^^).*.&
 
     (&mut Struct).consume();
    //^^^^^^^^^^^(
-   //^^^^^^^^^^^)
-   //^^^^^^^^^^^.*
+   //^^^^^^^^^^^).*
     (&mut Struct).by_ref();
    //^^^^^^^^^^^(
-   //^^^^^^^^^^^)
-   //^^^^^^^^^^^.*
-   //^^^^^^^^^^^.&
+   //^^^^^^^^^^^).*.&
     (&mut Struct).by_ref_mut();
    //^^^^^^^^^^^(
-   //^^^^^^^^^^^)
-   //^^^^^^^^^^^.*
-   //^^^^^^^^^^^.&mut
+   //^^^^^^^^^^^).*.&mut
 
     // Check that block-like expressions don't duplicate hints
     let _: &mut [u32] = (&mut []);
                        //^^^^^^^(
-                       //^^^^^^^)
-                       //^^^^^^^.*
-                       //^^^^^^^.&mut
-                       //^^^^^^^.<unsize>
+                       //^^^^^^^).*.&mut.<unsize>
     let _: &mut [u32] = { &mut [] };
                         //^^^^^^^(
-                        //^^^^^^^)
-                        //^^^^^^^.*
-                        //^^^^^^^.&mut
-                        //^^^^^^^.<unsize>
+                        //^^^^^^^).*.&mut.<unsize>
     let _: &mut [u32] = unsafe { &mut [] };
                                //^^^^^^^(
-                               //^^^^^^^)
-                               //^^^^^^^.*
-                               //^^^^^^^.&mut
-                               //^^^^^^^.<unsize>
+                               //^^^^^^^).*.&mut.<unsize>
     let _: &mut [u32] = if true {
         &mut []
       //^^^^^^^(
-      //^^^^^^^)
-      //^^^^^^^.*
-      //^^^^^^^.&mut
-      //^^^^^^^.<unsize>
+      //^^^^^^^).*.&mut.<unsize>
     } else {
         loop {}
       //^^^^^^^.<never-to-any>
     };
     let _: &mut [u32] = match () { () => &mut [] };
                                        //^^^^^^^(
-                                       //^^^^^^^)
-                                       //^^^^^^^.*
-                                       //^^^^^^^.&mut
-                                       //^^^^^^^.<unsize>
+                                       //^^^^^^^).*.&mut.<unsize>
 
     let _: &mut dyn Fn() = &mut || ();
                          //^^^^^^^^^^(
-                         //^^^^^^^^^^)
-                         //^^^^^^^^^^.*
-                         //^^^^^^^^^^.&mut
-                         //^^^^^^^^^^.<unsize>
+                         //^^^^^^^^^^).*.&mut.<unsize>
     () == ();
  // ^^.&
        // ^^.&
@@ -619,9 +606,7 @@ fn or_else() {
             r#"
 unsafe fn enabled() {
     f(&&());
-    //^^^^&
-    //^^^^*
-    //^^^^*
+    //^^^^&**
 }
 
 fn disabled() {
@@ -633,9 +618,7 @@ fn mixed() {
 
     unsafe {
         f(&&());
-        //^^^^&
-        //^^^^*
-        //^^^^*
+        //^^^^&**
     }
 }
 
@@ -644,9 +627,7 @@ const _: () = {
 
     unsafe {
         f(&&());
-        //^^^^&
-        //^^^^*
-        //^^^^*
+        //^^^^&**
     }
 };
 
@@ -655,18 +636,14 @@ static STATIC: () = {
 
     unsafe {
         f(&&());
-        //^^^^&
-        //^^^^*
-        //^^^^*
+        //^^^^&**
     }
 };
 
 enum E {
     Disable = { f(&&()); 0 },
     Enable = unsafe { f(&&()); 1 },
-                      //^^^^&
-                      //^^^^*
-                      //^^^^*
+                      //^^^^&**
 }
 
 const fn f(_: &()) {}
@@ -692,8 +669,7 @@ fn a() {
     _ = Struct.by_ref();
 
     _ = unsafe { Struct.by_ref() };
-               //^^^^^^(
-               //^^^^^^&
+               //^^^^^^(&
                //^^^^^^)
 }
             "#,
@@ -726,10 +702,7 @@ trait T<RHS = Self> {}
 
 fn hello(it: &&[impl T]) {
     it.len();
-  //^^(
-  //^^&
-  //^^*
-  //^^*
+  //^^(&**
   //^^)
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index d1c0677863d..cfe8657fd05 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -2,13 +2,16 @@
 //! ```no_run
 //! let /* & */ (/* ref */ x,) = &(0,);
 //! ```
+use std::mem;
+
 use hir::Mutability;
 use ide_db::famous_defs::FamousDefs;
 
+use ide_db::text_edit::TextEditBuilder;
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode};
 
-use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -21,16 +24,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let outer_paren_pat = pat
-        .syntax()
-        .ancestors()
-        .skip(1)
-        .map_while(ast::Pat::cast)
-        .map_while(|pat| match pat {
-            ast::Pat::ParenPat(pat) => Some(pat),
-            _ => None,
-        })
-        .last();
+    let outer_paren_pat = pat.syntax().ancestors().skip(1).map_while(ast::ParenPat::cast).last();
     let range = outer_paren_pat.as_ref().map_or_else(
         || match pat {
             // for ident patterns that @ bind a name, render the un-ref patterns in front of the inner pattern
@@ -42,7 +36,18 @@ pub(super) fn hints(
         },
         |it| it.syntax().text_range(),
     );
+    let mut hint = InlayHint {
+        range,
+        kind: InlayKind::BindingMode,
+        label: InlayHintLabel::default(),
+        text_edit: None,
+        position: InlayHintPosition::Before,
+        pad_left: false,
+        pad_right: false,
+        resolve_parent: Some(pat.syntax().text_range()),
+    };
     let pattern_adjustments = sema.pattern_adjustments(pat);
+    let mut was_mut_last = false;
     pattern_adjustments.iter().for_each(|ty| {
         let reference = ty.is_reference();
         let mut_reference = ty.is_mutable_reference();
@@ -51,41 +56,36 @@ pub(super) fn hints(
             (true, false) => "&",
             _ => return,
         };
-        acc.push(InlayHint {
-            range,
-            kind: InlayKind::BindingMode,
-            label: r.into(),
-            text_edit: None,
-            position: InlayHintPosition::Before,
-            pad_left: false,
-            pad_right: mut_reference,
-            resolve_parent: Some(pat.syntax().text_range()),
-        });
+        if mem::replace(&mut was_mut_last, mut_reference) {
+            hint.label.append_str(" ");
+        }
+        hint.label.append_str(r);
     });
+    hint.pad_right = was_mut_last;
+    let acc_base = acc.len();
     match pat {
         ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
             let bm = sema.binding_mode_of_pat(pat)?;
             let bm = match bm {
-                hir::BindingMode::Move => return None,
-                hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
-                hir::BindingMode::Ref(Mutability::Shared) => "ref",
+                hir::BindingMode::Move => None,
+                hir::BindingMode::Ref(Mutability::Mut) => Some("ref mut"),
+                hir::BindingMode::Ref(Mutability::Shared) => Some("ref"),
             };
-            acc.push(InlayHint {
-                range: pat.syntax().text_range(),
-                kind: InlayKind::BindingMode,
-                label: bm.into(),
-                text_edit: None,
-                position: InlayHintPosition::Before,
-                pad_left: false,
-                pad_right: true,
-                resolve_parent: Some(pat.syntax().text_range()),
-            });
+            if let Some(bm) = bm {
+                acc.push(InlayHint {
+                    range: pat.syntax().text_range(),
+                    kind: InlayKind::BindingMode,
+                    label: bm.into(),
+                    text_edit: None,
+                    position: InlayHintPosition::Before,
+                    pad_left: false,
+                    pad_right: true,
+                    resolve_parent: Some(pat.syntax().text_range()),
+                });
+            }
         }
         ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
-            acc.push(InlayHint::opening_paren_before(
-                InlayKind::BindingMode,
-                pat.syntax().text_range(),
-            ));
+            hint.label.append_str("(");
             acc.push(InlayHint::closing_paren_after(
                 InlayKind::BindingMode,
                 pat.syntax().text_range(),
@@ -93,6 +93,24 @@ pub(super) fn hints(
         }
         _ => (),
     }
+    if !hint.label.parts.is_empty() {
+        acc.push(hint);
+    }
+
+    if let hints @ [_, ..] = &mut acc[acc_base..] {
+        let mut edit = TextEditBuilder::default();
+        for h in &mut *hints {
+            edit.insert(
+                match h.position {
+                    InlayHintPosition::Before => h.range.start(),
+                    InlayHintPosition::After => h.range.end(),
+                },
+                h.label.parts.iter().map(|p| &*p.text).collect(),
+            );
+        }
+        let edit = edit.finish();
+        hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone()));
+    }
 
     Some(())
 }
@@ -117,6 +135,13 @@ fn __(
     (x,): &mut (u32,)
   //^^^^&mut
    //^ ref mut
+   (x,): &mut &mut (u32,)
+ //^^^^&mut &mut
+  //^ ref mut
+   (x,): &&(u32,)
+ //^^^^&&
+  //^ ref
+
 ) {
     let (x,) = (0,);
     let (x,) = &(0,);
@@ -136,11 +161,10 @@ fn __(
     }
     match &(0,) {
         (x,) | (x,) => (),
-      //^^^^^^^^^^^&
+      //^^^^^^^^^^^)
+      //^^^^^^^^^^^&(
        //^ ref
               //^ ref
-      //^^^^^^^^^^^(
-      //^^^^^^^^^^^)
         ((x,) | (x,)) => (),
       //^^^^^^^^^^^^^&
         //^ ref
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 58d8f97a8ce..028ed1650f4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -77,7 +77,7 @@ pub(super) fn hints(
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
-    use text_edit::{TextRange, TextSize};
+    use ide_db::text_edit::{TextRange, TextSize};
 
     use crate::{
         fixture,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index f399bd01d07..906f2acf0c4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -2,12 +2,14 @@
 //!
 //! Tests live in [`bind_pat`][super::bind_pat] module.
 use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::{TextRange, TextSize};
 use span::EditionedFileId;
 use stdx::{never, TupleExt};
 use syntax::ast::{self, AstNode};
-use text_edit::{TextRange, TextSize};
 
-use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{
+    InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
+};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -27,34 +29,27 @@ pub(super) fn hints(
         return None;
     }
 
-    let move_kw_range = match closure.move_token() {
-        Some(t) => t.text_range(),
+    let (range, label) = match closure.move_token() {
+        Some(t) => (t.text_range(), InlayHintLabel::default()),
         None => {
-            let range = closure.syntax().first_token()?.prev_token()?.text_range();
-            let range = TextRange::new(range.end() - TextSize::from(1), range.end());
-            acc.push(InlayHint {
-                range,
-                kind: InlayKind::ClosureCapture,
-                label: InlayHintLabel::from("move"),
-                text_edit: None,
-                position: InlayHintPosition::After,
-                pad_left: false,
-                pad_right: false,
-                resolve_parent: Some(closure.syntax().text_range()),
-            });
-            range
+            let prev_token = closure.syntax().first_token()?.prev_token()?.text_range();
+            (
+                TextRange::new(prev_token.end() - TextSize::from(1), prev_token.end()),
+                InlayHintLabel::from("move"),
+            )
         }
     };
-    acc.push(InlayHint {
-        range: move_kw_range,
+    let mut hint = InlayHint {
+        range,
         kind: InlayKind::ClosureCapture,
-        label: InlayHintLabel::from("("),
+        label,
         text_edit: None,
         position: InlayHintPosition::After,
         pad_left: false,
-        pad_right: false,
-        resolve_parent: None,
-    });
+        pad_right: true,
+        resolve_parent: Some(closure.syntax().text_range()),
+    };
+    hint.label.append_str("(");
     let last = captures.len() - 1;
     for (idx, capture) in captures.into_iter().enumerate() {
         let local = capture.local();
@@ -76,48 +71,20 @@ pub(super) fn hints(
         if never!(label.is_empty()) {
             continue;
         }
-        let label = InlayHintLabel::simple(
-            label,
-            None,
-            source.name().and_then(|name| {
+        hint.label.append_part(InlayHintLabelPart {
+            text: label,
+            linked_location: source.name().and_then(|name| {
                 name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into)
             }),
-        );
-        acc.push(InlayHint {
-            range: move_kw_range,
-            kind: InlayKind::ClosureCapture,
-            label,
-            text_edit: None,
-            position: InlayHintPosition::After,
-            pad_left: false,
-            pad_right: false,
-            resolve_parent: Some(closure.syntax().text_range()),
+            tooltip: None,
         });
 
         if idx != last {
-            acc.push(InlayHint {
-                range: move_kw_range,
-                kind: InlayKind::ClosureCapture,
-                label: InlayHintLabel::from(", "),
-                text_edit: None,
-                position: InlayHintPosition::After,
-                pad_left: false,
-                pad_right: false,
-                resolve_parent: None,
-            });
+            hint.label.append_str(", ");
         }
     }
-    acc.push(InlayHint {
-        range: move_kw_range,
-        kind: InlayKind::ClosureCapture,
-        label: InlayHintLabel::from(")"),
-        text_edit: None,
-        position: InlayHintPosition::After,
-        pad_left: false,
-        pad_right: true,
-        resolve_parent: None,
-    });
-
+    hint.label.append_str(")");
+    acc.push(hint);
     Some(())
 }
 
@@ -147,51 +114,25 @@ fn main() {
     let mut baz = NonCopy;
     let qux = &mut NonCopy;
     || {
-// ^ move
-// ^ (
-// ^ &foo
-// ^ , $
-// ^ bar
-// ^ , $
-// ^ baz
-// ^ , $
-// ^ qux
-// ^ )
+// ^ move(&foo, bar, baz, qux)
         foo;
         bar;
         baz;
         qux;
     };
     || {
-// ^ move
-// ^ (
-// ^ &foo
-// ^ , $
-// ^ &bar
-// ^ , $
-// ^ &baz
-// ^ , $
-// ^ &qux
-// ^ )
+// ^ move(&foo, &bar, &baz, &qux)
         &foo;
         &bar;
         &baz;
         &qux;
     };
     || {
-// ^ move
-// ^ (
-// ^ &mut baz
-// ^ )
+// ^ move(&mut baz)
         &mut baz;
     };
     || {
-// ^ move
-// ^ (
-// ^ &mut baz
-// ^ , $
-// ^ &mut *qux
-// ^ )
+// ^ move(&mut baz, &mut *qux)
         baz = NonCopy;
         *qux = NonCopy;
     };
@@ -209,9 +150,7 @@ fn main() {
 fn main() {
     let foo = u32;
     move || {
-//  ^^^^ (
-//  ^^^^ foo
-//  ^^^^ )
+//  ^^^^ (foo)
         foo;
     };
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 35b62878329..cd77c3ec3e9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -5,6 +5,7 @@
 //! }
 //! ```
 use hir::Semantics;
+use ide_db::text_edit::TextEdit;
 use ide_db::{famous_defs::FamousDefs, RootDatabase};
 use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasName};
@@ -65,11 +66,11 @@ fn variant_hints(
     let eq_ = if eq_token.is_none() { " =" } else { "" };
     let label = InlayHintLabel::simple(
         match d {
-            Ok(x) => {
-                if x >= 10 {
-                    format!("{eq_} {x} ({x:#X})")
+            Ok(val) => {
+                if val >= 10 {
+                    format!("{eq_} {val} ({val:#X})")
                 } else {
-                    format!("{eq_} {x}")
+                    format!("{eq_} {val}")
                 }
             }
             Err(_) => format!("{eq_} ?"),
@@ -87,7 +88,7 @@ fn variant_hints(
         },
         kind: InlayKind::Discriminant,
         label,
-        text_edit: None,
+        text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))),
         position: InlayHintPosition::After,
         pad_left: false,
         pad_right: false,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index 8d422478cbf..1560df37d0d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -4,6 +4,7 @@
 //! ```
 use either::Either;
 use ide_db::famous_defs::FamousDefs;
+use ide_db::text_edit::TextEdit;
 use span::EditionedFileId;
 use syntax::{
     ast::{self, AstNode},
@@ -38,7 +39,7 @@ pub(super) fn hints(
                 range: t.text_range(),
                 kind: InlayKind::Lifetime,
                 label: "'static".into(),
-                text_edit: None,
+                text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())),
                 position: InlayHintPosition::After,
                 pad_left: false,
                 pad_right: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index 9d8ba90b2ff..5192f91a4a6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -8,7 +8,7 @@ use syntax::{
     SyntaxToken, TextRange, TextSize, T,
 };
 
-use text_edit::{TextEdit, TextEditBuilder};
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
 
 pub struct JoinLinesConfig {
     pub join_else_if: bool,
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index d7163d57d22..d053c4b3c93 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -122,6 +122,7 @@ pub use ide_completion::{
     CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
     CompletionItemKind, CompletionRelevance, Snippet, SnippetScope,
 };
+pub use ide_db::text_edit::{Indel, TextEdit};
 pub use ide_db::{
     base_db::{Cancelled, CrateGraph, CrateId, FileChange, SourceRoot, SourceRootId},
     documentation::Documentation,
@@ -139,7 +140,6 @@ pub use ide_diagnostics::{
 pub use ide_ssr::SsrError;
 pub use span::Edition;
 pub use syntax::{TextRange, TextSize};
-pub use text_edit::{Indel, TextEdit};
 
 pub type Cancellable<T> = Result<T, Cancelled>;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index ea6cc9d6de2..a232df2b82b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -1,10 +1,11 @@
 use std::{iter::once, mem};
 
 use hir::Semantics;
+use ide_db::syntax_helpers::tree_diff::diff;
+use ide_db::text_edit::{TextEdit, TextEditBuilder};
 use ide_db::{helpers::pick_best_token, FileRange, RootDatabase};
 use itertools::Itertools;
-use syntax::{algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
-use text_edit::{TextEdit, TextEditBuilder};
+use syntax::{ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange};
 
 #[derive(Copy, Clone, Debug)]
 pub enum Direction {
@@ -166,7 +167,7 @@ fn replace_nodes<'a>(
 
     let mut edit = TextEditBuilder::default();
 
-    algo::diff(first, second).into_text_edit(&mut edit);
+    diff(first, second).into_text_edit(&mut edit);
     edit.replace(second.text_range(), first_with_cursor);
 
     edit.finish()
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index e7cb8a253f4..339315db571 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -1701,14 +1701,14 @@ fn f() {
 }
             "#,
             expect![[r#"
-                func Function FileId(0) 137..146 140..144
+                func Function FileId(0) 137..146 140..144 module
 
-                FileId(0) 161..165
+                FileId(0) 181..185
 
 
-                func Function FileId(0) 137..146 140..144 module
+                func Function FileId(0) 137..146 140..144
 
-                FileId(0) 181..185
+                FileId(0) 161..165
             "#]],
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index f17c1fa5c62..665fc954d23 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -15,7 +15,7 @@ use itertools::Itertools;
 use stdx::{always, never};
 use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize};
 
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
 
 use crate::{FilePosition, RangeInfo, SourceChange};
 
@@ -449,9 +449,9 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
 mod tests {
     use expect_test::{expect, Expect};
     use ide_db::source_change::SourceChange;
+    use ide_db::text_edit::TextEdit;
     use stdx::trim_indent;
     use test_utils::assert_eq_text;
-    use text_edit::TextEdit;
 
     use crate::fixture;
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index 961b2a4c938..0747d1b404b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -16,7 +16,7 @@ mod tests;
 use std::ops::ControlFlow;
 
 use hir::{InRealFile, Name, Semantics};
-use ide_db::{FxHashMap, RootDatabase, SymbolKind};
+use ide_db::{FxHashMap, Ranker, RootDatabase, SymbolKind};
 use span::EditionedFileId;
 use syntax::{
     ast::{self, IsString},
@@ -397,13 +397,12 @@ fn traverse(
                 Some(AttrOrDerive::Derive(_)) => inside_attribute,
                 None => false,
             };
+
         let descended_element = if in_macro {
             // Attempt to descend tokens into macro-calls.
             let res = match element {
                 NodeOrToken::Token(token) if token.kind() != COMMENT => {
-                    let kind = token.kind();
-                    let text = token.text();
-                    let ident_kind = kind.is_any_identifier();
+                    let ranker = Ranker::from_token(&token);
 
                     let mut t = None;
                     let mut r = 0;
@@ -412,21 +411,9 @@ fn traverse(
                         |tok, _ctx| {
                             // FIXME: Consider checking ctx transparency for being opaque?
                             let tok = tok.value;
-                            let tok_kind = tok.kind();
-
-                            let exact_same_kind = tok_kind == kind;
-                            let both_idents =
-                                exact_same_kind || (tok_kind.is_any_identifier() && ident_kind);
-                            let same_text = tok.text() == text;
-                            // anything that mapped into a token tree has likely no semantic information
-                            let no_tt_parent =
-                                tok.parent().map_or(false, |it| it.kind() != TOKEN_TREE);
-                            let my_rank = (both_idents as usize)
-                                | ((exact_same_kind as usize) << 1)
-                                | ((same_text as usize) << 2)
-                                | ((no_tt_parent as usize) << 3);
-
-                            if my_rank > 0b1110 {
+                            let my_rank = ranker.rank_token(&tok);
+
+                            if my_rank >= Ranker::MAX_RANK {
                                 // a rank of 0b1110 means that we have found a maximally interesting
                                 // token so stop early.
                                 t = Some(tok);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
index d07ba74db24..361dcd1bc37 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html
@@ -50,4 +50,4 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="brace">}</span>
 
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">issue_18089</span><span class="attribute_bracket attribute">]</span>
-<span class="keyword">fn</span> <span class="function declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
+<span class="keyword">fn</span> <span class="macro declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index a09e1e85ae1..9bb5de9f2e3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -23,7 +23,7 @@ use syntax::{
     AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T,
 };
 
-use text_edit::{Indel, TextEdit};
+use ide_db::text_edit::TextEdit;
 
 use crate::SourceChange;
 
@@ -126,7 +126,7 @@ fn on_opening_bracket_typed(
         return None;
     }
     // FIXME: Edition
-    let file = file.reparse(&Indel::delete(range), span::Edition::CURRENT_FIXME);
+    let file = file.reparse(range, "", span::Edition::CURRENT_FIXME);
 
     if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) {
         return Some(edit);
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index 6e56bd61850..773e352220e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -12,7 +12,7 @@ use syntax::{
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
 };
 
-use text_edit::TextEdit;
+use ide_db::text_edit::TextEdit;
 
 // Feature: On Enter
 //
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index ecfabca092c..92311238c23 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -144,10 +144,31 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
         LIFETIME_IDENT => lifetime(p),
         T![for] => types::for_type(p, false),
         // test precise_capturing
-        // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+        // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
         T![use] if p.nth_at(1, T![<]) => {
             p.bump_any();
-            generic_param_list(p)
+            let m = p.start();
+            delimited(
+                p,
+                T![<],
+                T![>],
+                T![,],
+                || "expected identifier or lifetime".into(),
+                TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]),
+                |p| {
+                    if p.at(T![Self]) {
+                        let m = p.start();
+                        p.bump(T![Self]);
+                        m.complete(p, NAME_REF);
+                    } else if p.at(LIFETIME_IDENT) {
+                        lifetime(p);
+                    } else {
+                        name_ref(p);
+                    }
+                    true
+                },
+            );
+            m.complete(p, USE_BOUND_GENERIC_ARGS);
         }
         T![?] if p.nth_at(1, T![for]) => {
             // test question_for_type_trait_bound
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
index 882c243b0cd..ed01fca2acd 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -21,7 +21,8 @@ const RANGE_PAT_END_FIRST: TokenSet =
     expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[T![-], T![const]]));
 
 pub(crate) fn pattern(p: &mut Parser<'_>) {
-    pattern_r(p, PAT_RECOVERY_SET);
+    let m = p.start();
+    pattern_r(p, m, false, PAT_RECOVERY_SET);
 }
 
 /// Parses a pattern list separated by pipes `|`.
@@ -36,13 +37,11 @@ pub(crate) fn pattern_single(p: &mut Parser<'_>) {
 /// Parses a pattern list separated by pipes `|`
 /// using the given `recovery_set`.
 pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
-    p.eat(T![|]);
-    pattern_r(p, recovery_set);
+    let m = p.start();
+    let has_leading_pipe = p.eat(T![|]);
+    pattern_r(p, m, has_leading_pipe, recovery_set);
 }
 
-/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
-/// given `recovery_set`.
-
 // test or_pattern
 // fn main() {
 //     match () {
@@ -52,11 +51,12 @@ pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
 //         [_ | _,] => (),
 //     }
 // }
-fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
-    let m = p.start();
+/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
+/// given `recovery_set`.
+fn pattern_r(p: &mut Parser<'_>, m: Marker, has_leading_pipe: bool, recovery_set: TokenSet) {
     pattern_single_r(p, recovery_set);
 
-    if !p.at(T![|]) {
+    if !p.at(T![|]) && !has_leading_pipe {
         m.abandon(p);
         return;
     }
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index 5322463a713..3c0eb1b42a6 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -39,7 +39,9 @@ impl<'a> LexedStr<'a> {
             conv.offset = shebang_len;
         };
 
-        for token in rustc_lexer::tokenize(&text[conv.offset..]) {
+        // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer
+        // but we want to split it to two in edition <2024.
+        while let Some(token) = rustc_lexer::tokenize(&text[conv.offset..]).next() {
             let token_text = &text[conv.offset..][..token.len as usize];
 
             conv.extend_token(&token.kind, token_text);
@@ -158,7 +160,7 @@ impl<'a> Converter<'a> {
         }
     }
 
-    fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, token_text: &str) {
+    fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, mut token_text: &str) {
         // A note on an intended tradeoff:
         // We drop some useful information here (see patterns with double dots `..`)
         // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
@@ -189,10 +191,15 @@ impl<'a> Converter<'a> {
                 rustc_lexer::TokenKind::RawIdent => IDENT,
 
                 rustc_lexer::TokenKind::GuardedStrPrefix if self.edition.at_least_2024() => {
+                    // FIXME: rustc does something better for recovery.
                     err = "Invalid string literal (reserved syntax)";
                     ERROR
                 }
-                rustc_lexer::TokenKind::GuardedStrPrefix => POUND,
+                rustc_lexer::TokenKind::GuardedStrPrefix => {
+                    // The token is `#"` or `##`, split it into two.
+                    token_text = &token_text[1..];
+                    POUND
+                }
 
                 rustc_lexer::TokenKind::Literal { kind, .. } => {
                     self.extend_literal(token_text.len(), kind);
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 8da338c0a2c..21730244a33 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -312,6 +312,8 @@ pub enum SyntaxKind {
     UNDERSCORE_EXPR,
     UNION,
     USE,
+    USE_BOUND_GENERIC_ARG,
+    USE_BOUND_GENERIC_ARGS,
     USE_TREE,
     USE_TREE_LIST,
     VARIANT,
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs
index e7bccb6685c..4b19ddc752a 100644
--- a/src/tools/rust-analyzer/crates/parser/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs
@@ -15,11 +15,20 @@ use crate::{Edition, LexedStr, TopEntryPoint};
 #[path = "../test_data/generated/runner.rs"]
 mod runner;
 
+fn infer_edition(file_path: &Path) -> Edition {
+    let file_content = std::fs::read_to_string(file_path).unwrap();
+    if let Some(edition) = file_content.strip_prefix("//@ edition: ") {
+        edition[..4].parse().expect("invalid edition directive")
+    } else {
+        Edition::CURRENT
+    }
+}
+
 #[test]
 fn lex_ok() {
     for case in TestCase::list("lexer/ok") {
         let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
-        let actual = lex(&case.text);
+        let actual = lex(&case.text, infer_edition(&case.rs));
         expect_file![case.rast].assert_eq(&actual)
     }
 }
@@ -28,13 +37,13 @@ fn lex_ok() {
 fn lex_err() {
     for case in TestCase::list("lexer/err") {
         let _guard = stdx::panic_context::enter(format!("{:?}", case.rs));
-        let actual = lex(&case.text);
+        let actual = lex(&case.text, infer_edition(&case.rs));
         expect_file![case.rast].assert_eq(&actual)
     }
 }
 
-fn lex(text: &str) -> String {
-    let lexed = LexedStr::new(Edition::CURRENT, text);
+fn lex(text: &str, edition: Edition) -> String {
+    let lexed = LexedStr::new(edition, text);
 
     let mut res = String::new();
     for i in 0..lexed.len() {
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
index c56bf0b6448..7076e03ba4b 100644
--- a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
@@ -195,6 +195,38 @@ fn macro_pattern() {
             error 0: expected pattern
         "#]],
     );
+
+    check(
+        TopEntryPoint::Pattern,
+        "| 42 | 43",
+        expect![[r#"
+            OR_PAT
+              PIPE "|"
+              WHITESPACE " "
+              LITERAL_PAT
+                LITERAL
+                  INT_NUMBER "42"
+              WHITESPACE " "
+              PIPE "|"
+              WHITESPACE " "
+              LITERAL_PAT
+                LITERAL
+                  INT_NUMBER "43"
+        "#]],
+    );
+
+    check(
+        TopEntryPoint::Pattern,
+        "| 42",
+        expect![[r#"
+            OR_PAT
+              PIPE "|"
+              WHITESPACE " "
+              LITERAL_PAT
+                LITERAL
+                  INT_NUMBER "42"
+        "#]],
+    );
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast
new file mode 100644
index 00000000000..1bdd6720441
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rast
@@ -0,0 +1,4 @@
+COMMENT "//@ edition: 2021"
+WHITESPACE "\n\n"
+POUND "#"
+STRING "\"foo\""
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs
new file mode 100644
index 00000000000..f00f949f0db
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/guarded_str_prefix_edition_2021.rs
@@ -0,0 +1,3 @@
+//@ edition: 2021
+
+#"foo"
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
index 8189cf0a8e5..92210281629 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/match_arm.rast
@@ -102,9 +102,9 @@ SOURCE_FILE
                 COMMA ","
               WHITESPACE "\n        "
               MATCH_ARM
-                PIPE "|"
-                WHITESPACE " "
                 OR_PAT
+                  PIPE "|"
+                  WHITESPACE " "
                   IDENT_PAT
                     NAME
                       IDENT "X"
@@ -132,11 +132,12 @@ SOURCE_FILE
                 COMMA ","
               WHITESPACE "\n        "
               MATCH_ARM
-                PIPE "|"
-                WHITESPACE " "
-                IDENT_PAT
-                  NAME
-                    IDENT "X"
+                OR_PAT
+                  PIPE "|"
+                  WHITESPACE " "
+                  IDENT_PAT
+                    NAME
+                      IDENT "X"
                 WHITESPACE " "
                 FAT_ARROW "=>"
                 WHITESPACE " "
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
index cf52f1e4799..f9c0a245af8 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast
@@ -50,16 +50,18 @@ SOURCE_FILE
           WHITESPACE " "
           TYPE_BOUND
             USE_KW "use"
-            GENERIC_PARAM_LIST
+            USE_BOUND_GENERIC_ARGS
               L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'b"
+              LIFETIME
+                LIFETIME_IDENT "'b"
               COMMA ","
               WHITESPACE " "
-              TYPE_PARAM
-                NAME
-                  IDENT "T"
+              NAME_REF
+                IDENT "T"
+              COMMA ","
+              WHITESPACE " "
+              NAME_REF
+                SELF_TYPE_KW "Self"
               R_ANGLE ">"
     WHITESPACE " "
     BLOCK_EXPR
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
index ec208d5062b..9ac2305f3a0 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rs
@@ -1 +1 @@
-fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T> {}
+fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
index dff72ba886f..06c30bba59f 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/slice_pat.rast
@@ -43,11 +43,12 @@ SOURCE_FILE
           WHITESPACE " "
           SLICE_PAT
             L_BRACK "["
-            PIPE "|"
-            WHITESPACE " "
-            IDENT_PAT
-              NAME
-                IDENT "a"
+            OR_PAT
+              PIPE "|"
+              WHITESPACE " "
+              IDENT_PAT
+                NAME
+                  IDENT "a"
             COMMA ","
             WHITESPACE " "
             REST_PAT
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
index 1a01e0f6938..c7cd11f774b 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat.rast
@@ -91,9 +91,9 @@ SOURCE_FILE
           WHITESPACE " "
           TUPLE_PAT
             L_PAREN "("
-            PIPE "|"
-            WHITESPACE " "
             OR_PAT
+              PIPE "|"
+              WHITESPACE " "
               IDENT_PAT
                 NAME
                   IDENT "a"
@@ -105,11 +105,12 @@ SOURCE_FILE
                   IDENT "a"
             COMMA ","
             WHITESPACE " "
-            PIPE "|"
-            WHITESPACE " "
-            IDENT_PAT
-              NAME
-                IDENT "b"
+            OR_PAT
+              PIPE "|"
+              WHITESPACE " "
+              IDENT_PAT
+                NAME
+                  IDENT "b"
             R_PAREN ")"
           WHITESPACE " "
           EQ "="
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
index 55baf2fdcb4..96353f46976 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/tuple_pat_fields.rast
@@ -110,11 +110,12 @@ SOURCE_FILE
                 NAME_REF
                   IDENT "S"
             L_PAREN "("
-            PIPE "|"
-            WHITESPACE " "
-            IDENT_PAT
-              NAME
-                IDENT "a"
+            OR_PAT
+              PIPE "|"
+              WHITESPACE " "
+              IDENT_PAT
+                NAME
+                  IDENT "a"
             R_PAREN ")"
           WHITESPACE " "
           EQ "="
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
index 88256e98b58..5443a9bd67b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
@@ -401,7 +401,7 @@ struct Writer<'a, 'span, S: InternableSpan> {
     text: Vec<String>,
 }
 
-impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
+impl<'a, S: InternableSpan> Writer<'a, '_, S> {
     fn write(&mut self, root: &'a tt::Subtree<S>) {
         self.enqueue(root);
         while let Some((idx, subtree)) = self.work.pop_front() {
@@ -524,7 +524,7 @@ struct Reader<'span, S: InternableSpan> {
     span_data_table: &'span S::Table,
 }
 
-impl<'span, S: InternableSpan> Reader<'span, S> {
+impl<S: InternableSpan> Reader<'_, S> {
     pub(crate) fn read(self) -> tt::Subtree<S> {
         let mut res: Vec<Option<tt::Subtree<S>>> = vec![None; self.subtree.len()];
         let read_span = |id| S::span_for_token_id(self.span_data_table, id);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index aa73ff89100..bc1f0e6fbf2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -24,14 +24,15 @@ pub(crate) fn get(
     config: RustcCfgConfig<'_>,
 ) -> Vec<CfgAtom> {
     let _p = tracing::info_span!("rustc_cfg::get").entered();
-    let mut res: Vec<_> = Vec::with_capacity(6 * 2 + 1);
+    let mut res: Vec<_> = Vec::with_capacity(7 * 2 + 1);
 
     // Some nightly-only cfgs, which are required for stdlib
     res.push(CfgAtom::Flag(Symbol::intern("target_thread_local")));
-    for ty in ["8", "16", "32", "64", "cas", "ptr"] {
-        for key in ["target_has_atomic", "target_has_atomic_load_store"] {
+    for key in ["target_has_atomic", "target_has_atomic_load_store"] {
+        for ty in ["8", "16", "32", "64", "cas", "ptr"] {
             res.push(CfgAtom::KeyValue { key: Symbol::intern(key), value: Symbol::intern(ty) });
         }
+        res.push(CfgAtom::Flag(Symbol::intern(key)));
     }
 
     let rustc_cfgs = get_rust_cfgs(target, extra_env, config);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index d1ee579c0d8..d53639e2423 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -1062,7 +1062,7 @@ fn cargo_to_crate_graph(
                 proc_macros,
                 cargo,
                 pkg_data,
-                build_data,
+                build_data.zip(Some(build_scripts.error().is_some())),
                 cfg_options.clone(),
                 file_id,
                 name,
@@ -1285,7 +1285,7 @@ fn handle_rustc_crates(
                         proc_macros,
                         rustc_workspace,
                         &rustc_workspace[pkg],
-                        build_scripts.get_output(pkg),
+                        build_scripts.get_output(pkg).zip(Some(build_scripts.error().is_some())),
                         cfg_options.clone(),
                         file_id,
                         &rustc_workspace[tgt].name,
@@ -1345,7 +1345,7 @@ fn add_target_crate_root(
     proc_macros: &mut ProcMacroPaths,
     cargo: &CargoWorkspace,
     pkg: &PackageData,
-    build_data: Option<&BuildScriptOutput>,
+    build_data: Option<(&BuildScriptOutput, bool)>,
     cfg_options: CfgOptions,
     file_id: FileId,
     cargo_name: &str,
@@ -1368,7 +1368,7 @@ fn add_target_crate_root(
         for feature in pkg.active_features.iter() {
             opts.insert_key_value(sym::feature.clone(), Symbol::intern(feature));
         }
-        if let Some(cfgs) = build_data.as_ref().map(|it| &it.cfgs) {
+        if let Some(cfgs) = build_data.map(|(it, _)| &it.cfgs) {
             opts.extend(cfgs.iter().cloned());
         }
         opts
@@ -1379,7 +1379,7 @@ fn add_target_crate_root(
     inject_cargo_env(&mut env);
     inject_rustc_tool_env(&mut env, cargo, cargo_name, kind);
 
-    if let Some(envs) = build_data.map(|it| &it.envs) {
+    if let Some(envs) = build_data.map(|(it, _)| &it.envs) {
         for (k, v) in envs {
             env.set(k, v.clone());
         }
@@ -1396,11 +1396,14 @@ fn add_target_crate_root(
         origin,
     );
     if let TargetKind::Lib { is_proc_macro: true } = kind {
-        let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
-            Some(it) => match it {
-                Some(path) => Ok((cargo_name.to_owned(), path.clone())),
-                None => Err("proc-macro crate build data is missing dylib path".to_owned()),
-            },
+        let proc_macro = match build_data {
+            Some((BuildScriptOutput { proc_macro_dylib_path, .. }, has_errors)) => {
+                match proc_macro_dylib_path {
+                    Some(path) => Ok((cargo_name.to_owned(), path.clone())),
+                    None if has_errors => Err("failed to build proc-macro".to_owned()),
+                    None => Err("proc-macro crate build data is missing dylib path".to_owned()),
+                }
+            }
             None => Err("proc-macro crate is missing its build data".to_owned()),
         };
         proc_macros.insert(crate_id, proc_macro);
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 3401d7f7e47..880e90c52a5 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -19,6 +19,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -81,6 +82,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -151,6 +153,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -221,6 +224,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -291,6 +295,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -303,6 +308,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 3401d7f7e47..880e90c52a5 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -19,6 +19,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -81,6 +82,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -151,6 +153,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -221,6 +224,7 @@
             [
                 "rust_analyzer",
                 "test",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -291,6 +295,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -303,6 +308,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 491568d4b75..7746acd225e 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -18,6 +18,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -79,6 +80,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -148,6 +150,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -217,6 +220,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -287,6 +291,7 @@
             [
                 "feature=default",
                 "feature=std",
+                "true",
             ],
         ),
         potential_cfg_options: Some(
@@ -299,6 +304,7 @@
                     "feature=rustc-dep-of-std",
                     "feature=std",
                     "feature=use_std",
+                    "true",
                 ],
             ),
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 8261e5a2d90..90f41a9c2fc 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -17,6 +17,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -56,6 +57,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -86,6 +88,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -116,6 +119,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -146,6 +150,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -193,6 +198,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -223,6 +229,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -318,6 +325,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -348,6 +356,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -378,6 +387,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -410,6 +420,7 @@
                 "group1_other_cfg=other_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -485,6 +496,7 @@
                 "group2_cfg=fourth_config",
                 "group2_cfg=yet_another_config",
                 "rust_analyzer",
+                "true",
                 "unrelated_cfg",
             ],
         ),
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index c123df80a6a..a0e14b8fcb2 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -17,6 +17,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -56,6 +57,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -86,6 +88,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -116,6 +119,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -146,6 +150,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -193,6 +198,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -223,6 +229,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -318,6 +325,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -348,6 +356,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -378,6 +387,7 @@
             [
                 "debug_assertions",
                 "miri",
+                "true",
             ],
         ),
         potential_cfg_options: None,
@@ -407,6 +417,7 @@
         cfg_options: CfgOptions(
             [
                 "rust_analyzer",
+                "true",
             ],
         ),
         potential_cfg_options: None,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
index de7a3976074..6c5ccba173b 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived/slot.rs
@@ -616,7 +616,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues."
     }
 }
 
-impl<'me, Q> Drop for PanicGuard<'me, Q>
+impl<Q> Drop for PanicGuard<'_, Q>
 where
     Q: QueryFunction,
     Q::Value: Eq,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
index d0e4b5422b5..ff9cc4eade2 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/derived_lru/slot.rs
@@ -666,7 +666,7 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues."
     }
 }
 
-impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP>
+impl<Q, MP> Drop for PanicGuard<'_, Q, MP>
 where
     Q: QueryFunction,
     MP: MemoizationPolicy<Q>,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
index 359662ec6b2..42c398d697d 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/interned.rs
@@ -493,7 +493,7 @@ where
     is_static::<Slot<K>>();
 }
 
-impl<'me, Q> QueryTable<'me, Q>
+impl<Q> QueryTable<'_, Q>
 where
     Q: Query<Storage = InternedStorage<Q>>,
     Q::Key: InternValue,
diff --git a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
index 1b327773ec6..bd1ab6971cb 100644
--- a/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ra-salsa/src/lib.rs
@@ -149,7 +149,7 @@ where
     db: &'me D,
 }
 
-impl<'me, D: ?Sized> fmt::Debug for EventDebug<'me, D>
+impl<D: ?Sized> fmt::Debug for EventDebug<'_, D>
 where
     D: plumbing::DatabaseOps,
 {
@@ -242,7 +242,7 @@ where
     db: &'me D,
 }
 
-impl<'me, D: ?Sized> fmt::Debug for EventKindDebug<'me, D>
+impl<D: ?Sized> fmt::Debug for EventKindDebug<'_, D>
 where
     D: plumbing::DatabaseOps,
 {
@@ -729,7 +729,7 @@ impl Cycle {
             db: &'me dyn Database,
         }
 
-        impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> {
+        impl std::fmt::Debug for UnexpectedCycleDebug<'_> {
             fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 fmt.debug_struct("UnexpectedCycle")
                     .field("all_participants", &self.c.all_participants(self.db))
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index ecc8333503e..e872585c571 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -85,7 +85,9 @@ fn actual_main() -> anyhow::Result<ExitCode> {
         flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?,
-        flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?,
+        flags::RustAnalyzerCmd::Lsif(cmd) => {
+            cmd.run(&mut std::io::stdout(), Some(project_model::RustLibSource::Discover))?
+        }
         flags::RustAnalyzerCmd::Scip(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::RunTests(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::RustcTests(cmd) => cmd.run()?,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index ca8acf57bff..33c4f31fbee 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -12,6 +12,7 @@ use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
 use lsp_types::lsif;
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
 use rustc_hash::FxHashMap;
+use stdx::format_to;
 use vfs::{AbsPathBuf, Vfs};
 
 use crate::{
@@ -21,7 +22,7 @@ use crate::{
     version::version,
 };
 
-struct LsifManager<'a> {
+struct LsifManager<'a, 'w> {
     count: i32,
     token_map: FxHashMap<TokenId, Id>,
     range_map: FxHashMap<FileRange, Id>,
@@ -30,6 +31,7 @@ struct LsifManager<'a> {
     analysis: &'a Analysis,
     db: &'a RootDatabase,
     vfs: &'a Vfs,
+    out: &'w mut dyn std::io::Write,
 }
 
 #[derive(Clone, Copy)]
@@ -41,8 +43,13 @@ impl From<Id> for lsp_types::NumberOrString {
     }
 }
 
-impl LsifManager<'_> {
-    fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
+impl LsifManager<'_, '_> {
+    fn new<'a, 'w>(
+        analysis: &'a Analysis,
+        db: &'a RootDatabase,
+        vfs: &'a Vfs,
+        out: &'w mut dyn std::io::Write,
+    ) -> LsifManager<'a, 'w> {
         LsifManager {
             count: 0,
             token_map: FxHashMap::default(),
@@ -52,6 +59,7 @@ impl LsifManager<'_> {
             analysis,
             db,
             vfs,
+            out,
         }
     }
 
@@ -70,9 +78,8 @@ impl LsifManager<'_> {
         self.add(lsif::Element::Edge(edge))
     }
 
-    // FIXME: support file in addition to stdout here
-    fn emit(&self, data: &str) {
-        println!("{data}");
+    fn emit(&mut self, data: &str) {
+        format_to!(self.out, "{data}\n");
     }
 
     fn get_token_id(&mut self, id: TokenId) -> Id {
@@ -272,14 +279,14 @@ impl LsifManager<'_> {
 }
 
 impl flags::Lsif {
-    pub fn run(self) -> anyhow::Result<()> {
+    pub fn run(
+        self,
+        out: &mut dyn std::io::Write,
+        sysroot: Option<RustLibSource>,
+    ) -> anyhow::Result<()> {
         let now = Instant::now();
-        let cargo_config = &CargoConfig {
-            sysroot: Some(RustLibSource::Discover),
-            all_targets: true,
-            set_test: true,
-            ..Default::default()
-        };
+        let cargo_config =
+            &CargoConfig { sysroot, all_targets: true, set_test: true, ..Default::default() };
         let no_progress = &|_| ();
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: true,
@@ -308,7 +315,7 @@ impl flags::Lsif {
 
         let si = StaticIndex::compute(&analysis, vendored_libs_config);
 
-        let mut lsif = LsifManager::new(&analysis, db, &vfs);
+        let mut lsif = LsifManager::new(&analysis, db, &vfs, out);
         lsif.add_vertex(lsif::Vertex::MetaData(lsif::MetaData {
             version: String::from("0.5.0"),
             project_root: lsp_types::Url::from_file_path(path).unwrap(),
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 518b588cb7d..f5b0fcecf39 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -727,7 +727,7 @@ enum RatomlFile {
     Crate(LocalConfigInput),
 }
 
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 pub struct Config {
     /// Projects that have a Cargo.toml or a rust-project.json in a
     /// parent directory, so we can discover them by walking the
@@ -765,6 +765,26 @@ pub struct Config {
     detached_files: Vec<AbsPathBuf>,
 }
 
+impl fmt::Debug for Config {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Config")
+            .field("discovered_projects_from_filesystem", &self.discovered_projects_from_filesystem)
+            .field("discovered_projects_from_command", &self.discovered_projects_from_command)
+            .field("workspace_roots", &self.workspace_roots)
+            .field("caps", &self.caps)
+            .field("root_path", &self.root_path)
+            .field("snippets", &self.snippets)
+            .field("visual_studio_code_version", &self.visual_studio_code_version)
+            .field("client_config", &self.client_config)
+            .field("user_config", &self.user_config)
+            .field("ratoml_file", &self.ratoml_file)
+            .field("source_root_parent_map", &self.source_root_parent_map)
+            .field("validation_errors", &self.validation_errors)
+            .field("detached_files", &self.detached_files)
+            .finish()
+    }
+}
+
 // Delegate capability fetching methods
 impl std::ops::Deref for Config {
     type Target = ClientCapabilities;
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 5f2871ac992..22910ee4c68 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -173,21 +173,6 @@ pub(crate) fn fetch_native_diagnostics(
     let _p = tracing::info_span!("fetch_native_diagnostics").entered();
     let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned());
 
-    let convert_diagnostic =
-        |line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic {
-            range: lsp::to_proto::range(line_index, d.range.range),
-            severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
-            code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
-            code_description: Some(lsp_types::CodeDescription {
-                href: lsp_types::Url::parse(&d.code.url()).unwrap(),
-            }),
-            source: Some("rust-analyzer".to_owned()),
-            message: d.message,
-            related_information: None,
-            tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
-            data: None,
-        };
-
     // the diagnostics produced may point to different files not requested by the concrete request,
     // put those into here and filter later
     let mut odd_ones = Vec::new();
@@ -203,10 +188,12 @@ pub(crate) fn fetch_native_diagnostics(
                 NativeDiagnosticsFetchKind::Syntax => {
                     snapshot.analysis.syntax_diagnostics(config, file_id).ok()?
                 }
-                NativeDiagnosticsFetchKind::Semantic => snapshot
+
+                NativeDiagnosticsFetchKind::Semantic if config.enabled => snapshot
                     .analysis
                     .semantic_diagnostics(config, ide::AssistResolveStrategy::None, file_id)
                     .ok()?,
+                NativeDiagnosticsFetchKind::Semantic => return None,
             };
             let diagnostics = diagnostics
                 .into_iter()
@@ -246,3 +233,22 @@ pub(crate) fn fetch_native_diagnostics(
     }
     diagnostics
 }
+
+pub(crate) fn convert_diagnostic(
+    line_index: &crate::line_index::LineIndex,
+    d: ide::Diagnostic,
+) -> lsp_types::Diagnostic {
+    lsp_types::Diagnostic {
+        range: lsp::to_proto::range(line_index, d.range.range),
+        severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
+        code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
+        code_description: Some(lsp_types::CodeDescription {
+            href: lsp_types::Url::parse(&d.code.url()).unwrap(),
+        }),
+        source: Some("rust-analyzer".to_owned()),
+        message: d.message,
+        related_information: None,
+        tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
+        data: None,
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
index ed7bf27843b..03759b036b4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
@@ -5,7 +5,7 @@ use std::{
 };
 
 use ide::Cancelled;
-use lsp_server::ExtractError;
+use lsp_server::{ExtractError, Response, ResponseError};
 use serde::{de::DeserializeOwned, Serialize};
 use stdx::thread::ThreadIntent;
 
@@ -117,7 +117,36 @@ impl RequestDispatcher<'_> {
             }
             return self;
         }
-        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+            ThreadIntent::Worker,
+            f,
+            Self::content_modified_error,
+        )
+    }
+
+    /// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
+    /// ready this will return a `default` constructed [`R::Result`].
+    pub(crate) fn on_with<R>(
+        &mut self,
+        f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
+        default: impl FnOnce() -> R::Result,
+        on_cancelled: fn() -> ResponseError,
+    ) -> &mut Self
+    where
+        R: lsp_types::request::Request<
+                Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
+                Result: Serialize,
+            > + 'static,
+    {
+        if !self.global_state.vfs_done {
+            if let Some(lsp_server::Request { id, .. }) =
+                self.req.take_if(|it| it.method == R::METHOD)
+            {
+                self.global_state.respond(lsp_server::Response::new_ok(id, default()));
+            }
+            return self;
+        }
+        self.on_with_thread_intent::<true, false, R>(ThreadIntent::Worker, f, on_cancelled)
     }
 
     /// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
@@ -136,7 +165,11 @@ impl RequestDispatcher<'_> {
             }
             return self;
         }
-        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+            ThreadIntent::Worker,
+            f,
+            Self::content_modified_error,
+        )
     }
 
     /// Dispatches a latency-sensitive request onto the thread pool. When the VFS is marked not
@@ -159,7 +192,11 @@ impl RequestDispatcher<'_> {
             }
             return self;
         }
-        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(
+            ThreadIntent::LatencySensitive,
+            f,
+            Self::content_modified_error,
+        )
     }
 
     /// Formatting requests should never block on waiting a for task thread to open up, editors will wait
@@ -174,7 +211,11 @@ impl RequestDispatcher<'_> {
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<false, false, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<false, false, R>(
+            ThreadIntent::LatencySensitive,
+            f,
+            Self::content_modified_error,
+        )
     }
 
     pub(crate) fn finish(&mut self) {
@@ -193,6 +234,7 @@ impl RequestDispatcher<'_> {
         &mut self,
         intent: ThreadIntent,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
+        on_cancelled: fn() -> ResponseError,
     ) -> &mut Self
     where
         R: lsp_types::request::Request + 'static,
@@ -221,11 +263,10 @@ impl RequestDispatcher<'_> {
             match thread_result_to_response::<R>(req.id.clone(), result) {
                 Ok(response) => Task::Response(response),
                 Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
-                Err(_cancelled) => Task::Response(lsp_server::Response::new_err(
-                    req.id,
-                    lsp_server::ErrorCode::ContentModified as i32,
-                    "content modified".to_owned(),
-                )),
+                Err(_cancelled) => {
+                    let error = on_cancelled();
+                    Task::Response(Response { id: req.id, result: None, error: Some(error) })
+                }
             }
         });
 
@@ -256,6 +297,14 @@ impl RequestDispatcher<'_> {
             }
         }
     }
+
+    fn content_modified_error() -> ResponseError {
+        ResponseError {
+            code: lsp_server::ErrorCode::ContentModified as i32,
+            message: "content modified".to_owned(),
+            data: None,
+        }
+    }
 }
 
 fn thread_result_to_response<R>(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index a9f8ac3a80a..fa584ab4d21 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -4,6 +4,7 @@
 use std::{
     fs,
     io::Write as _,
+    ops::Not,
     process::{self, Stdio},
 };
 
@@ -14,7 +15,7 @@ use ide::{
     FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query,
     RangeInfo, ReferenceCategory, Runnable, RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
-use ide_db::SymbolKind;
+use ide_db::{FxHashMap, SymbolKind};
 use itertools::Itertools;
 use lsp_server::ErrorCode;
 use lsp_types::{
@@ -36,6 +37,7 @@ use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
+    diagnostics::convert_diagnostic,
     global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot},
     hack_recover_crate_name,
     line_index::LineEndings,
@@ -119,7 +121,7 @@ pub(crate) fn handle_analyzer_status(
     format_to!(buf, "{}", crate::version());
 
     buf.push_str("\nConfiguration: \n");
-    format_to!(buf, "{:?}", snap.config);
+    format_to!(buf, "{:#?}", snap.config);
 
     Ok(buf)
 }
@@ -473,6 +475,74 @@ pub(crate) fn handle_on_type_formatting(
     Ok(Some(change))
 }
 
+pub(crate) fn handle_document_diagnostics(
+    snap: GlobalStateSnapshot,
+    params: lsp_types::DocumentDiagnosticParams,
+) -> anyhow::Result<lsp_types::DocumentDiagnosticReportResult> {
+    const EMPTY: lsp_types::DocumentDiagnosticReportResult =
+        lsp_types::DocumentDiagnosticReportResult::Report(
+            lsp_types::DocumentDiagnosticReport::Full(
+                lsp_types::RelatedFullDocumentDiagnosticReport {
+                    related_documents: None,
+                    full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+                        result_id: None,
+                        items: vec![],
+                    },
+                },
+            ),
+        );
+
+    let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+    let source_root = snap.analysis.source_root_id(file_id)?;
+    if !snap.analysis.is_local_source_root(source_root)? {
+        return Ok(EMPTY);
+    }
+    let config = snap.config.diagnostics(Some(source_root));
+    if !config.enabled {
+        return Ok(EMPTY);
+    }
+    let line_index = snap.file_line_index(file_id)?;
+    let supports_related = snap.config.text_document_diagnostic_related_document_support();
+
+    let mut related_documents = FxHashMap::default();
+    let diagnostics = snap
+        .analysis
+        .full_diagnostics(&config, AssistResolveStrategy::None, file_id)?
+        .into_iter()
+        .filter_map(|d| {
+            let file = d.range.file_id;
+            let diagnostic = convert_diagnostic(&line_index, d);
+            if file == file_id {
+                return Some(diagnostic);
+            }
+            if supports_related {
+                related_documents.entry(file).or_insert_with(Vec::new).push(diagnostic);
+            }
+            None
+        });
+    Ok(lsp_types::DocumentDiagnosticReportResult::Report(
+        lsp_types::DocumentDiagnosticReport::Full(lsp_types::RelatedFullDocumentDiagnosticReport {
+            full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+                result_id: None,
+                items: diagnostics.collect(),
+            },
+            related_documents: related_documents.is_empty().not().then(|| {
+                related_documents
+                    .into_iter()
+                    .map(|(id, items)| {
+                        (
+                            to_proto::url(&snap, id),
+                            lsp_types::DocumentDiagnosticReportKind::Full(
+                                lsp_types::FullDocumentDiagnosticReport { result_id: None, items },
+                            ),
+                        )
+                    })
+                    .collect()
+            }),
+        }),
+    ))
+}
+
 pub(crate) fn handle_document_symbol(
     snap: GlobalStateSnapshot,
     params: lsp_types::DocumentSymbolParams,
@@ -539,18 +609,11 @@ pub(crate) fn handle_document_symbol(
         url: &Url,
         res: &mut Vec<SymbolInformation>,
     ) {
-        let mut tags = Vec::new();
-
-        #[allow(deprecated)]
-        if let Some(true) = symbol.deprecated {
-            tags.push(SymbolTag::DEPRECATED)
-        }
-
         #[allow(deprecated)]
         res.push(SymbolInformation {
             name: symbol.name.clone(),
             kind: symbol.kind,
-            tags: Some(tags),
+            tags: symbol.tags.clone(),
             deprecated: symbol.deprecated,
             location: Location::new(url.clone(), symbol.range),
             container_name,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
index 3b19284f241..271a9c0f3d1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs
@@ -155,7 +155,15 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             "ssr": true,
             "workspaceSymbolScopeKindFiltering": true,
         })),
-        diagnostic_provider: None,
+        diagnostic_provider: Some(lsp_types::DiagnosticServerCapabilities::Options(
+            lsp_types::DiagnosticOptions {
+                identifier: None,
+                inter_file_dependencies: true,
+                // FIXME
+                workspace_diagnostics: false,
+                work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
+            },
+        )),
         inline_completion_provider: None,
     }
 }
@@ -210,9 +218,7 @@ impl ClientCapabilities {
                 .completion_item
                 .as_ref()?
                 .label_details_support
-                .as_ref()
-        })()
-        .is_some()
+        })() == Some(true)
     }
 
     fn completion_item(&self) -> Option<CompletionOptionsCompletionItem> {
@@ -382,6 +388,15 @@ impl ClientCapabilities {
         .unwrap_or_default()
     }
 
+    pub fn text_document_diagnostic(&self) -> bool {
+        (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref() })().is_some()
+    }
+
+    pub fn text_document_diagnostic_related_document_support(&self) -> bool {
+        (|| -> _ { self.0.text_document.as_ref()?.diagnostic.as_ref()?.related_document_support })()
+            == Some(true)
+    }
+
     pub fn code_action_group(&self) -> bool {
         self.experimental_bool("codeActionGroup")
     }
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 20be38a9e4b..9a51df80fe1 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
@@ -417,6 +417,8 @@ impl GlobalState {
                 }
             }
 
+            let supports_diagnostic_pull_model = self.config.text_document_diagnostic();
+
             let client_refresh = became_quiescent || state_changed;
             if client_refresh {
                 // Refresh semantic tokens if the client supports it.
@@ -434,11 +436,21 @@ impl GlobalState {
                 if self.config.inlay_hints_refresh() {
                     self.send_request::<lsp_types::request::InlayHintRefreshRequest>((), |_, _| ());
                 }
+
+                if supports_diagnostic_pull_model {
+                    self.send_request::<lsp_types::request::WorkspaceDiagnosticRefresh>(
+                        (),
+                        |_, _| (),
+                    );
+                }
             }
 
             let project_or_mem_docs_changed =
                 became_quiescent || state_changed || memdocs_added_or_removed;
-            if project_or_mem_docs_changed && self.config.publish_diagnostics(None) {
+            if project_or_mem_docs_changed
+                && !supports_diagnostic_pull_model
+                && self.config.publish_diagnostics(None)
+            {
                 self.update_diagnostics();
             }
             if project_or_mem_docs_changed && self.config.test_explorer() {
@@ -1080,6 +1092,23 @@ impl GlobalState {
             .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
             // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
             // All other request handlers
+            .on_with::<lsp_request::DocumentDiagnosticRequest>(handlers::handle_document_diagnostics, || lsp_types::DocumentDiagnosticReportResult::Report(
+                lsp_types::DocumentDiagnosticReport::Full(
+                    lsp_types::RelatedFullDocumentDiagnosticReport {
+                        related_documents: None,
+                        full_document_diagnostic_report: lsp_types::FullDocumentDiagnosticReport {
+                            result_id: None,
+                            items: vec![],
+                        },
+                    },
+                ),
+            ), || lsp_server::ResponseError {
+                code: lsp_server::ErrorCode::ServerCancelled as i32,
+                message: "server cancelled the request".to_owned(),
+                data: serde_json::to_value(lsp_types::DiagnosticServerCancellationData {
+                    retrigger_request: true
+                }).ok(),
+            })
             .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
             .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
             .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
index 5ab2dc2b67a..02ae4186ab6 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/config.rs
@@ -58,14 +58,22 @@ where
         let writer = self.writer;
 
         let ra_fmt_layer = tracing_subscriber::fmt::layer()
-            .with_timer(
-                time::OffsetTime::local_rfc_3339()
-                    .expect("Could not get local offset, make sure you're on the main thread"),
-            )
             .with_target(false)
             .with_ansi(false)
-            .with_writer(writer)
-            .with_filter(targets_filter);
+            .with_writer(writer);
+
+        let ra_fmt_layer = match time::OffsetTime::local_rfc_3339() {
+            Ok(timer) => {
+                // If we can get the time offset, format logs with the timezone.
+                ra_fmt_layer.with_timer(timer).boxed()
+            }
+            Err(_) => {
+                // Use system time if we can't get the time offset. This should
+                // never happen on Linux, but can happen on e.g. OpenBSD.
+                ra_fmt_layer.boxed()
+            }
+        }
+        .with_filter(targets_filter);
 
         let chalk_layer = match self.chalk_filter {
             Some(chalk_filter) => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
index cad92962f34..d466acef011 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
@@ -120,7 +120,7 @@ pub struct DataVisitor<'a> {
     string: &'a mut String,
 }
 
-impl<'a> Visit for DataVisitor<'a> {
+impl Visit for DataVisitor<'_> {
     fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
         write!(self.string, "{} = {:?} ", field.name(), value).unwrap();
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
new file mode 100644
index 00000000000..fba54666912
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
@@ -0,0 +1,131 @@
+use expect_test::expect;
+use test_utils::skip_slow_tests;
+
+use crate::support::Project;
+
+// If you choose to change the test fixture here, please inform the ferrocene/needy maintainers by
+// opening an issue at https://github.com/ferrocene/needy as the tool relies on specific token
+// mapping behavior.
+#[test]
+fn lsif_contains_generated_constant() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let stdout = Project::with_fixture(
+        r#"
+//- /Cargo.toml
+[package]
+name = "foo"
+version = "0.0.0"
+
+//- /src/lib.rs
+#![allow(unused)]
+
+macro_rules! generate_const_from_identifier(
+    ($id:ident) => (
+        const _: () = { const $id: &str = "encoded_data"; };
+    )
+);
+
+generate_const_from_identifier!(REQ_001);
+mod tests {
+    use super::*;
+    generate_const_from_identifier!(REQ_002);
+}
+"#,
+    )
+    .root("foo")
+    .run_lsif();
+    let n = stdout.find(r#"{"id":2,"#).unwrap();
+    // the first 2 entries contain paths that are not stable
+    let stdout = &stdout[n..];
+    expect![[r#"
+        {"id":2,"type":"vertex","label":"foldingRangeResult","result":[{"startLine":2,"startCharacter":43,"endLine":6,"endCharacter":1},{"startLine":3,"startCharacter":19,"endLine":5,"endCharacter":5},{"startLine":9,"startCharacter":10,"endLine":12,"endCharacter":1}]}
+        {"id":3,"type":"edge","label":"textDocument/foldingRange","inV":2,"outV":1}
+        {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}}
+        {"id":5,"type":"vertex","label":"resultSet"}
+        {"id":6,"type":"edge","label":"next","inV":5,"outV":4}
+        {"id":7,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}}
+        {"id":8,"type":"vertex","label":"resultSet"}
+        {"id":9,"type":"edge","label":"next","inV":8,"outV":7}
+        {"id":10,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}}
+        {"id":11,"type":"edge","label":"next","inV":8,"outV":10}
+        {"id":12,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}}
+        {"id":13,"type":"vertex","label":"resultSet"}
+        {"id":14,"type":"edge","label":"next","inV":13,"outV":12}
+        {"id":15,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}}
+        {"id":16,"type":"vertex","label":"resultSet"}
+        {"id":17,"type":"edge","label":"next","inV":16,"outV":15}
+        {"id":18,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}}
+        {"id":19,"type":"vertex","label":"resultSet"}
+        {"id":20,"type":"edge","label":"next","inV":19,"outV":18}
+        {"id":21,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}}
+        {"id":22,"type":"edge","label":"next","inV":8,"outV":21}
+        {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}}
+        {"id":24,"type":"vertex","label":"resultSet"}
+        {"id":25,"type":"edge","label":"next","inV":24,"outV":23}
+        {"id":26,"type":"edge","label":"contains","inVs":[4,7,10,12,15,18,21,23],"outV":1}
+        {"id":27,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}}
+        {"id":28,"type":"edge","label":"textDocument/hover","inV":27,"outV":5}
+        {"id":29,"type":"vertex","label":"referenceResult"}
+        {"id":30,"type":"edge","label":"textDocument/references","inV":29,"outV":5}
+        {"id":31,"type":"edge","label":"item","document":1,"property":"references","inVs":[4],"outV":29}
+        {"id":32,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}}
+        {"id":33,"type":"edge","label":"textDocument/hover","inV":32,"outV":8}
+        {"id":34,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"}
+        {"id":35,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"}
+        {"id":36,"type":"edge","label":"packageInformation","inV":34,"outV":35}
+        {"id":37,"type":"edge","label":"moniker","inV":35,"outV":8}
+        {"id":38,"type":"vertex","label":"definitionResult"}
+        {"id":39,"type":"edge","label":"item","document":1,"inVs":[7],"outV":38}
+        {"id":40,"type":"edge","label":"textDocument/definition","inV":38,"outV":8}
+        {"id":41,"type":"vertex","label":"referenceResult"}
+        {"id":42,"type":"edge","label":"textDocument/references","inV":41,"outV":8}
+        {"id":43,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[7],"outV":41}
+        {"id":44,"type":"edge","label":"item","document":1,"property":"references","inVs":[10,21],"outV":41}
+        {"id":45,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}}
+        {"id":46,"type":"edge","label":"textDocument/hover","inV":45,"outV":13}
+        {"id":47,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"}
+        {"id":48,"type":"edge","label":"packageInformation","inV":34,"outV":47}
+        {"id":49,"type":"edge","label":"moniker","inV":47,"outV":13}
+        {"id":50,"type":"vertex","label":"definitionResult"}
+        {"id":51,"type":"edge","label":"item","document":1,"inVs":[12],"outV":50}
+        {"id":52,"type":"edge","label":"textDocument/definition","inV":50,"outV":13}
+        {"id":53,"type":"vertex","label":"referenceResult"}
+        {"id":54,"type":"edge","label":"textDocument/references","inV":53,"outV":13}
+        {"id":55,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[12],"outV":53}
+        {"id":56,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}}
+        {"id":57,"type":"edge","label":"textDocument/hover","inV":56,"outV":16}
+        {"id":58,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"}
+        {"id":59,"type":"edge","label":"packageInformation","inV":34,"outV":58}
+        {"id":60,"type":"edge","label":"moniker","inV":58,"outV":16}
+        {"id":61,"type":"vertex","label":"definitionResult"}
+        {"id":62,"type":"edge","label":"item","document":1,"inVs":[15],"outV":61}
+        {"id":63,"type":"edge","label":"textDocument/definition","inV":61,"outV":16}
+        {"id":64,"type":"vertex","label":"referenceResult"}
+        {"id":65,"type":"edge","label":"textDocument/references","inV":64,"outV":16}
+        {"id":66,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":64}
+        {"id":67,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}}
+        {"id":68,"type":"edge","label":"textDocument/hover","inV":67,"outV":19}
+        {"id":69,"type":"vertex","label":"definitionResult"}
+        {"id":70,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}}
+        {"id":71,"type":"edge","label":"contains","inVs":[70],"outV":1}
+        {"id":72,"type":"edge","label":"item","document":1,"inVs":[70],"outV":69}
+        {"id":73,"type":"edge","label":"textDocument/definition","inV":69,"outV":19}
+        {"id":74,"type":"vertex","label":"referenceResult"}
+        {"id":75,"type":"edge","label":"textDocument/references","inV":74,"outV":19}
+        {"id":76,"type":"edge","label":"item","document":1,"property":"references","inVs":[18],"outV":74}
+        {"id":77,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}}
+        {"id":78,"type":"edge","label":"textDocument/hover","inV":77,"outV":24}
+        {"id":79,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"}
+        {"id":80,"type":"edge","label":"packageInformation","inV":34,"outV":79}
+        {"id":81,"type":"edge","label":"moniker","inV":79,"outV":24}
+        {"id":82,"type":"vertex","label":"definitionResult"}
+        {"id":83,"type":"edge","label":"item","document":1,"inVs":[23],"outV":82}
+        {"id":84,"type":"edge","label":"textDocument/definition","inV":82,"outV":24}
+        {"id":85,"type":"vertex","label":"referenceResult"}
+        {"id":86,"type":"edge","label":"textDocument/references","inV":85,"outV":24}
+        {"id":87,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[23],"outV":85}
+    "#]].assert_eq(stdout);
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 54cd27f4b3b..97c76bf8d17 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -10,6 +10,7 @@
 
 #![allow(clippy::disallowed_types)]
 
+mod cli;
 mod ratoml;
 mod support;
 mod testdir;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index 18aface632d..78572e37a9b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -6,11 +6,13 @@ use std::{
 };
 
 use crossbeam_channel::{after, select, Receiver};
+use itertools::Itertools;
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
 use parking_lot::{Mutex, MutexGuard};
 use paths::{Utf8Path, Utf8PathBuf};
 use rust_analyzer::{
+    cli::flags,
     config::{Config, ConfigChange, ConfigErrors},
     lsp, main_loop,
 };
@@ -84,6 +86,46 @@ impl Project<'_> {
         self
     }
 
+    pub(crate) fn run_lsif(self) -> String {
+        let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
+            if self.root_dir_contains_symlink {
+                TestDir::new_symlink()
+            } else {
+                TestDir::new()
+            }
+        });
+
+        let FixtureWithProjectMeta {
+            fixture,
+            mini_core,
+            proc_macro_names,
+            toolchain,
+            target_data_layout: _,
+        } = FixtureWithProjectMeta::parse(self.fixture);
+        assert!(proc_macro_names.is_empty());
+        assert!(mini_core.is_none());
+        assert!(toolchain.is_none());
+
+        for entry in fixture {
+            let path = tmp_dir.path().join(&entry.path['/'.len_utf8()..]);
+            fs::create_dir_all(path.parent().unwrap()).unwrap();
+            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
+        }
+
+        let tmp_dir_path = AbsPathBuf::assert(tmp_dir.path().to_path_buf());
+        let mut buf = Vec::new();
+        flags::Lsif::run(
+            flags::Lsif {
+                path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(),
+                exclude_vendored_libraries: false,
+            },
+            &mut buf,
+            None,
+        )
+        .unwrap();
+        String::from_utf8(buf).unwrap()
+    }
+
     pub(crate) fn server(self) -> Server {
         static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(());
         let tmp_dir = self.tmp_dir.unwrap_or_else(|| {
diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
index 0ebd72e1514..1d81d684511 100644
--- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs
+++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
@@ -224,9 +224,10 @@ impl AstIdMap {
         match self.map.raw_entry().from_hash(hash, |&idx| self.arena[idx] == ptr) {
             Some((&idx, &())) => ErasedFileAstId(idx.into_raw().into_u32()),
             None => panic!(
-                "Can't find {:?} in AstIdMap:\n{:?}",
+                "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}",
                 item,
                 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
+                item
             ),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 76dbd42ff6b..04c2153abf4 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -10,6 +10,7 @@ pub mod non_empty_vec;
 pub mod panic_context;
 pub mod process;
 pub mod rand;
+pub mod thin_vec;
 pub mod thread;
 
 pub use always_assert::{always, never};
@@ -304,22 +305,6 @@ pub fn slice_tails<T>(this: &[T]) -> impl Iterator<Item = &[T]> {
     (0..this.len()).map(|i| &this[i..])
 }
 
-pub trait IsNoneOr {
-    type Type;
-    #[allow(clippy::wrong_self_convention)]
-    fn is_none_or(self, s: impl FnOnce(Self::Type) -> bool) -> bool;
-}
-#[allow(unstable_name_collisions)]
-impl<T> IsNoneOr for Option<T> {
-    type Type = T;
-    fn is_none_or(self, f: impl FnOnce(T) -> bool) -> bool {
-        match self {
-            Some(v) => f(v),
-            None => true,
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
new file mode 100644
index 00000000000..700220e1d3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/stdx/src/thin_vec.rs
@@ -0,0 +1,472 @@
+use std::alloc::{dealloc, handle_alloc_error, Layout};
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
+use std::ptr::{addr_of_mut, slice_from_raw_parts_mut, NonNull};
+
+/// A type that is functionally equivalent to `(Header, Box<[Item]>)`,
+/// but all data is stored in one heap allocation and the pointer is thin,
+/// so the whole thing's size is like a pointer.
+pub struct ThinVecWithHeader<Header, Item> {
+    /// INVARIANT: Points to a valid heap allocation that contains `ThinVecInner<Header>`,
+    /// followed by (suitably aligned) `len` `Item`s.
+    ptr: NonNull<ThinVecInner<Header>>,
+    _marker: PhantomData<(Header, Box<[Item]>)>,
+}
+
+// SAFETY: We essentially own both the header and the items.
+unsafe impl<Header: Send, Item: Send> Send for ThinVecWithHeader<Header, Item> {}
+unsafe impl<Header: Sync, Item: Sync> Sync for ThinVecWithHeader<Header, Item> {}
+
+#[derive(Clone)]
+struct ThinVecInner<Header> {
+    header: Header,
+    len: usize,
+}
+
+impl<Header, Item> ThinVecWithHeader<Header, Item> {
+    /// # Safety
+    ///
+    /// The iterator must produce `len` elements.
+    #[inline]
+    unsafe fn from_trusted_len_iter(
+        header: Header,
+        len: usize,
+        items: impl Iterator<Item = Item>,
+    ) -> Self {
+        let (ptr, layout, items_offset) = Self::allocate(len);
+
+        struct DeallocGuard(*mut u8, Layout);
+        impl Drop for DeallocGuard {
+            fn drop(&mut self) {
+                // SAFETY: We allocated this above.
+                unsafe {
+                    dealloc(self.0, self.1);
+                }
+            }
+        }
+        let _dealloc_guard = DeallocGuard(ptr.as_ptr().cast::<u8>(), layout);
+
+        // INVARIANT: Between `0..1` there are only initialized items.
+        struct ItemsGuard<Item>(*mut Item, *mut Item);
+        impl<Item> Drop for ItemsGuard<Item> {
+            fn drop(&mut self) {
+                // SAFETY: Our invariant.
+                unsafe {
+                    slice_from_raw_parts_mut(self.0, self.1.offset_from(self.0) as usize)
+                        .drop_in_place();
+                }
+            }
+        }
+
+        // SAFETY: We allocated enough space.
+        let mut items_ptr = unsafe { ptr.as_ptr().byte_add(items_offset).cast::<Item>() };
+        // INVARIANT: There are zero elements in this range.
+        let mut items_guard = ItemsGuard(items_ptr, items_ptr);
+        items.for_each(|item| {
+            // SAFETY: Our precondition guarantee we won't get more than `len` items, and we allocated
+            // enough space for `len` items.
+            unsafe {
+                items_ptr.write(item);
+                items_ptr = items_ptr.add(1);
+            }
+            // INVARIANT: We just initialized this item.
+            items_guard.1 = items_ptr;
+        });
+
+        // SAFETY: We allocated enough space.
+        unsafe {
+            ptr.write(ThinVecInner { header, len });
+        }
+
+        std::mem::forget(items_guard);
+
+        std::mem::forget(_dealloc_guard);
+
+        // INVARIANT: We allocated and initialized all fields correctly.
+        Self { ptr, _marker: PhantomData }
+    }
+
+    #[inline]
+    fn allocate(len: usize) -> (NonNull<ThinVecInner<Header>>, Layout, usize) {
+        let (layout, items_offset) = Self::layout(len);
+        // SAFETY: We always have `len`, so our allocation cannot be zero-sized.
+        let ptr = unsafe { std::alloc::alloc(layout).cast::<ThinVecInner<Header>>() };
+        let Some(ptr) = NonNull::<ThinVecInner<Header>>::new(ptr) else {
+            handle_alloc_error(layout);
+        };
+        (ptr, layout, items_offset)
+    }
+
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(header: Header, items: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = Item>,
+    {
+        let items = items.into_iter();
+        // SAFETY: `TrustedLen` guarantees the iterator length is exact.
+        unsafe { Self::from_trusted_len_iter(header, items.len(), items) }
+    }
+
+    #[inline]
+    fn items_offset(&self) -> usize {
+        // SAFETY: We `pad_to_align()` in `layout()`, so at most where accessing past the end of the allocation,
+        // which is allowed.
+        unsafe {
+            Layout::new::<ThinVecInner<Header>>().extend(Layout::new::<Item>()).unwrap_unchecked().1
+        }
+    }
+
+    #[inline]
+    fn header_and_len(&self) -> &ThinVecInner<Header> {
+        // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+        unsafe { &*self.ptr.as_ptr() }
+    }
+
+    #[inline]
+    fn items_ptr(&self) -> *mut [Item] {
+        let len = self.header_and_len().len;
+        // SAFETY: `items_offset()` returns the correct offset of the items, where they are allocated.
+        let ptr = unsafe { self.ptr.as_ptr().byte_add(self.items_offset()).cast::<Item>() };
+        slice_from_raw_parts_mut(ptr, len)
+    }
+
+    #[inline]
+    pub fn header(&self) -> &Header {
+        &self.header_and_len().header
+    }
+
+    #[inline]
+    pub fn header_mut(&mut self) -> &mut Header {
+        // SAFETY: By `ptr`'s invariant, it is correctly allocated and initialized.
+        unsafe { &mut *addr_of_mut!((*self.ptr.as_ptr()).header) }
+    }
+
+    #[inline]
+    pub fn items(&self) -> &[Item] {
+        // SAFETY: `items_ptr()` gives a valid pointer.
+        unsafe { &*self.items_ptr() }
+    }
+
+    #[inline]
+    pub fn items_mut(&mut self) -> &mut [Item] {
+        // SAFETY: `items_ptr()` gives a valid pointer.
+        unsafe { &mut *self.items_ptr() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.header_and_len().len
+    }
+
+    #[inline]
+    fn layout(len: usize) -> (Layout, usize) {
+        let (layout, items_offset) = Layout::new::<ThinVecInner<Header>>()
+            .extend(Layout::array::<Item>(len).expect("too big `ThinVec` requested"))
+            .expect("too big `ThinVec` requested");
+        let layout = layout.pad_to_align();
+        (layout, items_offset)
+    }
+}
+
+/// # Safety
+///
+/// The length reported must be exactly the number of items yielded.
+pub unsafe trait TrustedLen: ExactSizeIterator {}
+
+unsafe impl<T> TrustedLen for std::vec::IntoIter<T> {}
+unsafe impl<T> TrustedLen for std::slice::Iter<'_, T> {}
+unsafe impl<'a, T: Clone + 'a, I: TrustedLen<Item = &'a T>> TrustedLen for std::iter::Cloned<I> {}
+unsafe impl<T, I: TrustedLen, F: FnMut(I::Item) -> T> TrustedLen for std::iter::Map<I, F> {}
+unsafe impl<T> TrustedLen for std::vec::Drain<'_, T> {}
+unsafe impl<T, const N: usize> TrustedLen for std::array::IntoIter<T, N> {}
+
+impl<Header: Clone, Item: Clone> Clone for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn clone(&self) -> Self {
+        Self::from_iter(self.header().clone(), self.items().iter().cloned())
+    }
+}
+
+impl<Header, Item> Drop for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn drop(&mut self) {
+        // This must come before we drop `header`, because after that we cannot make a reference to it in `len()`.
+        let len = self.len();
+
+        // SAFETY: The contents are allocated and initialized.
+        unsafe {
+            addr_of_mut!((*self.ptr.as_ptr()).header).drop_in_place();
+            self.items_ptr().drop_in_place();
+        }
+
+        let (layout, _) = Self::layout(len);
+        // SAFETY: This was allocated in `new()` with the same layout calculation.
+        unsafe {
+            dealloc(self.ptr.as_ptr().cast::<u8>(), layout);
+        }
+    }
+}
+
+impl<Header: fmt::Debug, Item: fmt::Debug> fmt::Debug for ThinVecWithHeader<Header, Item> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ThinVecWithHeader")
+            .field("header", self.header())
+            .field("items", &self.items())
+            .finish()
+    }
+}
+
+impl<Header: PartialEq, Item: PartialEq> PartialEq for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.header() == other.header() && self.items() == other.items()
+    }
+}
+
+impl<Header: Eq, Item: Eq> Eq for ThinVecWithHeader<Header, Item> {}
+
+impl<Header: Hash, Item: Hash> Hash for ThinVecWithHeader<Header, Item> {
+    #[inline]
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.header().hash(state);
+        self.items().hash(state);
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct ThinVec<T>(ThinVecWithHeader<(), T>);
+
+impl<T> ThinVec<T> {
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(values: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = T>,
+    {
+        Self(ThinVecWithHeader::from_iter((), values))
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    #[inline]
+    pub fn iter(&self) -> std::slice::Iter<'_, T> {
+        (**self).iter()
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+        (**self).iter_mut()
+    }
+}
+
+impl<T> Deref for ThinVec<T> {
+    type Target = [T];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.0.items()
+    }
+}
+
+impl<T> DerefMut for ThinVec<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0.items_mut()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a ThinVec<T> {
+    type IntoIter = std::slice::Iter<'a, T>;
+    type Item = &'a T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
+    type IntoIter = std::slice::IterMut<'a, T>;
+    type Item = &'a mut T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for ThinVec<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(&**self).finish()
+    }
+}
+
+/// A [`ThinVec`] that requires no allocation for the empty case.
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct EmptyOptimizedThinVec<T>(Option<ThinVec<T>>);
+
+impl<T> EmptyOptimizedThinVec<T> {
+    #[inline]
+    #[allow(clippy::should_implement_trait)]
+    pub fn from_iter<I>(values: I) -> Self
+    where
+        I: IntoIterator,
+        I::IntoIter: TrustedLen<Item = T>,
+    {
+        let values = values.into_iter();
+        if values.len() == 0 {
+            Self::empty()
+        } else {
+            Self(Some(ThinVec::from_iter(values)))
+        }
+    }
+
+    #[inline]
+    pub fn empty() -> Self {
+        Self(None)
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.0.as_ref().map_or(0, ThinVec::len)
+    }
+
+    #[inline]
+    pub fn iter(&self) -> std::slice::Iter<'_, T> {
+        (**self).iter()
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+        (**self).iter_mut()
+    }
+}
+
+impl<T> Default for EmptyOptimizedThinVec<T> {
+    #[inline]
+    fn default() -> Self {
+        Self::empty()
+    }
+}
+
+impl<T> Deref for EmptyOptimizedThinVec<T> {
+    type Target = [T];
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.0.as_deref().unwrap_or_default()
+    }
+}
+
+impl<T> DerefMut for EmptyOptimizedThinVec<T> {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.0.as_deref_mut().unwrap_or_default()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a EmptyOptimizedThinVec<T> {
+    type IntoIter = std::slice::Iter<'a, T>;
+    type Item = &'a T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut EmptyOptimizedThinVec<T> {
+    type IntoIter = std::slice::IterMut<'a, T>;
+    type Item = &'a mut T;
+
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter_mut()
+    }
+}
+
+impl<T: fmt::Debug> fmt::Debug for EmptyOptimizedThinVec<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(&**self).finish()
+    }
+}
+
+/// Syntax:
+///
+/// ```ignore
+/// thin_vec_with_header_struct! {
+///     pub new(pub(crate)) struct MyCoolStruct, MyCoolStructHeader {
+///         pub(crate) variable_length: [Ty],
+///         pub field1: CopyTy,
+///         pub field2: NonCopyTy; ref,
+///     }
+/// }
+/// ```
+#[doc(hidden)]
+#[macro_export]
+macro_rules! thin_vec_with_header_struct_ {
+    (@maybe_ref (ref) $($t:tt)*) => { &$($t)* };
+    (@maybe_ref () $($t:tt)*) => { $($t)* };
+    (
+        $vis:vis new($new_vis:vis) struct $struct:ident, $header:ident {
+            $items_vis:vis $items:ident : [$items_ty:ty],
+            $( $header_var_vis:vis $header_var:ident : $header_var_ty:ty $(; $ref:ident)?, )+
+        }
+    ) => {
+        #[derive(Debug, Clone, Eq, PartialEq, Hash)]
+        struct $header {
+            $( $header_var : $header_var_ty, )+
+        }
+
+        #[derive(Clone, Eq, PartialEq, Hash)]
+        $vis struct $struct($crate::thin_vec::ThinVecWithHeader<$header, $items_ty>);
+
+        impl $struct {
+            #[inline]
+            #[allow(unused)]
+            $new_vis fn new<I>(
+                $( $header_var: $header_var_ty, )+
+                $items: I,
+            ) -> Self
+            where
+                I: ::std::iter::IntoIterator,
+                I::IntoIter: $crate::thin_vec::TrustedLen<Item = $items_ty>,
+            {
+                Self($crate::thin_vec::ThinVecWithHeader::from_iter(
+                    $header { $( $header_var, )+ },
+                    $items,
+                ))
+            }
+
+            #[inline]
+            $items_vis fn $items(&self) -> &[$items_ty] {
+                self.0.items()
+            }
+
+            $(
+                #[inline]
+                $header_var_vis fn $header_var(&self) -> $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) $header_var_ty) {
+                    $crate::thin_vec_with_header_struct_!(@maybe_ref ($($ref)?) self.0.header().$header_var)
+                }
+            )+
+        }
+
+        impl ::std::fmt::Debug for $struct {
+            fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+                f.debug_struct(stringify!($struct))
+                    $( .field(stringify!($header_var), &self.$header_var()) )*
+                    .field(stringify!($items), &self.$items())
+                    .finish()
+            }
+        }
+    };
+}
+pub use crate::thin_vec_with_header_struct_ as thin_vec_with_header_struct;
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index fcb9b0ea354..51eaea54346 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -27,7 +27,6 @@ ra-ap-rustc_lexer.workspace = true
 
 parser.workspace = true
 stdx.workspace = true
-text-edit.workspace = true
 
 [dev-dependencies]
 rayon.workspace = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 90441c27f62..02c59646a99 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -657,7 +657,14 @@ TypeBoundList =
 TypeBound =
   Lifetime
 | ('~' 'const' | 'const')? 'async'? '?'? Type
-| 'use' GenericParamList
+| 'use' UseBoundGenericArgs
+
+UseBoundGenericArgs =
+ '<' (UseBoundGenericArg (',' UseBoundGenericArg)* ','?)? '>'
+
+UseBoundGenericArg =
+  Lifetime
+| NameRef
 
 //************************//
 //        Patterns        //
@@ -729,7 +736,7 @@ PathPat =
   Path
 
 OrPat =
-  (Pat ('|' Pat)* '|'?)
+  '|'? (Pat ('|' Pat)*)
 
 BoxPat =
   'box' Pat
diff --git a/src/tools/rust-analyzer/crates/syntax/src/algo.rs b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
index 8dc6d36a7e7..2acb2158318 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/algo.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/algo.rs
@@ -1,11 +1,6 @@
 //! Collection of assorted algorithms for syntax trees.
 
-use std::hash::BuildHasherDefault;
-
-use indexmap::IndexMap;
 use itertools::Itertools;
-use rustc_hash::FxHashMap;
-use text_edit::TextEditBuilder;
 
 use crate::{
     AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
@@ -101,559 +96,3 @@ pub fn neighbor<T: AstNode>(me: &T, direction: Direction) -> Option<T> {
 pub fn has_errors(node: &SyntaxNode) -> bool {
     node.children().any(|it| it.kind() == SyntaxKind::ERROR)
 }
-
-type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<rustc_hash::FxHasher>>;
-
-#[derive(Debug, Hash, PartialEq, Eq)]
-enum TreeDiffInsertPos {
-    After(SyntaxElement),
-    AsFirstChild(SyntaxElement),
-}
-
-#[derive(Debug)]
-pub struct TreeDiff {
-    replacements: FxHashMap<SyntaxElement, SyntaxElement>,
-    deletions: Vec<SyntaxElement>,
-    // the vec as well as the indexmap are both here to preserve order
-    insertions: FxIndexMap<TreeDiffInsertPos, Vec<SyntaxElement>>,
-}
-
-impl TreeDiff {
-    pub fn into_text_edit(&self, builder: &mut TextEditBuilder) {
-        let _p = tracing::info_span!("into_text_edit").entered();
-
-        for (anchor, to) in &self.insertions {
-            let offset = match anchor {
-                TreeDiffInsertPos::After(it) => it.text_range().end(),
-                TreeDiffInsertPos::AsFirstChild(it) => it.text_range().start(),
-            };
-            to.iter().for_each(|to| builder.insert(offset, to.to_string()));
-        }
-        for (from, to) in &self.replacements {
-            builder.replace(from.text_range(), to.to_string());
-        }
-        for text_range in self.deletions.iter().map(SyntaxElement::text_range) {
-            builder.delete(text_range);
-        }
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.replacements.is_empty() && self.deletions.is_empty() && self.insertions.is_empty()
-    }
-}
-
-/// Finds a (potentially minimal) diff, which, applied to `from`, will result in `to`.
-///
-/// Specifically, returns a structure that consists of a replacements, insertions and deletions
-/// such that applying this map on `from` will result in `to`.
-///
-/// This function tries to find a fine-grained diff.
-pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
-    let _p = tracing::info_span!("diff").entered();
-
-    let mut diff = TreeDiff {
-        replacements: FxHashMap::default(),
-        insertions: FxIndexMap::default(),
-        deletions: Vec::new(),
-    };
-    let (from, to) = (from.clone().into(), to.clone().into());
-
-    if !syntax_element_eq(&from, &to) {
-        go(&mut diff, from, to);
-    }
-    return diff;
-
-    fn syntax_element_eq(lhs: &SyntaxElement, rhs: &SyntaxElement) -> bool {
-        lhs.kind() == rhs.kind()
-            && lhs.text_range().len() == rhs.text_range().len()
-            && match (&lhs, &rhs) {
-                (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => {
-                    lhs == rhs || lhs.text() == rhs.text()
-                }
-                (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => lhs.text() == rhs.text(),
-                _ => false,
-            }
-    }
-
-    // FIXME: this is horribly inefficient. I bet there's a cool algorithm to diff trees properly.
-    fn go(diff: &mut TreeDiff, lhs: SyntaxElement, rhs: SyntaxElement) {
-        let (lhs, rhs) = match lhs.as_node().zip(rhs.as_node()) {
-            Some((lhs, rhs)) => (lhs, rhs),
-            _ => {
-                cov_mark::hit!(diff_node_token_replace);
-                diff.replacements.insert(lhs, rhs);
-                return;
-            }
-        };
-
-        let mut look_ahead_scratch = Vec::default();
-
-        let mut rhs_children = rhs.children_with_tokens();
-        let mut lhs_children = lhs.children_with_tokens();
-        let mut last_lhs = None;
-        loop {
-            let lhs_child = lhs_children.next();
-            match (lhs_child.clone(), rhs_children.next()) {
-                (None, None) => break,
-                (None, Some(element)) => {
-                    let insert_pos = match last_lhs.clone() {
-                        Some(prev) => {
-                            cov_mark::hit!(diff_insert);
-                            TreeDiffInsertPos::After(prev)
-                        }
-                        // first iteration, insert into out parent as the first child
-                        None => {
-                            cov_mark::hit!(diff_insert_as_first_child);
-                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
-                        }
-                    };
-                    diff.insertions.entry(insert_pos).or_default().push(element);
-                }
-                (Some(element), None) => {
-                    cov_mark::hit!(diff_delete);
-                    diff.deletions.push(element);
-                }
-                (Some(ref lhs_ele), Some(ref rhs_ele)) if syntax_element_eq(lhs_ele, rhs_ele) => {}
-                (Some(lhs_ele), Some(rhs_ele)) => {
-                    // nodes differ, look for lhs_ele in rhs, if its found we can mark everything up
-                    // until that element as insertions. This is important to keep the diff minimal
-                    // in regards to insertions that have been actually done, this is important for
-                    // use insertions as we do not want to replace the entire module node.
-                    look_ahead_scratch.push(rhs_ele.clone());
-                    let mut rhs_children_clone = rhs_children.clone();
-                    let mut insert = false;
-                    for rhs_child in &mut rhs_children_clone {
-                        if syntax_element_eq(&lhs_ele, &rhs_child) {
-                            cov_mark::hit!(diff_insertions);
-                            insert = true;
-                            break;
-                        }
-                        look_ahead_scratch.push(rhs_child);
-                    }
-                    let drain = look_ahead_scratch.drain(..);
-                    if insert {
-                        let insert_pos = if let Some(prev) = last_lhs.clone().filter(|_| insert) {
-                            TreeDiffInsertPos::After(prev)
-                        } else {
-                            cov_mark::hit!(insert_first_child);
-                            TreeDiffInsertPos::AsFirstChild(lhs.clone().into())
-                        };
-
-                        diff.insertions.entry(insert_pos).or_default().extend(drain);
-                        rhs_children = rhs_children_clone;
-                    } else {
-                        go(diff, lhs_ele, rhs_ele);
-                    }
-                }
-            }
-            last_lhs = lhs_child.or(last_lhs);
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::{expect, Expect};
-    use itertools::Itertools;
-    use parser::{Edition, SyntaxKind};
-    use text_edit::TextEdit;
-
-    use crate::{AstNode, SyntaxElement};
-
-    #[test]
-    fn replace_node_token() {
-        cov_mark::check!(diff_node_token_replace);
-        check_diff(
-            r#"use node;"#,
-            r#"ident"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-                Line 0: Token(USE_KW@0..3 "use") -> ident
-
-                deletions:
-
-                Line 1: " "
-                Line 1: node
-                Line 1: ;
-            "#]],
-        );
-    }
-
-    #[test]
-    fn replace_parent() {
-        cov_mark::check!(diff_insert_as_first_child);
-        check_diff(
-            r#""#,
-            r#"use foo::bar;"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: AsFirstChild(Node(SOURCE_FILE@0..0))
-                -> use foo::bar;
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn insert_last() {
-        cov_mark::check!(diff_insert);
-        check_diff(
-            r#"
-use foo;
-use bar;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Node(USE@10..18))
-                -> "\n"
-                -> use baz;
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn insert_middle() {
-        check_diff(
-            r#"
-use foo;
-use baz;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Token(WHITESPACE@9..10 "\n"))
-                -> use bar;
-                -> "\n"
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        )
-    }
-
-    #[test]
-    fn insert_first() {
-        check_diff(
-            r#"
-use bar;
-use baz;"#,
-            r#"
-use foo;
-use bar;
-use baz;"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: After(Token(WHITESPACE@0..1 "\n"))
-                -> use foo;
-                -> "\n"
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        )
-    }
-
-    #[test]
-    fn first_child_insertion() {
-        cov_mark::check!(insert_first_child);
-        check_diff(
-            r#"fn main() {
-        stdi
-    }"#,
-            r#"use foo::bar;
-
-    fn main() {
-        stdi
-    }"#,
-            expect![[r#"
-                insertions:
-
-                Line 0: AsFirstChild(Node(SOURCE_FILE@0..30))
-                -> use foo::bar;
-                -> "\n\n    "
-
-                replacements:
-
-
-
-                deletions:
-
-
-            "#]],
-        );
-    }
-
-    #[test]
-    fn delete_last() {
-        cov_mark::check!(diff_delete);
-        check_diff(
-            r#"use foo;
-            use bar;"#,
-            r#"use foo;"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-
-
-                deletions:
-
-                Line 1: "\n            "
-                Line 2: use bar;
-            "#]],
-        );
-    }
-
-    #[test]
-    fn delete_middle() {
-        cov_mark::check!(diff_insertions);
-        check_diff(
-            r#"
-use expect_test::{expect, Expect};
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
-            r#"
-use expect_test::{expect, Expect};
-
-use crate::AstNode;
-"#,
-            expect![[r#"
-                insertions:
-
-                Line 1: After(Node(USE@1..35))
-                -> "\n\n"
-                -> use crate::AstNode;
-
-                replacements:
-
-
-
-                deletions:
-
-                Line 2: use text_edit::TextEdit;
-                Line 3: "\n\n"
-                Line 4: use crate::AstNode;
-                Line 5: "\n"
-            "#]],
-        )
-    }
-
-    #[test]
-    fn delete_first() {
-        check_diff(
-            r#"
-use text_edit::TextEdit;
-
-use crate::AstNode;
-"#,
-            r#"
-use crate::AstNode;
-"#,
-            expect![[r#"
-                insertions:
-
-
-
-                replacements:
-
-                Line 2: Token(IDENT@5..14 "text_edit") -> crate
-                Line 2: Token(IDENT@16..24 "TextEdit") -> AstNode
-                Line 2: Token(WHITESPACE@25..27 "\n\n") -> "\n"
-
-                deletions:
-
-                Line 3: use crate::AstNode;
-                Line 4: "\n"
-            "#]],
-        )
-    }
-
-    #[test]
-    fn merge_use() {
-        check_diff(
-            r#"
-use std::{
-    fmt,
-    hash::BuildHasherDefault,
-    ops::{self, RangeInclusive},
-};
-"#,
-            r#"
-use std::fmt;
-use std::hash::BuildHasherDefault;
-use std::ops::{self, RangeInclusive};
-"#,
-            expect![[r#"
-                insertions:
-
-                Line 2: After(Node(PATH_SEGMENT@5..8))
-                -> ::
-                -> fmt
-                Line 6: After(Token(WHITESPACE@86..87 "\n"))
-                -> use std::hash::BuildHasherDefault;
-                -> "\n"
-                -> use std::ops::{self, RangeInclusive};
-                -> "\n"
-
-                replacements:
-
-                Line 2: Token(IDENT@5..8 "std") -> std
-
-                deletions:
-
-                Line 2: ::
-                Line 2: {
-                    fmt,
-                    hash::BuildHasherDefault,
-                    ops::{self, RangeInclusive},
-                }
-            "#]],
-        )
-    }
-
-    #[test]
-    fn early_return_assist() {
-        check_diff(
-            r#"
-fn main() {
-    if let Ok(x) = Err(92) {
-        foo(x);
-    }
-}
-            "#,
-            r#"
-fn main() {
-    let x = match Err(92) {
-        Ok(it) => it,
-        _ => return,
-    };
-    foo(x);
-}
-            "#,
-            expect![[r#"
-                insertions:
-
-                Line 3: After(Node(BLOCK_EXPR@40..63))
-                -> " "
-                -> match Err(92) {
-                        Ok(it) => it,
-                        _ => return,
-                    }
-                -> ;
-                Line 3: After(Node(IF_EXPR@17..63))
-                -> "\n    "
-                -> foo(x);
-
-                replacements:
-
-                Line 3: Token(IF_KW@17..19 "if") -> let
-                Line 3: Token(LET_KW@20..23 "let") -> x
-                Line 3: Node(BLOCK_EXPR@40..63) -> =
-
-                deletions:
-
-                Line 3: " "
-                Line 3: Ok(x)
-                Line 3: " "
-                Line 3: =
-                Line 3: " "
-                Line 3: Err(92)
-            "#]],
-        )
-    }
-
-    fn check_diff(from: &str, to: &str, expected_diff: Expect) {
-        let from_node = crate::SourceFile::parse(from, Edition::CURRENT).tree().syntax().clone();
-        let to_node = crate::SourceFile::parse(to, Edition::CURRENT).tree().syntax().clone();
-        let diff = super::diff(&from_node, &to_node);
-
-        let line_number =
-            |syn: &SyntaxElement| from[..syn.text_range().start().into()].lines().count();
-
-        let fmt_syntax = |syn: &SyntaxElement| match syn.kind() {
-            SyntaxKind::WHITESPACE => format!("{:?}", syn.to_string()),
-            _ => format!("{syn}"),
-        };
-
-        let insertions =
-            diff.insertions.iter().format_with("\n", |(k, v), f| -> Result<(), std::fmt::Error> {
-                f(&format!(
-                    "Line {}: {:?}\n-> {}",
-                    line_number(match k {
-                        super::TreeDiffInsertPos::After(syn) => syn,
-                        super::TreeDiffInsertPos::AsFirstChild(syn) => syn,
-                    }),
-                    k,
-                    v.iter().format_with("\n-> ", |v, f| f(&fmt_syntax(v)))
-                ))
-            });
-
-        let replacements = diff
-            .replacements
-            .iter()
-            .sorted_by_key(|(syntax, _)| syntax.text_range().start())
-            .format_with("\n", |(k, v), f| {
-                f(&format!("Line {}: {k:?} -> {}", line_number(k), fmt_syntax(v)))
-            });
-
-        let deletions = diff
-            .deletions
-            .iter()
-            .format_with("\n", |v, f| f(&format!("Line {}: {}", line_number(v), fmt_syntax(v))));
-
-        let actual = format!(
-            "insertions:\n\n{insertions}\n\nreplacements:\n\n{replacements}\n\ndeletions:\n\n{deletions}\n"
-        );
-        expected_diff.assert_eq(&actual);
-
-        let mut from = from.to_owned();
-        let mut text_edit = TextEdit::builder();
-        diff.into_text_edit(&mut text_edit);
-        text_edit.finish().apply(&mut from);
-        assert_eq!(&*from, to, "diff did not turn `from` to `to`");
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
index 6ed205e2856..f3053f59836 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs
@@ -232,6 +232,10 @@ impl ast::RangeExpr {
             Some((ix, token, bin_op))
         })
     }
+
+    pub fn is_range_full(&self) -> bool {
+        support::children::<Expr>(&self.syntax).next().is_none()
+    }
 }
 
 impl RangeItem for ast::RangeExpr {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 4f8bff489cf..23d2b355a94 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1283,6 +1283,8 @@ pub struct OrPat {
 impl OrPat {
     #[inline]
     pub fn pats(&self) -> AstChildren<Pat> { support::children(&self.syntax) }
+    #[inline]
+    pub fn pipe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![|]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1994,12 +1996,14 @@ pub struct TypeBound {
 }
 impl TypeBound {
     #[inline]
-    pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
-    #[inline]
     pub fn lifetime(&self) -> Option<Lifetime> { support::child(&self.syntax) }
     #[inline]
     pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
     #[inline]
+    pub fn use_bound_generic_args(&self) -> Option<UseBoundGenericArgs> {
+        support::child(&self.syntax)
+    }
+    #[inline]
     pub fn question_mark_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![?]) }
     #[inline]
     pub fn async_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![async]) }
@@ -2077,6 +2081,21 @@ impl Use {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UseBoundGenericArgs {
+    pub(crate) syntax: SyntaxNode,
+}
+impl UseBoundGenericArgs {
+    #[inline]
+    pub fn use_bound_generic_args(&self) -> AstChildren<UseBoundGenericArg> {
+        support::children(&self.syntax)
+    }
+    #[inline]
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    #[inline]
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct UseTree {
     pub(crate) syntax: SyntaxNode,
 }
@@ -2403,6 +2422,12 @@ pub enum Type {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum UseBoundGenericArg {
+    Lifetime(Lifetime),
+    NameRef(NameRef),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct AnyHasArgList {
     pub(crate) syntax: SyntaxNode,
 }
@@ -4435,6 +4460,20 @@ impl AstNode for Use {
     #[inline]
     fn syntax(&self) -> &SyntaxNode { &self.syntax }
 }
+impl AstNode for UseBoundGenericArgs {
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { kind == USE_BOUND_GENERIC_ARGS }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
 impl AstNode for UseTree {
     #[inline]
     fn can_cast(kind: SyntaxKind) -> bool { kind == USE_TREE }
@@ -5560,6 +5599,34 @@ impl AstNode for Type {
         }
     }
 }
+impl From<Lifetime> for UseBoundGenericArg {
+    #[inline]
+    fn from(node: Lifetime) -> UseBoundGenericArg { UseBoundGenericArg::Lifetime(node) }
+}
+impl From<NameRef> for UseBoundGenericArg {
+    #[inline]
+    fn from(node: NameRef) -> UseBoundGenericArg { UseBoundGenericArg::NameRef(node) }
+}
+impl AstNode for UseBoundGenericArg {
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { matches!(kind, LIFETIME | NAME_REF) }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        let res = match syntax.kind() {
+            LIFETIME => UseBoundGenericArg::Lifetime(Lifetime { syntax }),
+            NAME_REF => UseBoundGenericArg::NameRef(NameRef { syntax }),
+            _ => return None,
+        };
+        Some(res)
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode {
+        match self {
+            UseBoundGenericArg::Lifetime(it) => &it.syntax,
+            UseBoundGenericArg::NameRef(it) => &it.syntax,
+        }
+    }
+}
 impl AnyHasArgList {
     #[inline]
     pub fn new<T: ast::HasArgList>(node: T) -> AnyHasArgList {
@@ -6570,6 +6637,11 @@ impl std::fmt::Display for Type {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for UseBoundGenericArg {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for Abi {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
@@ -7275,6 +7347,11 @@ impl std::fmt::Display for Use {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for UseBoundGenericArgs {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for UseTree {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index 693bfe330bd..6ec73e76f78 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -795,7 +795,7 @@ pub enum TypeBoundKind {
     /// for<'a> ...
     ForType(ast::ForType),
     /// use
-    Use(ast::GenericParamList),
+    Use(ast::UseBoundGenericArgs),
     /// 'a
     Lifetime(ast::Lifetime),
 }
@@ -806,8 +806,8 @@ impl ast::TypeBound {
             TypeBoundKind::PathType(path_type)
         } else if let Some(for_type) = support::children(self.syntax()).next() {
             TypeBoundKind::ForType(for_type)
-        } else if let Some(generic_param_list) = self.generic_param_list() {
-            TypeBoundKind::Use(generic_param_list)
+        } else if let Some(args) = self.use_bound_generic_args() {
+            TypeBoundKind::Use(args)
         } else if let Some(lifetime) = self.lifetime() {
             TypeBoundKind::Lifetime(lifetime)
         } else {
@@ -1140,3 +1140,13 @@ impl From<ast::AssocItem> for ast::AnyHasAttrs {
         Self::new(node)
     }
 }
+
+impl ast::OrPat {
+    pub fn leading_pipe(&self) -> Option<SyntaxToken> {
+        self.syntax
+            .children_with_tokens()
+            .find(|it| !it.kind().is_trivia())
+            .and_then(NodeOrToken::into_token)
+            .filter(|it| it.kind() == T![|])
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
index 682dcd7cc44..fd20e603edc 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
@@ -5,7 +5,6 @@
 use std::str::{self, FromStr};
 
 use parser::Edition;
-use text_edit::Indel;
 
 use crate::{validation, AstNode, SourceFile, TextRange};
 
@@ -22,7 +21,8 @@ pub fn check_parser(text: &str) {
 #[derive(Debug, Clone)]
 pub struct CheckReparse {
     text: String,
-    edit: Indel,
+    delete: TextRange,
+    insert: String,
     edited_text: String,
 }
 
@@ -43,14 +43,13 @@ impl CheckReparse {
             TextRange::at(delete_start.try_into().unwrap(), delete_len.try_into().unwrap());
         let edited_text =
             format!("{}{}{}", &text[..delete_start], &insert, &text[delete_start + delete_len..]);
-        let edit = Indel { insert, delete };
-        Some(CheckReparse { text, edit, edited_text })
+        Some(CheckReparse { text, insert, delete, edited_text })
     }
 
     #[allow(clippy::print_stderr)]
     pub fn run(&self) {
         let parse = SourceFile::parse(&self.text, Edition::CURRENT);
-        let new_parse = parse.reparse(&self.edit, Edition::CURRENT);
+        let new_parse = parse.reparse(self.delete, &self.insert, Edition::CURRENT);
         check_file_invariants(&new_parse.tree());
         assert_eq!(&new_parse.tree().syntax().text().to_string(), &self.edited_text);
         let full_reparse = SourceFile::parse(&self.edited_text, Edition::CURRENT);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index c1554c4b294..c9e9f468dca 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -44,10 +44,9 @@ pub mod syntax_editor;
 pub mod ted;
 pub mod utils;
 
-use std::marker::PhantomData;
+use std::{marker::PhantomData, ops::Range};
 
 use stdx::format_to;
-use text_edit::Indel;
 use triomphe::Arc;
 
 pub use crate::{
@@ -150,16 +149,22 @@ impl Parse<SourceFile> {
         buf
     }
 
-    pub fn reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
-        self.incremental_reparse(indel, edition)
-            .unwrap_or_else(|| self.full_reparse(indel, edition))
+    pub fn reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
+        self.incremental_reparse(delete, insert, edition)
+            .unwrap_or_else(|| self.full_reparse(delete, insert, edition))
     }
 
-    fn incremental_reparse(&self, indel: &Indel, edition: Edition) -> Option<Parse<SourceFile>> {
+    fn incremental_reparse(
+        &self,
+        delete: TextRange,
+        insert: &str,
+        edition: Edition,
+    ) -> Option<Parse<SourceFile>> {
         // FIXME: validation errors are not handled here
         parsing::incremental_reparse(
             self.tree().syntax(),
-            indel,
+            delete,
+            insert,
             self.errors.as_deref().unwrap_or_default().iter().cloned(),
             edition,
         )
@@ -170,9 +175,9 @@ impl Parse<SourceFile> {
         })
     }
 
-    fn full_reparse(&self, indel: &Indel, edition: Edition) -> Parse<SourceFile> {
+    fn full_reparse(&self, delete: TextRange, insert: &str, edition: Edition) -> Parse<SourceFile> {
         let mut text = self.tree().syntax().text().to_string();
-        indel.apply(&mut text);
+        text.replace_range(Range::<usize>::from(delete), insert);
         SourceFile::parse(&text, edition)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
index a5cc4e90dfb..f2eab18c279 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
@@ -6,8 +6,9 @@
 //!   - otherwise, we search for the nearest `{}` block which contains the edit
 //!     and try to parse only this block.
 
+use std::ops::Range;
+
 use parser::{Edition, Reparser};
-use text_edit::Indel;
 
 use crate::{
     parsing::build_tree,
@@ -19,38 +20,48 @@ use crate::{
 
 pub(crate) fn incremental_reparse(
     node: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     errors: impl IntoIterator<Item = SyntaxError>,
     edition: Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    if let Some((green, new_errors, old_range)) = reparse_token(node, edit, edition) {
-        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+    if let Some((green, new_errors, old_range)) = reparse_token(node, delete, insert, edition) {
+        return Some((
+            green,
+            merge_errors(errors, new_errors, old_range, delete, insert),
+            old_range,
+        ));
     }
 
-    if let Some((green, new_errors, old_range)) = reparse_block(node, edit, edition) {
-        return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
+    if let Some((green, new_errors, old_range)) = reparse_block(node, delete, insert, edition) {
+        return Some((
+            green,
+            merge_errors(errors, new_errors, old_range, delete, insert),
+            old_range,
+        ));
     }
     None
 }
 
 fn reparse_token(
     root: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     edition: Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    let prev_token = root.covering_element(edit.delete).as_token()?.clone();
+    let prev_token = root.covering_element(delete).as_token()?.clone();
     let prev_token_kind = prev_token.kind();
     match prev_token_kind {
         WHITESPACE | COMMENT | IDENT | STRING | BYTE_STRING | C_STRING => {
             if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
                 // removing a new line may extends previous token
-                let deleted_range = edit.delete - prev_token.text_range().start();
+                let deleted_range = delete - prev_token.text_range().start();
                 if prev_token.text()[deleted_range].contains('\n') {
                     return None;
                 }
             }
 
-            let mut new_text = get_text_after_edit(prev_token.clone().into(), edit);
+            let mut new_text = get_text_after_edit(prev_token.clone().into(), delete, insert);
             let (new_token_kind, new_err) = parser::LexedStr::single_token(edition, &new_text)?;
 
             if new_token_kind != prev_token_kind
@@ -85,11 +96,12 @@ fn reparse_token(
 
 fn reparse_block(
     root: &SyntaxNode,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
     edition: parser::Edition,
 ) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
-    let (node, reparser) = find_reparsable_node(root, edit.delete)?;
-    let text = get_text_after_edit(node.clone().into(), edit);
+    let (node, reparser) = find_reparsable_node(root, delete)?;
+    let text = get_text_after_edit(node.clone().into(), delete, insert);
 
     let lexed = parser::LexedStr::new(edition, text.as_str());
     let parser_input = lexed.to_input(edition);
@@ -104,14 +116,14 @@ fn reparse_block(
     Some((node.replace_with(green), new_parser_errors, node.text_range()))
 }
 
-fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
-    let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone());
+fn get_text_after_edit(element: SyntaxElement, mut delete: TextRange, insert: &str) -> String {
+    delete -= element.text_range().start();
 
     let mut text = match element {
         NodeOrToken::Token(token) => token.text().to_owned(),
         NodeOrToken::Node(node) => node.text().to_string(),
     };
-    edit.apply(&mut text);
+    text.replace_range(Range::<usize>::from(delete), insert);
     text
 }
 
@@ -153,7 +165,8 @@ fn merge_errors(
     old_errors: impl IntoIterator<Item = SyntaxError>,
     new_errors: Vec<SyntaxError>,
     range_before_reparse: TextRange,
-    edit: &Indel,
+    delete: TextRange,
+    insert: &str,
 ) -> Vec<SyntaxError> {
     let mut res = Vec::new();
 
@@ -162,8 +175,8 @@ fn merge_errors(
         if old_err_range.end() <= range_before_reparse.start() {
             res.push(old_err);
         } else if old_err_range.start() >= range_before_reparse.end() {
-            let inserted_len = TextSize::of(&edit.insert);
-            res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
+            let inserted_len = TextSize::of(insert);
+            res.push(old_err.with_range((old_err_range + inserted_len) - delete.len()));
             // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
         }
     }
@@ -177,6 +190,8 @@ fn merge_errors(
 
 #[cfg(test)]
 mod tests {
+    use std::ops::Range;
+
     use parser::Edition;
     use test_utils::{assert_eq_text, extract_range};
 
@@ -185,10 +200,9 @@ mod tests {
 
     fn do_check(before: &str, replace_with: &str, reparsed_len: u32) {
         let (range, before) = extract_range(before);
-        let edit = Indel::replace(range, replace_with.to_owned());
         let after = {
             let mut after = before.clone();
-            edit.apply(&mut after);
+            after.replace_range(Range::<usize>::from(range), replace_with);
             after
         };
 
@@ -197,7 +211,8 @@ mod tests {
             let before = SourceFile::parse(&before, Edition::CURRENT);
             let (green, new_errors, range) = incremental_reparse(
                 before.tree().syntax(),
-                &edit,
+                range,
+                replace_with,
                 before.errors.as_deref().unwrap_or_default().iter().cloned(),
                 Edition::CURRENT,
             )
diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
deleted file mode 100644
index dc6b3d31a09..00000000000
--- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-[package]
-name = "text-edit"
-version = "0.0.0"
-repository.workspace = true
-description = "Representation of a `TextEdit` for rust-analyzer."
-
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-rust-version.workspace = true
-
-[lib]
-doctest = false
-
-[dependencies]
-itertools.workspace = true
-text-size.workspace = true
-
-[lints]
-workspace = true
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/tt/src/buffer.rs b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
index 1319739371f..acb7e2d6c51 100644
--- a/src/tools/rust-analyzer/crates/tt/src/buffer.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
@@ -134,7 +134,7 @@ pub enum TokenTreeRef<'a, Span> {
     Leaf(&'a Leaf<Span>, &'a TokenTree<Span>),
 }
 
-impl<'a, Span: Copy> TokenTreeRef<'a, Span> {
+impl<Span: Copy> TokenTreeRef<'_, Span> {
     pub fn span(&self) -> Span {
         match self {
             TokenTreeRef::Subtree(subtree, _) => subtree.delimiter.open,
diff --git a/src/tools/rust-analyzer/editors/code/.vscodeignore b/src/tools/rust-analyzer/editors/code/.vscodeignore
index 09dc27056b3..1712a1477e6 100644
--- a/src/tools/rust-analyzer/editors/code/.vscodeignore
+++ b/src/tools/rust-analyzer/editors/code/.vscodeignore
@@ -12,3 +12,4 @@
 !ra_syntax_tree.tmGrammar.json
 !server
 !README.md
+!walkthrough-setup-tips.md
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index e55eceff781..6eebdf9f016 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -3224,10 +3224,9 @@
                     {
                         "id": "setup",
                         "title": "Useful Setup Tips",
-                        "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the following to your settings.json will mark all Rust library sources as readonly:\n```json\n\"files.readonlyInclude\": {\n    \"**/.cargo/registry/src/**/*.rs\": true,\n    \"**/lib/rustlib/src/rust/library/**/*.rs\": true,\n},\n```\n\n**Check on Save**\n\nBy default, rust-analyzer will run `cargo check` on your codebase when you save a file, rendering diagnostics emitted by `cargo check` within your code. This can potentially collide with other `cargo` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the `rust-analyzer.checkOnSave` configuration and running the `rust-analyzer: Run flycheck` command on-demand instead.",
+                        "description": "There are a couple of things you might want to configure upfront to your tastes. We'll name a few here but be sure to check out the docs linked below!\n\n**Marking library sources as readonly**\n\nAdding the snippet on the right to your settings.json will mark all Rust library sources as readonly.\n\n**Check on Save**\n\nBy default, rust-analyzer will run ``cargo check`` on your codebase when you save a file, rendering diagnostics emitted by ``cargo check`` within your code. This can potentially collide with other ``cargo`` commands running concurrently, blocking them from running for a certain amount of time. In these cases it is recommended to disable the ``rust-analyzer.checkOnSave`` configuration and running the ``rust-analyzer: Run flycheck`` command on-demand instead.",
                         "media": {
-                            "image": "./icon.png",
-                            "altText": "rust-analyzer logo"
+                            "markdown": "./walkthrough-setup-tips.md"
                         }
                     },
                     {
@@ -3245,7 +3244,7 @@
                     {
                         "id": "faq",
                         "title": "FAQ",
-                        "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the `editor.inlayHints.enabled` setting.",
+                        "description": "What are these code hints that are being inserted into my code?\n\nThese hints are called inlay hints which rust-analyzer support and are enabled by default in VSCode. If you wish to disable them you can do so via the ``editor.inlayHints.enabled`` setting.",
                         "media": {
                             "image": "icon.png",
                             "altText": "rust-analyzer logo"
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 0f2a758db42..234fe6ab024 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -446,7 +446,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 return;
         }
         if (status.message) {
-            statusBar.tooltip.appendText(status.message);
+            statusBar.tooltip.appendMarkdown(status.message);
         }
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendMarkdown("\n\n---\n\n");
diff --git a/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
new file mode 100644
index 00000000000..fda4ac80023
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/walkthrough-setup-tips.md
@@ -0,0 +1,10 @@
+# Settings Example
+
+Add the following to settings.json to mark Rust library sources as read-only:
+
+```json
+"files.readonlyInclude": {
+  "**/.cargo/registry/src/**/*.rs": true,
+  "**/lib/rustlib/src/rust/library/**/*.rs": true,
+},
+```
diff --git a/src/tools/rust-analyzer/rust-bors.toml b/src/tools/rust-analyzer/rust-bors.toml
deleted file mode 100644
index c31ba66c50f..00000000000
--- a/src/tools/rust-analyzer/rust-bors.toml
+++ /dev/null
@@ -1 +0,0 @@
-timeout = 3600
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index bc324402a96..ffb312d06e6 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-1de57a5ce952c722f7053aeacfc6c90bc139b678
+a9d17627d241645a54c1134a20f1596127fedb60
diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs
index 4c7b07c5e02..bc04b9474f2 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen.rs
@@ -79,7 +79,7 @@ impl CommentBlock {
         let mut block = dummy_block.clone();
         for (line_num, line) in lines.enumerate() {
             match line.strip_prefix("//") {
-                Some(mut contents) => {
+                Some(mut contents) if !contents.starts_with('/') => {
                     if let Some('/' | '!') = contents.chars().next() {
                         contents = &contents[1..];
                         block.is_doc = true;
@@ -89,7 +89,7 @@ impl CommentBlock {
                     }
                     block.contents.push(contents.to_owned());
                 }
-                None => {
+                _ => {
                     if !block.contents.is_empty() {
                         let block = mem::replace(&mut block, dummy_block.clone());
                         res.push(block);
diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs
index 742cf7f609a..c6a0be8aeb9 100644
--- a/src/tools/rust-analyzer/xtask/src/dist.rs
+++ b/src/tools/rust-analyzer/xtask/src/dist.rs
@@ -101,9 +101,10 @@ fn dist_server(
     cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release").run()?;
 
     let dst = Path::new("dist").join(&target.artifact_name);
-    gzip(&target.server_path, &dst.with_extension("gz"))?;
     if target_name.contains("-windows-") {
         zip(&target.server_path, target.symbols_path.as_ref(), &dst.with_extension("zip"))?;
+    } else {
+        gzip(&target.server_path, &dst.with_extension("gz"))?;
     }
 
     Ok(())
diff --git a/src/tools/rust-analyzer/xtask/src/release/changelog.rs b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
index 086a4d463ea..343a9efbbc8 100644
--- a/src/tools/rust-analyzer/xtask/src/release/changelog.rs
+++ b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
@@ -128,9 +128,10 @@ fn unescape(s: &str) -> String {
 }
 
 fn parse_pr_number(s: &str) -> Option<u32> {
-    const BORS_PREFIX: &str = "Merge #";
+    const GITHUB_PREFIX: &str = "Merge pull request #";
     const HOMU_PREFIX: &str = "Auto merge of #";
-    if let Some(s) = s.strip_prefix(BORS_PREFIX) {
+    if let Some(s) = s.strip_prefix(GITHUB_PREFIX) {
+        let s = if let Some(space) = s.find(' ') { &s[..space] } else { s };
         s.parse().ok()
     } else if let Some(s) = s.strip_prefix(HOMU_PREFIX) {
         if let Some(space) = s.find(' ') {
diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs
index 0268e2473c0..c3d531344a1 100644
--- a/src/tools/rust-analyzer/xtask/src/tidy.rs
+++ b/src/tools/rust-analyzer/xtask/src/tidy.rs
@@ -223,7 +223,7 @@ struct TidyDocs {
 impl TidyDocs {
     fn visit(&mut self, path: &Path, text: &str) {
         // Tests and diagnostic fixes don't need module level comments.
-        if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa"]) {
+        if is_exclude_dir(path, &["tests", "test_data", "fixes", "grammar", "ra-salsa", "stdx"]) {
             return;
         }
 
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 94f8d23c158..932a58788e0 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -4102,7 +4102,6 @@ ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs
 ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs
 ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs
 ui/type-alias-impl-trait/issue-57611-trait-alias.rs
-ui/type-alias-impl-trait/issue-57700.rs
 ui/type-alias-impl-trait/issue-57807-associated-type.rs
 ui/type-alias-impl-trait/issue-57961.rs
 ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs
diff --git a/tests/assembly/riscv-soft-abi-with-float-features.rs b/tests/assembly/riscv-soft-abi-with-float-features.rs
index 733137f5700..6d6001af084 100644
--- a/tests/assembly/riscv-soft-abi-with-float-features.rs
+++ b/tests/assembly/riscv-soft-abi-with-float-features.rs
@@ -1,6 +1,9 @@
 //@ assembly-output: emit-asm
 //@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d
 //@ needs-llvm-components: riscv
+//@ revisions: LLVM-PRE-20 LLVM-POST-20
+//@ [LLVM-PRE-20] ignore-llvm-version: 20 - 99
+//@ [LLVM-POST-20] min-llvm-version: 20
 
 #![feature(no_core, lang_items, f16)]
 #![crate_type = "lib"]
@@ -31,9 +34,11 @@ pub extern "C" fn read_f16(x: &f16) -> f16 {
 // CHECK-LABEL: read_f32
 #[no_mangle]
 pub extern "C" fn read_f32(x: &f32) -> f32 {
-    // CHECK: flw fa5, 0(a0)
-    // CHECK-NEXT: fmv.x.w a0, fa5
-    // CHECK-NEXT: ret
+    // LLVM-PRE-20: flw fa5, 0(a0)
+    // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5
+    // LLVM-PRE-20-NEXT: ret
+    // LLVM-POST-20: lw a0, 0(a0)
+    // LLVM-POST-20-NEXT: ret
     *x
 }
 
diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs
deleted file mode 100644
index 1cf6338a0d6..00000000000
--- a/tests/crashes/125249.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: rust-lang/rust#125185
-#![feature(return_position_impl_trait_in_trait, return_type_notation)]
-
-trait IntFactory {
-    fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
-}
-
-pub fn main() {}
diff --git a/tests/crashes/126725.rs b/tests/crashes/126725.rs
deleted file mode 100644
index d7a7d21ae42..00000000000
--- a/tests/crashes/126725.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: rust-lang/rust#126725
-trait Foo {
-    fn foo<'a>(&'a self) -> <&'a impl Sized as Bar>::Output;
-}
-
-trait Bar {
-    type Output;
-}
-
-struct X(i32);
-
-impl<'a> Bar for &'a X {
-    type Output = &'a i32;
-}
-
-impl Foo for X {
-    fn foo<'a>(&'a self) -> <&'a Self as Bar>::Output {
-        &self.0
-    }
-}
diff --git a/tests/crashes/23707.rs b/tests/crashes/23707.rs
deleted file mode 100644
index 4105933c60f..00000000000
--- a/tests/crashes/23707.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-//@ known-bug: #23707
-//@ compile-flags: -Copt-level=0 --edition=2021
-//@ only-x86_64
-#![recursion_limit="2048"]
-
-use std::marker::PhantomData;
-use std::fmt;
-use std::fmt::Debug;
-
-pub struct Z( () );
-pub struct S<T> (PhantomData<T>);
-
-
-pub trait Nat {
-    fn sing() -> Self;
-    fn get(&self) -> usize;
-}
-
-impl Nat for Z {
-    fn sing() -> Z { Z( () ) }
-    #[inline(always)]
-    fn get(&self) -> usize {
-        0
-    }
-}
-
-impl<T : Nat> Nat for S<T> {
-    fn sing() -> S<T> { S::<T>( PhantomData::<T> ) }
-    #[inline(always)]
-    fn get(&self) -> usize {
-        let prd : T = Nat::sing();
-        1 + prd.get()
-    }
-}
-
-pub type N0 = Z;
-pub type N1 = S<N0>;
-pub type N2 = S<N1>;
-pub type N3 = S<N2>;
-pub type N4 = S<N3>;
-pub type N5 = S<N4>;
-
-
-pub struct Node<D : Nat>(usize,PhantomData<D>);
-
-impl<D:Nat> Node<D> {
-    pub fn push(&self, c : usize) -> Node<S<D>> {
-        let Node(i,_) = *self;
-        Node(10*i+c, PhantomData::<S<D>>)
-    }
-}
-
-impl<D:Nat> Node<S<D>> {
-    pub fn pop(&self) -> (Node<D>,usize) {
-        let Node(i,_) = *self;
-        (Node(i/10, PhantomData::<D>), i-10*(i/10))
-    }
-}
-
-impl<D:Nat> Debug for Node<D> {
-    fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
-        let s : D = Nat::sing();
-        write!(f, "Node<{}>: i= {}",
-               s.get(), self.0)
-    }
-}
-pub trait Step {
-    fn step(&self, usize) -> Self;
-}
-
-impl Step for Node<N0> {
-    #[inline(always)]
-    fn step(&self, n : usize) -> Node<N0> {
-        println!("base case");
-        Node(n,PhantomData::<N0>)
-    }
-}
-
-impl<D:Nat> Step for Node<S<D>>
-    where Node<D> : Step {
-        #[inline(always)]
-        fn step(&self, n : usize) -> Node<S<D>> {
-            println!("rec");
-            let (par,c) = self.pop();
-            let cnew = c+n;
-            par.step(c).push(cnew)
-        }
-
-}
-
-fn tst<D:Nat>(ref p : &Node<D>, c : usize) -> usize
-    where Node<D> : Step {
-        let Node(i,_) = p.step(c);
-        i
-}
-
-
-
-fn main() {
-    let nd : Node<N3> = Node(555,PhantomData::<N3>);
-
-    // overflow...core::marker::Size
-    let Node(g,_) = tst(nd,1);
-
-    // ok
-    //let Node(g,_) = nd.step(1);
-
-    println!("{:?}", g);
-}
diff --git a/tests/run-make/linkage-attr-framework/main.rs b/tests/run-make/linkage-attr-framework/main.rs
new file mode 100644
index 00000000000..8efabc83e62
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/main.rs
@@ -0,0 +1,17 @@
+#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
+
+#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
+#[cfg_attr(
+    any(weak, both),
+    link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
+    link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
+)]
+extern "C" {
+    fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
+}
+
+fn main() {
+    unsafe {
+        CFRunLoopGetTypeID();
+    }
+}
diff --git a/tests/run-make/linkage-attr-framework/rmake.rs b/tests/run-make/linkage-attr-framework/rmake.rs
new file mode 100644
index 00000000000..4450350f96e
--- /dev/null
+++ b/tests/run-make/linkage-attr-framework/rmake.rs
@@ -0,0 +1,26 @@
+//! Check that linking frameworks on Apple platforms works.
+
+//@ only-apple
+
+use run_make_support::{Rustc, run, rustc};
+
+fn compile(cfg: &str) -> Rustc {
+    let mut rustc = rustc();
+    rustc.cfg(cfg).input("main.rs");
+    rustc
+}
+
+fn main() {
+    for cfg in ["link", "weak", "both"] {
+        compile(cfg).run();
+        run("main");
+    }
+
+    let errs = compile("omit").run_fail();
+    // The linker's exact error output changes between Xcode versions, depends on
+    // linker invocation details, and the linker sometimes outputs more warnings.
+    errs.assert_stderr_contains_regex(r"error: linking with `.*` failed");
+    errs.assert_stderr_contains_regex(r"(Undefined symbols|ld: symbol[^\s]* not found)");
+    errs.assert_stderr_contains_regex(r".?_CFRunLoopGetTypeID.?, referenced from:");
+    errs.assert_stderr_contains("clang: error: linker command failed with exit code 1");
+}
diff --git a/tests/rustdoc-gui/check-stab-in-docblock.goml b/tests/rustdoc-gui/check-stab-in-docblock.goml
index f25c88690e5..916bea6b069 100644
--- a/tests/rustdoc-gui/check-stab-in-docblock.goml
+++ b/tests/rustdoc-gui/check-stab-in-docblock.goml
@@ -1,5 +1,5 @@
 // This test checks that using `.stab` attributes in `.docblock` elements doesn't
-// create scrollable paragraphs.
+// create scrollable paragraphs and is correctly displayed (not making weird blocks).
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
 // Needs the text to be display to check for scrollable content.
 show-text: true
@@ -31,3 +31,15 @@ assert-property: (
     ".top-doc .docblock p:nth-of-type(3)",
     {"scrollHeight": |clientHeight|, "scrollWidth": |clientWidth|},
 )
+
+// Ensure that `<code>` elements in code don't make big blocks.
+compare-elements-size-near: (
+    "#reexport\.TheStdReexport > code",
+    ".docblock p span[data-span='1']",
+    {"height": 1},
+)
+compare-elements-size-near: (
+    "#reexport\.TheStdReexport > code",
+    ".docblock p span[data-span='2']",
+    {"height": 1},
+)
diff --git a/tests/rustdoc-gui/docblock-big-code-mobile.goml b/tests/rustdoc-gui/docblock-big-code-mobile.goml
index 6fc6834768e..71e08e2c7e2 100644
--- a/tests/rustdoc-gui/docblock-big-code-mobile.goml
+++ b/tests/rustdoc-gui/docblock-big-code-mobile.goml
@@ -1,13 +1,15 @@
 // If we have a long `<code>`, we need to ensure that it'll be fully displayed on mobile, meaning
 // that it'll be on two lines.
+
 emulate: "iPhone 8" // it has the following size: (375, 667)
 go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block/index.html"
-// We now check that the block is on two lines:
 show-text: true // We need to enable text draw to be able to have the "real" size
+
+// We now check that the block is on two lines:
 // Little explanations for this test: if the text wasn't displayed on two lines, it would take
-// around 20px (which is the font size).
-assert-property: (".docblock p > code", {"offsetHeight": "44"})
+// around 24px (which is the font size).
+assert-size: (".docblock p > code", {"height": 48})
 
 // Same check, but where the long code block is also a link
 go-to: "file://" + |DOC_PATH| + "/test_docs/long_code_block_link/index.html"
-assert-property: (".docblock p > a > code", {"offsetHeight": "44"})
+assert-size: (".docblock p > a > code", {"height": 48})
diff --git a/tests/rustdoc-gui/fields.goml b/tests/rustdoc-gui/fields.goml
index b8139a2edac..dce9918c332 100644
--- a/tests/rustdoc-gui/fields.goml
+++ b/tests/rustdoc-gui/fields.goml
@@ -1,13 +1,37 @@
-// This test checks that fields are displayed as expected (one by line).
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/struct.Struct.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+// This test checks that fields are displayed as expected (one by line) and they are surrounded
+// by margins.
 
-go-to: "file://" + |DOC_PATH| + "/test_docs/fields/union.Union.html"
-store-position: ("#structfield\.a", {"y": a_y})
-store-position: ("#structfield\.b", {"y": b_y})
-assert: |a_y| < |b_y|
+store-value: (margin, "9.6px")
+define-function: (
+    "check-fields",
+    [path, selector_1, selector_2],
+    block {
+        go-to: "file://" + |DOC_PATH| + "/test_docs/fields/" + |path|
+        store-position: (|selector_1|, {"y": a_y})
+        store-position: (|selector_2|, {"y": b_y})
+        assert: |a_y| < |b_y|
+
+        // Check the margins.
+        assert-css: (".structfield.section-header", {
+            "margin-top": |margin|,
+            "margin-bottom": |margin|,
+            "margin-left": "0px",
+            "margin-right": "0px",
+        }, ALL)
+    }
+)
+
+call-function: ("check-fields", {
+    "path": "struct.Struct.html",
+    "selector_1": "#structfield\.a",
+    "selector_2": "#structfield\.b",
+})
+
+call-function: ("check-fields", {
+    "path": "union.Union.html",
+    "selector_1": "#structfield\.a",
+    "selector_2": "#structfield\.b",
+})
 
 go-to: "file://" + |DOC_PATH| + "/test_docs/fields/enum.Enum.html"
 store-position: ("#variant\.A\.field\.a", {"y": a_y})
@@ -16,3 +40,11 @@ assert: |a_y| < |b_y|
 store-position: ("#variant\.B\.field\.a", {"y": a_y})
 store-position: ("#variant\.B\.field\.b", {"y": b_y})
 assert: |a_y| < |b_y|
+
+// Check the margins.
+assert-css: (".sub-variant-field", {
+    "margin-top": |margin|,
+    "margin-bottom": |margin|,
+    "margin-left": "24px",
+    "margin-right": "0px",
+}, ALL)
diff --git a/tests/rustdoc-gui/struct-fields.goml b/tests/rustdoc-gui/struct-fields.goml
index 3c87a4cd654..302a1a0d80b 100644
--- a/tests/rustdoc-gui/struct-fields.goml
+++ b/tests/rustdoc-gui/struct-fields.goml
@@ -1,4 +1,5 @@
-// This test ensures that each field is on its own line (In other words, they have display: block).
+// This test ensures that each field is on its own line (In other words, they have
+// `display: block`).
 go-to: "file://" + |DOC_PATH| + "/test_docs/struct.StructWithPublicUndocumentedFields.html"
 
 store-property: ("//*[@id='structfield.first']", {"offsetTop": first_top})
diff --git a/tests/rustdoc-js/extern-func.js b/tests/rustdoc-js/extern-func.js
new file mode 100644
index 00000000000..a3fe2d8ea42
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.js
@@ -0,0 +1,8 @@
+const EXPECTED = [
+    {
+        'query': 'c_float -> c_float',
+        'others': [
+            { 'path': 'extern_func', 'name': 'sqrt' }
+        ],
+    },
+];
diff --git a/tests/rustdoc-js/extern-func.rs b/tests/rustdoc-js/extern-func.rs
new file mode 100644
index 00000000000..ab1e3e75da7
--- /dev/null
+++ b/tests/rustdoc-js/extern-func.rs
@@ -0,0 +1,5 @@
+use std::ffi::c_float;
+
+extern "C" {
+    pub fn sqrt(x: c_float) -> c_float;
+}
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.rs b/tests/rustdoc-ui/doctest/dead-code-2024.rs
new file mode 100644
index 00000000000..4c77112e61a
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.rs
@@ -0,0 +1,15 @@
+// This test ensures that the 2024 edition merged doctest will not use `#[allow(unused)]`.
+
+//@ compile-flags:--test -Zunstable-options --edition 2024
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ failure-status: 101
+
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+/// Example
+///
+/// ```rust,no_run
+/// trait T { fn f(); }
+/// ```
+pub fn f() {}
diff --git a/tests/rustdoc-ui/doctest/dead-code-2024.stdout b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
new file mode 100644
index 00000000000..69dd4e2ede1
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/dead-code-2024.stdout
@@ -0,0 +1,29 @@
+
+running 1 test
+test $DIR/dead-code-2024.rs - f (line 12) - compile ... FAILED
+
+failures:
+
+---- $DIR/dead-code-2024.rs - f (line 12) stdout ----
+error: trait `T` is never used
+  --> $DIR/dead-code-2024.rs:13:7
+   |
+LL | trait T { fn f(); }
+   |       ^
+   |
+note: the lint level is defined here
+  --> $DIR/dead-code-2024.rs:11:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 1 previous error
+
+Couldn't compile the test.
+
+failures:
+    $DIR/dead-code-2024.rs - f (line 12)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/rustdoc-ui/doctest/dead-code.rs b/tests/rustdoc-ui/doctest/dead-code.rs
new file mode 100644
index 00000000000..cb9b4c28f6c
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/dead-code.rs
@@ -0,0 +1,15 @@
+// This test ensures that the doctest will not use `#[allow(unused)]`.
+
+//@ compile-flags:--test
+//@ normalize-stdout-test: "tests/rustdoc-ui/doctest" -> "$$DIR"
+//@ normalize-stdout-test: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ failure-status: 101
+
+#![doc(test(attr(allow(unused_variables), deny(warnings))))]
+
+/// Example
+///
+/// ```rust,no_run
+/// trait T { fn f(); }
+/// ```
+pub fn f() {}
diff --git a/tests/rustdoc-ui/doctest/dead-code.stdout b/tests/rustdoc-ui/doctest/dead-code.stdout
new file mode 100644
index 00000000000..38d15d5c1bc
--- /dev/null
+++ b/tests/rustdoc-ui/doctest/dead-code.stdout
@@ -0,0 +1,29 @@
+
+running 1 test
+test $DIR/dead-code.rs - f (line 12) - compile ... FAILED
+
+failures:
+
+---- $DIR/dead-code.rs - f (line 12) stdout ----
+error: trait `T` is never used
+  --> $DIR/dead-code.rs:13:7
+   |
+LL | trait T { fn f(); }
+   |       ^
+   |
+note: the lint level is defined here
+  --> $DIR/dead-code.rs:11:9
+   |
+LL | #![deny(warnings)]
+   |         ^^^^^^^^
+   = note: `#[deny(dead_code)]` implied by `#[deny(warnings)]`
+
+error: aborting due to 1 previous error
+
+Couldn't compile the test.
+
+failures:
+    $DIR/dead-code.rs - f (line 12)
+
+test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index ff7af388514..03fca17aa55 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -1,10 +1,10 @@
-error: unsupported type attribute for diagnostic derive enum
+error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum
   --> $DIR/diagnostic-derive.rs:47:1
    |
 LL | #[diag(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:50:5
    |
 LL |     Foo,
@@ -12,7 +12,7 @@ LL |     Foo,
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:52:5
    |
 LL |     Bar,
@@ -20,13 +20,13 @@ LL |     Bar,
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[nonsense(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:63:1
    |
 LL | #[nonsense(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:63:1
    |
 LL | #[nonsense(no_crate_example, code = E0123)]
@@ -34,7 +34,7 @@ LL | #[nonsense(no_crate_example, code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:70:1
    |
 LL | #[diag(code = E0123)]
@@ -42,13 +42,13 @@ LL | #[diag(code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
   --> $DIR/diagnostic-derive.rs:80:16
    |
 LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
    |                ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:80:1
    |
 LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
@@ -56,7 +56,7 @@ LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:86:8
    |
 LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -64,7 +64,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
    |
    = note: only the `code` parameter is valid after the slug
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:86:1
    |
 LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
@@ -72,7 +72,7 @@ LL | #[diag(nonsense = "...", code = E0123, slug = "foo")]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:92:8
    |
 LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -80,7 +80,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
    |
    = note: only the `code` parameter is valid after the slug
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:92:1
    |
 LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
@@ -88,7 +88,7 @@ LL | #[diag(nonsense = 4, code = E0123, slug = "foo")]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: unknown argument
+error: derive(Diagnostic): unknown argument
   --> $DIR/diagnostic-derive.rs:98:40
    |
 LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
@@ -96,13 +96,13 @@ LL | #[diag(no_crate_example, code = E0123, slug = "foo")]
    |
    = note: only the `code` parameter is valid after the slug
 
-error: `#[suggestion = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:105:5
    |
 LL |     #[suggestion = "bar"]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:112:8
    |
 LL | #[diag(no_crate_example, code = E0456)]
@@ -114,7 +114,7 @@ note: previously specified here
 LL | #[diag(no_crate_example, code = E0123)]
    |        ^^^^^^^^^^^^^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:112:26
    |
 LL | #[diag(no_crate_example, code = E0456)]
@@ -126,7 +126,7 @@ note: previously specified here
 LL | #[diag(no_crate_example, code = E0123)]
    |                          ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:118:40
    |
 LL | #[diag(no_crate_example, code = E0123, code = E0456)]
@@ -138,13 +138,13 @@ note: previously specified here
 LL | #[diag(no_crate_example, code = E0123, code = E0456)]
    |                          ^^^^
 
-error: diagnostic slug must be the first argument
+error: derive(Diagnostic): diagnostic slug must be the first argument
   --> $DIR/diagnostic-derive.rs:123:43
    |
 LL | #[diag(no_crate_example, no_crate::example, code = E0123)]
    |                                           ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:128:1
    |
 LL | struct KindNotProvided {}
@@ -152,7 +152,7 @@ LL | struct KindNotProvided {}
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:131:1
    |
 LL | #[diag(code = E0123)]
@@ -160,25 +160,25 @@ LL | #[diag(code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:142:5
    |
 LL |     #[primary_span]
    |     ^
 
-error: `#[nonsense]` is not a valid attribute
+error: derive(Diagnostic): `#[nonsense]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:150:5
    |
 LL |     #[nonsense]
    |     ^
 
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:167:5
    |
 LL |     #[label(no_crate_label)]
    |     ^
 
-error: `name` doesn't refer to a field on this type
+error: derive(Diagnostic): `name` doesn't refer to a field on this type
   --> $DIR/diagnostic-derive.rs:175:46
    |
 LL |     #[suggestion(no_crate_suggestion, code = "{name}")]
@@ -202,19 +202,19 @@ LL | #[derive(Diagnostic)]
    = note: if you intended to print `}`, you can escape it using `}}`
    = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/diagnostic-derive.rs:210:5
    |
 LL |     #[label(no_crate_label)]
    |     ^
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:229:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/diagnostic-derive.rs:237:18
    |
 LL |     #[suggestion(nonsense = "bar")]
@@ -222,13 +222,13 @@ LL |     #[suggestion(nonsense = "bar")]
    |
    = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:237:5
    |
 LL |     #[suggestion(nonsense = "bar")]
    |     ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/diagnostic-derive.rs:246:18
    |
 LL |     #[suggestion(msg = "bar")]
@@ -236,13 +236,13 @@ LL |     #[suggestion(msg = "bar")]
    |
    = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:246:5
    |
 LL |     #[suggestion(msg = "bar")]
    |     ^
 
-error: wrong field type for suggestion
+error: derive(Diagnostic): wrong field type for suggestion
   --> $DIR/diagnostic-derive.rs:269:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "This is suggested code")]
@@ -250,7 +250,7 @@ LL |     #[suggestion(no_crate_suggestion, code = "This is suggested code")]
    |
    = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:285:24
    |
 LL |     suggestion: (Span, Span, Applicability),
@@ -262,7 +262,7 @@ note: previously specified here
 LL |     suggestion: (Span, Span, Applicability),
    |                  ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:293:33
    |
 LL |     suggestion: (Applicability, Applicability, Span),
@@ -274,13 +274,13 @@ note: previously specified here
 LL |     suggestion: (Applicability, Applicability, Span),
    |                  ^^^^^^^^^^^^^
 
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:300:5
    |
 LL |     #[label = "bar"]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:451:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")]
@@ -292,37 +292,37 @@ note: previously specified here
 LL |     suggestion: (Span, Applicability),
    |                        ^^^^^^^^^^^^^
 
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
   --> $DIR/diagnostic-derive.rs:459:69
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")]
    |                                                                     ^^^^^^^^
 
-error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
+error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()`
   --> $DIR/diagnostic-derive.rs:526:5
    |
 LL |     #[help(no_crate_help)]
    |     ^
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/diagnostic-derive.rs:535:32
    |
 LL |     #[label(no_crate_label, foo)]
    |                                ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/diagnostic-derive.rs:543:29
    |
 LL |     #[label(no_crate_label, foo = "...")]
    |                             ^^^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/diagnostic-derive.rs:551:29
    |
 LL |     #[label(no_crate_label, foo("..."))]
    |                             ^^^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:563:5
    |
 LL |     #[primary_span]
@@ -330,13 +330,13 @@ LL |     #[primary_span]
    |
    = help: the `primary_span` field attribute is not valid for lint diagnostics
 
-error: `#[error(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[error(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:583:1
    |
 LL | #[error(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:583:1
    |
 LL | #[error(no_crate_example, code = E0123)]
@@ -344,13 +344,13 @@ LL | #[error(no_crate_example, code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[warn_(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:590:1
    |
 LL | #[warn_(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:590:1
    |
 LL | #[warn_(no_crate_example, code = E0123)]
@@ -358,13 +358,13 @@ LL | #[warn_(no_crate_example, code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:597:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:597:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
@@ -372,13 +372,13 @@ LL | #[lint(no_crate_example, code = E0123)]
    |
    = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]`
 
-error: `#[lint(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:604:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
    | ^
 
-error: diagnostic slug not specified
+error: derive(Diagnostic): diagnostic slug not specified
   --> $DIR/diagnostic-derive.rs:604:1
    |
 LL | #[lint(no_crate_example, code = E0123)]
@@ -386,7 +386,7 @@ LL | #[lint(no_crate_example, code = E0123)]
    |
    = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]`
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/diagnostic-derive.rs:613:53
    |
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
@@ -398,7 +398,7 @@ note: previously specified here
 LL |     #[suggestion(no_crate_suggestion, code = "...", code = ",,,")]
    |                                       ^^^^
 
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
   --> $DIR/diagnostic-derive.rs:622:24
    |
 LL |     suggestion: (Span, usize),
@@ -406,7 +406,7 @@ LL |     suggestion: (Span, usize),
    |
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
-error: wrong types for suggestion
+error: derive(Diagnostic): wrong types for suggestion
   --> $DIR/diagnostic-derive.rs:630:17
    |
 LL |     suggestion: (Span,),
@@ -414,13 +414,13 @@ LL |     suggestion: (Span,),
    |
    = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)`
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/diagnostic-derive.rs:637:5
    |
 LL |     #[suggestion(no_crate_suggestion)]
    |     ^
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:644:1
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
@@ -428,7 +428,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)]
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:647:1
    |
 LL | #[multipart_suggestion()]
@@ -436,7 +436,7 @@ LL | #[multipart_suggestion()]
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[multipart_suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:651:5
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
@@ -444,7 +444,7 @@ LL |     #[multipart_suggestion(no_crate_suggestion)]
    |
    = help: consider creating a `Subdiagnostic` instead
 
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:659:1
    |
 LL | #[suggestion(no_crate_suggestion, code = "...")]
@@ -452,7 +452,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")]
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[label]` is not a valid attribute
+error: derive(Diagnostic): `#[label]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:668:1
    |
 LL | #[label]
@@ -460,61 +460,61 @@ LL | #[label]
    |
    = help: `#[label]` and `#[suggestion]` can only be applied to fields
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:702:5
    |
 LL |     #[subdiagnostic(bad)]
    |     ^
 
-error: `#[subdiagnostic = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:710:5
    |
 LL |     #[subdiagnostic = "bad"]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:718:5
    |
 LL |     #[subdiagnostic(bad, bad)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:726:5
    |
 LL |     #[subdiagnostic("bad")]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:734:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:742:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: `#[subdiagnostic(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:763:5
    |
 LL |     #[subdiagnostic(eager)]
    |     ^
 
-error: expected at least one string literal for `code(...)`
+error: derive(Diagnostic): expected at least one string literal for `code(...)`
   --> $DIR/diagnostic-derive.rs:794:23
    |
 LL |     #[suggestion(code())]
    |                       ^
 
-error: `code(...)` must contain only string literals
+error: derive(Diagnostic): `code(...)` must contain only string literals
   --> $DIR/diagnostic-derive.rs:802:23
    |
 LL |     #[suggestion(code(foo))]
    |                       ^^^
 
-error: `#[suggestion(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute
   --> $DIR/diagnostic-derive.rs:826:5
    |
 LL |     #[suggestion(no_crate_suggestion, code = "")]
diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
index df1bad3cad0..4f54239f0fa 100644
--- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr
@@ -1,4 +1,4 @@
-error: diagnostic slug and crate name do not match
+error: derive(Diagnostic): diagnostic slug and crate name do not match
   --> $DIR/enforce_slug_naming.rs:22:8
    |
 LL | #[diag(compiletest_example, code = E0123)]
diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
index 96f6ef06d1d..0ae7ba4c497 100644
--- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr
@@ -1,142 +1,142 @@
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:51:1
    |
 LL | #[label(no_crate_example)]
    | ^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:58:1
    |
 LL | #[label]
    | ^
 
-error: `#[foo]` is not a valid attribute
+error: derive(Diagnostic): `#[foo]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:67:1
    |
 LL | #[foo]
    | ^
 
-error: `#[label = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[label = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:77:1
    |
 LL | #[label = "..."]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:86:9
    |
 LL | #[label(bug = "...")]
    |         ^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:86:1
    |
 LL | #[label(bug = "...")]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:106:9
    |
 LL | #[label(slug = 4)]
    |         ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:106:1
    |
 LL | #[label(slug = 4)]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:116:9
    |
 LL | #[label(slug("..."))]
    |         ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:116:1
    |
 LL | #[label(slug("..."))]
    | ^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:136:1
    |
 LL | #[label()]
    | ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:145:27
    |
 LL | #[label(no_crate_example, code = "...")]
    |                           ^^^^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:154:27
    |
 LL | #[label(no_crate_example, applicability = "machine-applicable")]
    |                           ^^^^^^^^^^^^^
 
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:163:1
    |
 LL | #[foo]
    | ^
 
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:177:5
    |
 LL |     #[bar]
    |     ^
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:189:5
    |
 LL |     #[bar = "..."]
    |     ^
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:201:5
    |
 LL |     #[bar = 4]
    |     ^
 
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:213:5
    |
 LL |     #[bar("...")]
    |     ^
 
-error: only `no_span` is a valid nested attribute
+error: derive(Diagnostic): only `no_span` is a valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:225:13
    |
 LL |     #[label(code = "...")]
    |             ^^^^
 
-error: diagnostic slug must be first argument of a `#[label(...)]` attribute
+error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute
   --> $DIR/subdiagnostic-derive.rs:225:5
    |
 LL |     #[label(code = "...")]
    |     ^
 
-error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:254:5
    |
 LL |     #[primary_span]
    |     ^
 
-error: label without `#[primary_span]` field
+error: derive(Diagnostic): label without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:251:1
    |
 LL | #[label(no_crate_example)]
    | ^
 
-error: `#[applicability]` is only valid on suggestions
+error: derive(Diagnostic): `#[applicability]` is only valid on suggestions
   --> $DIR/subdiagnostic-derive.rs:264:5
    |
 LL |     #[applicability]
    |     ^
 
-error: `#[bar]` is not a valid attribute
+error: derive(Diagnostic): `#[bar]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:274:5
    |
 LL |     #[bar]
@@ -144,13 +144,13 @@ LL |     #[bar]
    |
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
-error: `#[bar = ...]` is not a valid attribute
+error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:285:5
    |
 LL |     #[bar = "..."]
    |     ^
 
-error: `#[bar(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:296:5
    |
 LL |     #[bar("...")]
@@ -158,13 +158,13 @@ LL |     #[bar("...")]
    |
    = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/subdiagnostic-derive.rs:328:44
    |
 LL | #[label(no_crate_example, no_crate::example)]
    |                                            ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:341:5
    |
 LL |     #[primary_span]
@@ -176,13 +176,13 @@ note: previously specified here
 LL |     #[primary_span]
    |     ^
 
-error: subdiagnostic kind not specified
+error: derive(Diagnostic): subdiagnostic kind not specified
   --> $DIR/subdiagnostic-derive.rs:347:8
    |
 LL | struct AG {
    |        ^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:384:46
    |
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
@@ -194,7 +194,7 @@ note: previously specified here
 LL | #[suggestion(no_crate_example, code = "...", code = "...")]
    |                                ^^^^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:402:5
    |
 LL |     #[applicability]
@@ -206,49 +206,49 @@ note: previously specified here
 LL |     #[applicability]
    |     ^
 
-error: the `#[applicability]` attribute can only be applied to fields of type `Applicability`
+error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability`
   --> $DIR/subdiagnostic-derive.rs:412:5
    |
 LL |     #[applicability]
    |     ^
 
-error: suggestion without `code = "..."`
+error: derive(Diagnostic): suggestion without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:425:1
    |
 LL | #[suggestion(no_crate_example)]
    | ^
 
-error: invalid applicability
+error: derive(Diagnostic): invalid applicability
   --> $DIR/subdiagnostic-derive.rs:435:62
    |
 LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")]
    |                                                              ^^^^^
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:453:1
    |
 LL | #[suggestion(no_crate_example, code = "...")]
    | ^
 
-error: unsupported type attribute for subdiagnostic enum
+error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum
   --> $DIR/subdiagnostic-derive.rs:467:1
    |
 LL | #[label]
    | ^
 
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
   --> $DIR/subdiagnostic-derive.rs:487:39
    |
 LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                       ^^^^^^^
 
-error: `var` doesn't refer to a field on this type
+error: derive(Diagnostic): `var` doesn't refer to a field on this type
   --> $DIR/subdiagnostic-derive.rs:506:43
    |
 LL |     #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")]
    |                                           ^^^^^^^
 
-error: `#[suggestion_part]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:529:5
    |
 LL |     #[suggestion_part]
@@ -256,7 +256,7 @@ LL |     #[suggestion_part]
    |
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead
 
-error: `#[suggestion_part(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:532:5
    |
 LL |     #[suggestion_part(code = "...")]
@@ -264,13 +264,13 @@ LL |     #[suggestion_part(code = "...")]
    |
    = help: `#[suggestion_part(...)]` is only valid in multipart suggestions
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:526:1
    |
 LL | #[suggestion(no_crate_example, code = "...")]
    | ^
 
-error: invalid nested attribute
+error: derive(Diagnostic): invalid nested attribute
   --> $DIR/subdiagnostic-derive.rs:541:42
    |
 LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
@@ -278,25 +278,25 @@ LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "mac
    |
    = help: only `no_span`, `style` and `applicability` are valid nested attributes
 
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
   --> $DIR/subdiagnostic-derive.rs:541:1
    |
 LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")]
    | ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:551:5
    |
 LL |     #[suggestion_part]
    |     ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:559:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:568:5
    |
 LL |     #[primary_span]
@@ -304,43 +304,43 @@ LL |     #[primary_span]
    |
    = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]`
 
-error: multipart suggestion without any `#[suggestion_part(...)]` fields
+error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields
   --> $DIR/subdiagnostic-derive.rs:565:1
    |
 LL | #[multipart_suggestion(no_crate_example)]
    | ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:576:5
    |
 LL |     #[suggestion_part]
    |     ^
 
-error: `#[suggestion_part(...)]` attribute without `code = "..."`
+error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."`
   --> $DIR/subdiagnostic-derive.rs:579:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: `code` is the only valid nested attribute
+error: derive(Diagnostic): `code` is the only valid nested attribute
   --> $DIR/subdiagnostic-derive.rs:582:23
    |
 LL |     #[suggestion_part(foo = "bar")]
    |                       ^^^
 
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:587:5
    |
 LL |     #[suggestion_part(code = "...")]
    |     ^
 
-error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
+error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan`
   --> $DIR/subdiagnostic-derive.rs:590:5
    |
 LL |     #[suggestion_part()]
    |     ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:598:37
    |
 LL |     #[suggestion_part(code = "...", code = ",,,")]
@@ -352,37 +352,37 @@ note: previously specified here
 LL |     #[suggestion_part(code = "...", code = ",,,")]
    |                       ^^^^
 
-error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
+error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."`
   --> $DIR/subdiagnostic-derive.rs:627:5
    |
 LL |     #[applicability]
    |     ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:675:34
    |
 LL |     #[suggestion_part(code("foo"))]
    |                                  ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:686:41
    |
 LL |     #[suggestion_part(code("foo", "bar"))]
    |                                         ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:697:30
    |
 LL |     #[suggestion_part(code(3))]
    |                              ^
 
-error: expected exactly one string literal for `code = ...`
+error: derive(Diagnostic): expected exactly one string literal for `code = ...`
   --> $DIR/subdiagnostic-derive.rs:708:29
    |
 LL |     #[suggestion_part(code())]
    |                             ^
 
-error: specified multiple times
+error: derive(Diagnostic): attribute specified multiple times
   --> $DIR/subdiagnostic-derive.rs:763:1
    |
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
@@ -394,7 +394,7 @@ note: previously specified here
 LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")]
    | ^
 
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:772:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "")]
@@ -402,7 +402,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")]
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
-error: `#[suggestion_hidden(...)]` is not a valid attribute
+error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:780:1
    |
 LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
@@ -410,7 +410,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")]
    |
    = help: Use `#[suggestion(..., style = "hidden")]` instead
 
-error: invalid suggestion style
+error: derive(Diagnostic): invalid suggestion style
   --> $DIR/subdiagnostic-derive.rs:788:51
    |
 LL | #[suggestion(no_crate_example, code = "", style = "foo")]
@@ -418,25 +418,25 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")]
    |
    = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
 
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
   --> $DIR/subdiagnostic-derive.rs:796:49
    |
 LL | #[suggestion(no_crate_example, code = "", style = 42)]
    |                                                 ^
 
-error: a diagnostic slug must be the first argument to the attribute
+error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute
   --> $DIR/subdiagnostic-derive.rs:804:48
    |
 LL | #[suggestion(no_crate_example, code = "", style)]
    |                                                ^
 
-error: expected `= "xxx"`
+error: derive(Diagnostic): expected `= "xxx"`
   --> $DIR/subdiagnostic-derive.rs:812:48
    |
 LL | #[suggestion(no_crate_example, code = "", style("foo"))]
    |                                                ^
 
-error: `#[primary_span]` is not a valid attribute
+error: derive(Diagnostic): `#[primary_span]` is not a valid attribute
   --> $DIR/subdiagnostic-derive.rs:825:5
    |
 LL |     #[primary_span]
@@ -445,7 +445,7 @@ LL |     #[primary_span]
    = note: there must be exactly one primary span
    = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead
 
-error: suggestion without `#[primary_span]` field
+error: derive(Diagnostic): suggestion without `#[primary_span]` field
   --> $DIR/subdiagnostic-derive.rs:822:1
    |
 LL | #[suggestion(no_crate_example, code = "")]
diff --git a/tests/ui-fulldeps/try-from-u32/errors.rs b/tests/ui-fulldeps/try-from-u32/errors.rs
new file mode 100644
index 00000000000..0470063312c
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.rs
@@ -0,0 +1,24 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+
+// Checks the error messages produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32)]
+struct MyStruct {} //~ type is not an enum
+
+#[derive(TryFromU32)]
+enum NonTrivial {
+    A,
+    B(),
+    C {},
+    D(bool),                //~ enum variant cannot have fields
+    E(bool, bool),          //~ enum variant cannot have fields
+    F { x: bool },          //~ enum variant cannot have fields
+    G { x: bool, y: bool }, //~ enum variant cannot have fields
+}
+
+fn main() {}
diff --git a/tests/ui-fulldeps/try-from-u32/errors.stderr b/tests/ui-fulldeps/try-from-u32/errors.stderr
new file mode 100644
index 00000000000..d20567061d7
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/errors.stderr
@@ -0,0 +1,32 @@
+error: type is not an enum (TryFromU32)
+  --> $DIR/errors.rs:11:1
+   |
+LL | struct MyStruct {}
+   | ^^^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:18:7
+   |
+LL |     D(bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:19:7
+   |
+LL |     E(bool, bool),
+   |       ^^^^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:20:9
+   |
+LL |     F { x: bool },
+   |         ^
+
+error: enum variant cannot have fields (TryFromU32)
+  --> $DIR/errors.rs:21:9
+   |
+LL |     G { x: bool, y: bool },
+   |         ^
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui-fulldeps/try-from-u32/hygiene.rs b/tests/ui-fulldeps/try-from-u32/hygiene.rs
new file mode 100644
index 00000000000..e0655a64a64
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/hygiene.rs
@@ -0,0 +1,32 @@
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ check-pass
+
+// Checks that the derive macro still works even if the surrounding code has
+// shadowed the relevant library types.
+
+extern crate rustc_macros;
+
+mod submod {
+    use rustc_macros::TryFromU32;
+
+    struct Result;
+    trait TryFrom {}
+    #[allow(non_camel_case_types)]
+    struct u32;
+    struct Ok;
+    struct Err;
+    mod core {}
+    mod std {}
+
+    #[derive(TryFromU32)]
+    pub(crate) enum MyEnum {
+        Zero,
+        One,
+    }
+}
+
+fn main() {
+    use submod::MyEnum;
+    let _: Result<MyEnum, u32> = MyEnum::try_from(1u32);
+}
diff --git a/tests/ui-fulldeps/try-from-u32/values.rs b/tests/ui-fulldeps/try-from-u32/values.rs
new file mode 100644
index 00000000000..180a8f2beb7
--- /dev/null
+++ b/tests/ui-fulldeps/try-from-u32/values.rs
@@ -0,0 +1,36 @@
+#![feature(assert_matches)]
+#![feature(rustc_private)]
+//@ edition: 2021
+//@ run-pass
+
+// Checks the values accepted by the `TryFrom<u32>` impl produced by `#[derive(TryFromU32)]`.
+
+extern crate rustc_macros;
+
+use core::assert_matches::assert_matches;
+use rustc_macros::TryFromU32;
+
+#[derive(TryFromU32, Debug, PartialEq)]
+#[repr(u32)]
+enum Repr {
+    Zero,
+    One(),
+    Seven = 7,
+}
+
+#[derive(TryFromU32, Debug)]
+enum NoRepr {
+    Zero,
+    One,
+}
+
+fn main() {
+    assert_eq!(Repr::try_from(0u32), Ok(Repr::Zero));
+    assert_eq!(Repr::try_from(1u32), Ok(Repr::One()));
+    assert_eq!(Repr::try_from(2u32), Err(2));
+    assert_eq!(Repr::try_from(7u32), Ok(Repr::Seven));
+
+    assert_matches!(NoRepr::try_from(0u32), Ok(NoRepr::Zero));
+    assert_matches!(NoRepr::try_from(1u32), Ok(NoRepr::One));
+    assert_matches!(NoRepr::try_from(2u32), Err(2));
+}
diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
index 574a53c58fe..0f99f6b1b1e 100644
--- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
+++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.rs
@@ -1,3 +1,3 @@
 pub fn main() {
-    vec![,]; //~ ERROR no rules expected the token `,`
+    vec![,]; //~ ERROR no rules expected `,`
 }
diff --git a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
index b3f953af6d2..d76d493eca8 100644
--- a/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
+++ b/tests/ui/array-slice-vec/vec-macro-with-comma-only.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `,`
+error: no rules expected `,`
   --> $DIR/vec-macro-with-comma-only.rs:2:10
    |
 LL |     vec![,];
diff --git a/tests/ui/associated-consts/issue-58022.stderr b/tests/ui/associated-consts/issue-58022.stderr
index 6ce995eaab7..82cbc9ed3b0 100644
--- a/tests/ui/associated-consts/issue-58022.stderr
+++ b/tests/ui/associated-consts/issue-58022.stderr
@@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     fn new(slice: &[u8; Self::SIZE]) -> Self {
    |                                         ^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `Bar<[u8]>: Sized`
+   = help: within `Bar<[u8]>`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `Bar<[u8]>`
   --> $DIR/issue-58022.rs:8:12
    |
diff --git a/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs
new file mode 100644
index 00000000000..38f55696914
--- /dev/null
+++ b/tests/ui/associated-type-bounds/implied-from-self-where-clause.rs
@@ -0,0 +1,21 @@
+// Make sure that, like associated type where clauses on traits, we gather item
+// bounds for RPITITs from RTN where clauses.
+
+//@ check-pass
+
+#![feature(return_type_notation)]
+
+trait Foo
+where
+    Self::method(..): Send,
+{
+    fn method() -> impl Sized;
+}
+
+fn is_send(_: impl Send) {}
+
+fn test<T: Foo>() {
+    is_send(T::method());
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
index 110d2a00583..0a31cc67533 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/basic.without.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo::<T>());
    |             ^^^^^^^^^^ future returned by `foo` is not `Send`
    |
-   = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }`, which is required by `impl Future<Output = Result<(), ()>>: Send`
+   = help: within `impl Future<Output = Result<(), ()>>`, the trait `Send` is not implemented for `impl Future<Output = Result<(), ()>> { <T as Foo>::method(..) }`
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/basic.rs:12:5
    |
diff --git a/tests/crashes/131648.rs b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs
index 68046ce2a1f..0d3e6f9c8e3 100644
--- a/tests/crashes/131648.rs
+++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs
@@ -1,7 +1,8 @@
-//@ known-bug: #131648
 #![feature(return_type_notation)]
 
 trait IntFactory {
     fn stream(self) -> impl IntFactory<stream(..): Send>;
+    //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream`
 }
+
 fn main() {}
diff --git a/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr
new file mode 100644
index 00000000000..0ed54415b9e
--- /dev/null
+++ b/tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.stderr
@@ -0,0 +1,27 @@
+error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream`
+  --> $DIR/impl-trait-in-trait.rs:4:5
+   |
+LL |     fn stream(self) -> impl IntFactory<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing function signature of `IntFactory::stream`...
+  --> $DIR/impl-trait-in-trait.rs:4:5
+   |
+LL |     fn stream(self) -> impl IntFactory<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires looking up late bound vars inside `IntFactory::stream`...
+  --> $DIR/impl-trait-in-trait.rs:4:5
+   |
+LL |     fn stream(self) -> impl IntFactory<stream(..): Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle
+note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}`
+  --> $DIR/impl-trait-in-trait.rs:4:24
+   |
+LL |     fn stream(self) -> impl IntFactory<stream(..): Send>;
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr
index 95810342d5a..90d0feb5217 100644
--- a/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr
+++ b/tests/ui/associated-type-bounds/return-type-notation/path-unsatisfied.stderr
@@ -7,7 +7,7 @@ LL |     fn method() -> impl Sized {
 LL |     test::<DoesntWork>();
    |            ^^^^^^^^^^ `*mut ()` cannot be sent between threads safely
    |
-   = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`, which is required by `impl Sized: Send`
+   = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`
 note: required because it appears within the type `impl Sized`
   --> $DIR/path-unsatisfied.rs:9:20
    |
diff --git a/tests/ui/associated-types/defaults-suitability.current.stderr b/tests/ui/associated-types/defaults-suitability.current.stderr
index 3cdeaa93a34..9c0ae59ae43 100644
--- a/tests/ui/associated-types/defaults-suitability.current.stderr
+++ b/tests/ui/associated-types/defaults-suitability.current.stderr
@@ -39,7 +39,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:31:23
    |
 LL |     type Bar: Clone = Vec<T>;
-   |                       ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `Vec<T>: Clone`
+   |                       ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Vec<T>` to implement `Clone`
 note: required by a bound in `Foo::Bar`
@@ -88,7 +88,7 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:68:23
    |
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`, which is required by `Vec<<Self as Foo2<T>>::Baz>: Clone`
+   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
    |
    = note: required for `Vec<<Self as Foo2<T>>::Baz>` to implement `Clone`
 note: required by a bound in `Foo2::Bar`
@@ -105,7 +105,7 @@ error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:77:23
    |
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`, which is required by `Vec<<Self as Foo25<T>>::Baz>: Clone`
+   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
    |
    = note: required for `Vec<<Self as Foo25<T>>::Baz>` to implement `Clone`
 note: required by a bound in `Foo25::Bar`
diff --git a/tests/ui/associated-types/defaults-suitability.next.stderr b/tests/ui/associated-types/defaults-suitability.next.stderr
index 3cdeaa93a34..9c0ae59ae43 100644
--- a/tests/ui/associated-types/defaults-suitability.next.stderr
+++ b/tests/ui/associated-types/defaults-suitability.next.stderr
@@ -39,7 +39,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:31:23
    |
 LL |     type Bar: Clone = Vec<T>;
-   |                       ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `Vec<T>: Clone`
+   |                       ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Vec<T>` to implement `Clone`
 note: required by a bound in `Foo::Bar`
@@ -88,7 +88,7 @@ error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:68:23
    |
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`, which is required by `Vec<<Self as Foo2<T>>::Baz>: Clone`
+   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo2<T>>::Baz`
    |
    = note: required for `Vec<<Self as Foo2<T>>::Baz>` to implement `Clone`
 note: required by a bound in `Foo2::Bar`
@@ -105,7 +105,7 @@ error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: Clone` is not satisfied
   --> $DIR/defaults-suitability.rs:77:23
    |
 LL |     type Bar: Clone = Vec<Self::Baz>;
-   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`, which is required by `Vec<<Self as Foo25<T>>::Baz>: Clone`
+   |                       ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `<Self as Foo25<T>>::Baz`
    |
    = note: required for `Vec<<Self as Foo25<T>>::Baz>` to implement `Clone`
 note: required by a bound in `Foo25::Bar`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-1.stderr
index 8830048ed4e..5b00e714194 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-1.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-1.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-1.rs:12:14
    |
 LL |     type U = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <i32 as X<'b>>::U: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `X`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr
index ad6d3e17684..07d3afb74e4 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-1.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-1.rs:14:14
    |
 LL |     type V = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <u8 as Y<'b, u8>>::V: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `Y`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr
index 6a5729e7784..74cc2083d26 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-2.stderr
@@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-2.rs:17:14
    |
 LL |     type W = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <u16 as Z<'b, u16>>::W: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `Z`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr
index 70e030f2d1c..58b82fc9306 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-3.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-3.rs:13:14
    |
 LL |     type U = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, (T,)>>::U: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `X`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr
index cba12afd674..6d6373a1918 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-4.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-4.rs:13:14
    |
 LL |     type U = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <(T,) as X<'b, T>>::U: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `X`
diff --git a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr
index ac96187749a..44c446c599f 100644
--- a/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr
+++ b/tests/ui/associated-types/hr-associated-type-bound-param-5.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-5.rs:26:14
    |
 LL |     type U = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <<Vec<T> as Cycle>::Next as X<'b, <Vec<T> as Cycle>::Next>>::U: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `X`
@@ -18,7 +18,7 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
   --> $DIR/hr-associated-type-bound-param-5.rs:31:14
    |
 LL |     type U = str;
-   |              ^^^ the trait `Clone` is not implemented for `str`, which is required by `for<'b> <<Box<T> as Cycle>::Next as X<'b, <Box<T> as Cycle>::Next>>::U: Clone`
+   |              ^^^ the trait `Clone` is not implemented for `str`
    |
    = help: the trait `Clone` is implemented for `String`
 note: required by a bound in `X`
diff --git a/tests/ui/associated-types/issue-38821.stderr b/tests/ui/associated-types/issue-38821.stderr
index f1c8f83e30c..58f019704e7 100644
--- a/tests/ui/associated-types/issue-38821.stderr
+++ b/tests/ui/associated-types/issue-38821.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:40:1
    |
 LL | pub enum ColumnInsertValue<Col, Expr> where
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -26,7 +26,7 @@ LL | |     Col: Column,
 ...  |
 LL | |     Default(Col),
 LL | | }
-   | |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   | |_^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -44,7 +44,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -63,7 +63,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -83,7 +83,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -98,7 +98,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -114,7 +114,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:17
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -133,7 +133,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:17
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                 ^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -153,7 +153,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -172,7 +172,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -192,7 +192,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -207,7 +207,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -223,7 +223,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -239,7 +239,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -255,7 +255,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -271,7 +271,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -287,7 +287,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:10
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |          ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
@@ -303,7 +303,7 @@ error[E0277]: the trait bound `<Col as Expression>::SqlType: NotNull` is not sat
   --> $DIR/issue-38821.rs:23:23
    |
 LL | #[derive(Debug, Copy, Clone)]
-   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`, which is required by `<Col as Expression>::SqlType: IntoNullable`
+   |                       ^^^^^ the trait `NotNull` is not implemented for `<Col as Expression>::SqlType`
    |
 note: required for `<Col as Expression>::SqlType` to implement `IntoNullable`
   --> $DIR/issue-38821.rs:9:18
diff --git a/tests/ui/associated-types/issue-43784-associated-type.stderr b/tests/ui/associated-types/issue-43784-associated-type.stderr
index b2cbe8ee86e..529fc1f119a 100644
--- a/tests/ui/associated-types/issue-43784-associated-type.stderr
+++ b/tests/ui/associated-types/issue-43784-associated-type.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/issue-43784-associated-type.rs:14:18
    |
 LL |     type Assoc = T;
-   |                  ^ the trait `Copy` is not implemented for `T`, which is required by `<T as Complete>::Assoc: Partial<T>`
+   |                  ^ the trait `Copy` is not implemented for `T`
    |
 note: required for `<T as Complete>::Assoc` to implement `Partial<T>`
   --> $DIR/issue-43784-associated-type.rs:1:11
diff --git a/tests/ui/associated-types/issue-65774-1.stderr b/tests/ui/associated-types/issue-65774-1.stderr
index 9748a8fbbf4..9c77a25c432 100644
--- a/tests/ui/associated-types/issue-65774-1.stderr
+++ b/tests/ui/associated-types/issue-65774-1.stderr
@@ -15,7 +15,7 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied
   --> $DIR/issue-65774-1.rs:44:76
    |
 LL |         let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config);
-   |                                                                            ^^^^^^^ the trait `MyDisplay` is not implemented for `T`, which is required by `&mut T: MyDisplay`
+   |                                                                            ^^^^^^^ the trait `MyDisplay` is not implemented for `T`
    |
    = help: the trait `MyDisplay` is implemented for `&'a mut T`
 note: required for `&mut T` to implement `MyDisplay`
diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr
index 8d3146be560..1ea8ab23556 100644
--- a/tests/ui/associated-types/substs-ppaux.normal.stderr
+++ b/tests/ui/associated-types/substs-ppaux.normal.stderr
@@ -80,7 +80,7 @@ error[E0277]: the trait bound `str: Foo<'_, '_, u8>` is not satisfied
   --> $DIR/substs-ppaux.rs:55:6
    |
 LL |     <str as Foo<u8>>::bar;
-   |      ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'_, '_, u8>`
+   |      ^^^ the trait `Sized` is not implemented for `str`
    |
 note: required for `str` to implement `Foo<'_, '_, u8>`
   --> $DIR/substs-ppaux.rs:15:20
diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr
index 0b5f449e576..05cd971c882 100644
--- a/tests/ui/associated-types/substs-ppaux.verbose.stderr
+++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr
@@ -80,7 +80,7 @@ error[E0277]: the trait bound `str: Foo<'?0, '?1, u8>` is not satisfied
   --> $DIR/substs-ppaux.rs:55:6
    |
 LL |     <str as Foo<u8>>::bar;
-   |      ^^^ the trait `Sized` is not implemented for `str`, which is required by `str: Foo<'?0, '?1, u8>`
+   |      ^^^ the trait `Sized` is not implemented for `str`
    |
 note: required for `str` to implement `Foo<'?0, '?1, u8>`
   --> $DIR/substs-ppaux.rs:15:20
diff --git a/tests/ui/async-await/async-await-let-else.stderr b/tests/ui/async-await/async-await-let-else.stderr
index 0952be2abe5..5883f34f87d 100644
--- a/tests/ui/async-await/async-await-let-else.stderr
+++ b/tests/ui/async-await/async-await-let-else.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo(Some(true)));
    |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-await-let-else.rs:8:15
    |
@@ -29,7 +29,7 @@ LL |     is_send(foo2(Some(true)));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: required because it's used within this `async` fn body
   --> $DIR/async-await-let-else.rs:24:29
    |
@@ -60,7 +60,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo3(Some(true)));
    |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-await-let-else.rs:30:29
    |
@@ -80,7 +80,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo4(Some(true)));
    |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-await-let-else.rs:38:15
    |
diff --git a/tests/ui/async-await/async-closures/not-clone-closure.stderr b/tests/ui/async-await/async-closures/not-clone-closure.stderr
index aea48a455c2..8d5612687db 100644
--- a/tests/ui/async-await/async-closures/not-clone-closure.stderr
+++ b/tests/ui/async-await/async-closures/not-clone-closure.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotClonableUpvar: Clone` is not satisfied in `{as
   --> $DIR/not-clone-closure.rs:32:15
    |
 LL |     not_clone.clone();
-   |               ^^^^^ within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar`, which is required by `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}: Clone`
+   |               ^^^^^ within `{async closure@$DIR/not-clone-closure.rs:29:21: 29:34}`, the trait `Clone` is not implemented for `NotClonableUpvar`
    |
 note: required because it's used within this closure
   --> $DIR/not-clone-closure.rs:29:21
diff --git a/tests/ui/async-await/async-fn-nonsend.stderr b/tests/ui/async-await/async-fn-nonsend.stderr
index 8b245281da9..0ced6c36f47 100644
--- a/tests/ui/async-await/async-fn-nonsend.stderr
+++ b/tests/ui/async-await/async-fn-nonsend.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     assert_send(non_send_temporary_in_match());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-fn-nonsend.rs:33:26
    |
@@ -24,7 +24,7 @@ error: future cannot be sent between threads safely
 LL |     assert_send(non_sync_with_method_call());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
 note: future is not `Send` as this value is used across an await
   --> $DIR/async-fn-nonsend.rs:46:15
    |
diff --git a/tests/ui/async-await/async-is-unwindsafe.stderr b/tests/ui/async-await/async-is-unwindsafe.stderr
index 9c5e8f0252c..9323ce25b77 100644
--- a/tests/ui/async-await/async-is-unwindsafe.stderr
+++ b/tests/ui/async-await/async-is-unwindsafe.stderr
@@ -13,7 +13,7 @@ LL | |         drop(cx_ref);
 LL | |     });
    | |______^ `&mut Context<'_>` may not be safely transferred across an unwind boundary
    |
-   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`, which is required by `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}: UnwindSafe`
+   = help: within `{async block@$DIR/async-is-unwindsafe.rs:12:19: 12:24}`, the trait `UnwindSafe` is not implemented for `&mut Context<'_>`
    = note: `UnwindSafe` is implemented for `&Context<'_>`, but not for `&mut Context<'_>`
 note: future does not implement `UnwindSafe` as this value is used across an await
   --> $DIR/async-is-unwindsafe.rs:25:18
diff --git a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr
index eab5bea681c..8c9d06c79ca 100644
--- a/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr
+++ b/tests/ui/async-await/debug-ice-attempted-to-add-with-overflow.stderr
@@ -7,7 +7,7 @@ LL |     [0usize; 0xffff_ffff_ffff_ffff].await;
    |                                    |`[usize; usize::MAX]` is not a future
    |                                    help: remove the `.await`
    |
-   = help: the trait `Future` is not implemented for `[usize; usize::MAX]`, which is required by `[usize; usize::MAX]: IntoFuture`
+   = help: the trait `Future` is not implemented for `[usize; usize::MAX]`
    = note: [usize; usize::MAX] must be a future or must implement `IntoFuture` to be awaited
    = note: required for `[usize; usize::MAX]` to implement `IntoFuture`
 
diff --git a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr
index 53cdc9b61d3..721e0106293 100644
--- a/tests/ui/async-await/drop-track-bad-field-in-fru.stderr
+++ b/tests/ui/async-await/drop-track-bad-field-in-fru.stderr
@@ -15,7 +15,7 @@ LL |     None { value: (), ..Default::default() }.await;
    |                                             |`Option<_>` is not a future
    |                                             help: remove the `.await`
    |
-   = help: the trait `Future` is not implemented for `Option<_>`, which is required by `Option<_>: IntoFuture`
+   = help: the trait `Future` is not implemented for `Option<_>`
    = note: Option<_> must be a future or must implement `IntoFuture` to be awaited
    = note: required for `Option<_>` to implement `IntoFuture`
 
diff --git a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr
index ce2cee6ed47..9fce4d61b3b 100644
--- a/tests/ui/async-await/drop-track-field-assign-nonsend.stderr
+++ b/tests/ui/async-await/drop-track-field-assign-nonsend.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     assert_send(agent.handle());
    |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/drop-track-field-assign-nonsend.rs:20:39
    |
diff --git a/tests/ui/async-await/field-assign-nonsend.stderr b/tests/ui/async-await/field-assign-nonsend.stderr
index 525a2cc78b4..418a0829c65 100644
--- a/tests/ui/async-await/field-assign-nonsend.stderr
+++ b/tests/ui/async-await/field-assign-nonsend.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     assert_send(agent.handle());
    |                 ^^^^^^^^^^^^^^ future returned by `handle` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<String>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/field-assign-nonsend.rs:20:39
    |
diff --git a/tests/ui/async-await/in-trait/missing-send-bound.stderr b/tests/ui/async-await/in-trait/missing-send-bound.stderr
index 93f37a9a8e9..aeabb5931df 100644
--- a/tests/ui/async-await/in-trait/missing-send-bound.stderr
+++ b/tests/ui/async-await/in-trait/missing-send-bound.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     assert_is_send(test::<T>());
    |                    ^^^^^^^^^^^ future returned by `test` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `impl Future<Output = ()>`
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/missing-send-bound.rs:9:5
    |
diff --git a/tests/ui/async-await/issue-101715.stderr b/tests/ui/async-await/issue-101715.stderr
index 3b429793b78..f6af15c00d6 100644
--- a/tests/ui/async-await/issue-101715.stderr
+++ b/tests/ui/async-await/issue-101715.stderr
@@ -7,7 +7,7 @@ LL |         .await
    |         |`()` is not a future
    |         help: remove the `.await`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 
diff --git a/tests/ui/async-await/issue-64130-1-sync.stderr b/tests/ui/async-await/issue-64130-1-sync.stderr
index 15f49124f6f..5428d7ef71b 100644
--- a/tests/ui/async-await/issue-64130-1-sync.stderr
+++ b/tests/ui/async-await/issue-64130-1-sync.stderr
@@ -4,7 +4,7 @@ error: future cannot be shared between threads safely
 LL |     is_sync(bar());
    |             ^^^^^ future returned by `bar` is not `Sync`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Sync`
+   = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo`
 note: future is not `Sync` as this value is used across an await
   --> $DIR/issue-64130-1-sync.rs:15:11
    |
diff --git a/tests/ui/async-await/issue-64130-2-send.stderr b/tests/ui/async-await/issue-64130-2-send.stderr
index 67368314b1b..f05e954d2d7 100644
--- a/tests/ui/async-await/issue-64130-2-send.stderr
+++ b/tests/ui/async-await/issue-64130-2-send.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(bar());
    |             ^^^^^ future returned by `bar` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-64130-2-send.rs:15:11
    |
diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr
index e3a73920c92..3ac30bdc23e 100644
--- a/tests/ui/async-await/issue-64130-3-other.stderr
+++ b/tests/ui/async-await/issue-64130-3-other.stderr
@@ -5,7 +5,7 @@ LL | async fn bar() {
    | -------------- within this `impl Future<Output = ()>`
 ...
 LL |     is_qux(bar());
-   |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`, which is required by `impl Future<Output = ()>: Qux`
+   |            ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo`
    |
 note: future does not implement `Qux` as this value is used across an await
   --> $DIR/issue-64130-3-other.rs:18:11
diff --git a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
index bd890c83817..d28807e223b 100644
--- a/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
+++ b/tests/ui/async-await/issue-64130-non-send-future-diags.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo());
    |             ^^^^^ future returned by `foo` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-64130-non-send-future-diags.rs:17:11
    |
diff --git a/tests/ui/async-await/issue-67252-unnamed-future.stderr b/tests/ui/async-await/issue-67252-unnamed-future.stderr
index 2ed40284702..4ec6779dda8 100644
--- a/tests/ui/async-await/issue-67252-unnamed-future.stderr
+++ b/tests/ui/async-await/issue-67252-unnamed-future.stderr
@@ -8,7 +8,7 @@ LL | |         let _a = a;
 LL | |     });
    | |______^ future created by async block is not `Send`
    |
-   = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}: Send`
+   = help: within `{async block@$DIR/issue-67252-unnamed-future.rs:18:11: 18:16}`, the trait `Send` is not implemented for `*mut ()`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-67252-unnamed-future.rs:20:17
    |
diff --git a/tests/ui/async-await/issue-68112.stderr b/tests/ui/async-await/issue-68112.stderr
index ca60079f3ef..f8889ebcca1 100644
--- a/tests/ui/async-await/issue-68112.stderr
+++ b/tests/ui/async-await/issue-68112.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     require_send(send_fut);
    |     ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:29:20: 29:25}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:31:17
@@ -23,7 +23,7 @@ error: future cannot be sent between threads safely
 LL |     require_send(send_fut);
    |     ^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:39:20: 39:25}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: future is not `Send` as it awaits another future which is not `Send`
   --> $DIR/issue-68112.rs:40:17
@@ -42,7 +42,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely
 LL |     require_send(send_fut);
    |     ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{async block@$DIR/issue-68112.rs:57:20: 57:25}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this `async` fn body
diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr
index 1ca0b339c16..c6b7e21b9dd 100644
--- a/tests/ui/async-await/issue-70935-complex-spans.stderr
+++ b/tests/ui/async-await/issue-70935-complex-spans.stderr
@@ -4,7 +4,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely
 LL | fn foo(x: NotSync) -> impl Future + Send {
    |                       ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
    |
-   = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send`
+   = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
 note: required because it appears within the type `PhantomData<*mut ()>`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
 note: required because it appears within the type `NotSync`
@@ -37,7 +37,7 @@ error[E0277]: `*mut ()` cannot be shared between threads safely
 LL | fn foo(x: NotSync) -> impl Future + Send {
    |                       ^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
    |
-   = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`, which is required by `{async block@$DIR/issue-70935-complex-spans.rs:18:5: 18:15}: Send`
+   = help: within `NotSync`, the trait `Sync` is not implemented for `*mut ()`
 note: required because it appears within the type `PhantomData<*mut ()>`
   --> $SRC_DIR/core/src/marker.rs:LL:COL
 note: required because it appears within the type `NotSync`
diff --git a/tests/ui/async-await/issue-71137.stderr b/tests/ui/async-await/issue-71137.stderr
index 75d72e425f5..8739c22a310 100644
--- a/tests/ui/async-await/issue-71137.stderr
+++ b/tests/ui/async-await/issue-71137.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |   fake_spawn(wrong_mutex());
    |              ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
 note: future is not `Send` as this value is used across an await
   --> $DIR/issue-71137.rs:14:26
    |
diff --git a/tests/ui/async-await/issue-72590-type-error-sized.stderr b/tests/ui/async-await/issue-72590-type-error-sized.stderr
index 1b822234d80..778423578e1 100644
--- a/tests/ui/async-await/issue-72590-type-error-sized.stderr
+++ b/tests/ui/async-await/issue-72590-type-error-sized.stderr
@@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL |     async fn frob(self) {}
    |                   ^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized`
+   = help: within `Foo`, the trait `Sized` is not implemented for `str`
 note: required because it appears within the type `Foo`
   --> $DIR/issue-72590-type-error-sized.rs:5:8
    |
diff --git a/tests/ui/async-await/issues/issue-67893.stderr b/tests/ui/async-await/issues/issue-67893.stderr
index 0c28aea44bb..c01237255b8 100644
--- a/tests/ui/async-await/issues/issue-67893.stderr
+++ b/tests/ui/async-await/issues/issue-67893.stderr
@@ -11,7 +11,7 @@ LL |     g(issue_67893::run())
 LL | pub async fn run() {
    | ------------------ within this `impl Future<Output = ()>`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
 note: required because it's used within this `async` fn body
   --> $DIR/auxiliary/issue_67893.rs:9:20
    |
diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr
index 0bd7d50b941..042ed18984e 100644
--- a/tests/ui/async-await/partial-drop-partial-reinit.stderr
+++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr
@@ -9,7 +9,7 @@ LL |     gimme_send(foo());
 LL | async fn foo() {
    | -------------- within this `impl Future<Output = ()>`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`, which is required by `impl Future<Output = ()>: Send`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend`
    = note: required because it appears within the type `(NotSend,)`
 note: required because it's used within this `async` fn body
   --> $DIR/partial-drop-partial-reinit.rs:27:16
diff --git a/tests/ui/async-await/pin-needed-to-poll-2.stderr b/tests/ui/async-await/pin-needed-to-poll-2.stderr
index e22baabc25b..8eb671531e7 100644
--- a/tests/ui/async-await/pin-needed-to-poll-2.stderr
+++ b/tests/ui/async-await/pin-needed-to-poll-2.stderr
@@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned
   --> $DIR/pin-needed-to-poll-2.rs:43:18
    |
 LL |         Pin::new(&mut self.sleep).poll(cx)
-   |         -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Sleep: Unpin`
+   |         -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
    |         |
    |         required by a bound introduced by this call
    |
diff --git a/tests/ui/async-await/unnecessary-await.stderr b/tests/ui/async-await/unnecessary-await.stderr
index 8d819576532..620370a6113 100644
--- a/tests/ui/async-await/unnecessary-await.stderr
+++ b/tests/ui/async-await/unnecessary-await.stderr
@@ -6,7 +6,7 @@ LL |     boo().await;
    |     |
    |     this call returns `()`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 help: remove the `.await`
@@ -28,7 +28,7 @@ LL |     e!().await;
    |         |`()` is not a future
    |         help: remove the `.await`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 
@@ -44,7 +44,7 @@ LL |         $expr.await
 LL |     f!(());
    |     ------ in this macro invocation
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
    = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -58,7 +58,7 @@ LL |     for x in [] {}.await
    |                   |`()` is not a future
    |                   help: remove the `.await`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 
diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr
index 20bfe7e36ca..7c437b7e6c8 100644
--- a/tests/ui/auto-traits/issue-83857-ub.stderr
+++ b/tests/ui/auto-traits/issue-83857-ub.stderr
@@ -4,7 +4,7 @@ error[E0277]: `Foo<T, U>` cannot be sent between threads safely
 LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) {
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `Foo<T, U>`, which is required by `Foo<T, U>: WithAssoc`
+   = help: the trait `Send` is not implemented for `Foo<T, U>`
 note: required for `Foo<T, U>` to implement `WithAssoc`
   --> $DIR/issue-83857-ub.rs:14:15
    |
@@ -29,7 +29,7 @@ LL | |
 LL | | }
    | |_^ `Foo<T, U>` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `Foo<T, U>`, which is required by `Foo<T, U>: WithAssoc`
+   = help: the trait `Send` is not implemented for `Foo<T, U>`
 note: required for `Foo<T, U>` to implement `WithAssoc`
   --> $DIR/issue-83857-ub.rs:14:15
    |
diff --git a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr
index ebd3a556e75..e1dae35be00 100644
--- a/tests/ui/auto-traits/str-contains-slice-conceptually.stderr
+++ b/tests/ui/auto-traits/str-contains-slice-conceptually.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `[u8]: AutoTrait` is not satisfied in `str`
   --> $DIR/str-contains-slice-conceptually.rs:11:22
    |
 LL |   needs_auto_trait::<str>();
-   |                      ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]`, which is required by `str: AutoTrait`
+   |                      ^^^ within `str`, the trait `AutoTrait` is not implemented for `[u8]`
    |
    = note: `str` is considered to contain a `[u8]` slice for auto trait purposes
 note: required by a bound in `needs_auto_trait`
diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr
index b7c97389912..aa5585a5371 100644
--- a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr
+++ b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)`
   --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:18
    |
 LL |     is_mytrait::<(MyS2, MyS)>();
-   |                  ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`, which is required by `(MyS2, MyS): MyTrait`
+   |                  ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2`
    |
    = note: required because it appears within the type `(MyS2, MyS)`
 note: required by a bound in `is_mytrait`
diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
index 4773ac4ccf7..fca01b3f48d 100644
--- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
+++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static u32: Defaulted` is not satisfied
   --> $DIR/typeck-default-trait-impl-precedence.rs:19:20
    |
 LL |     is_defaulted::<&'static u32>();
-   |                    ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`, which is required by `&'static u32: Defaulted`
+   |                    ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
    |
 note: required for `&'static u32` to implement `Defaulted`
   --> $DIR/typeck-default-trait-impl-precedence.rs:10:19
diff --git a/tests/ui/binop/binary-op-suggest-deref.stderr b/tests/ui/binop/binary-op-suggest-deref.stderr
index 01852fbc633..440625d8ccb 100644
--- a/tests/ui/binop/binary-op-suggest-deref.stderr
+++ b/tests/ui/binop/binary-op-suggest-deref.stderr
@@ -27,7 +27,7 @@ error[E0277]: can't compare `&{integer}` with `{integer}`
 LL |     _ = foo == &0;
    |             ^^ no implementation for `&{integer} == {integer}`
    |
-   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`, which is required by `&&{integer}: PartialEq<&{integer}>`
+   = help: the trait `PartialEq<{integer}>` is not implemented for `&{integer}`
    = note: required for `&&{integer}` to implement `PartialEq<&{integer}>`
 help: consider dereferencing here
    |
@@ -65,7 +65,7 @@ error[E0277]: can't compare `&&{integer}` with `{integer}`
 LL |     _ = &&foo == &&0;
    |               ^^ no implementation for `&&{integer} == {integer}`
    |
-   = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}`, which is required by `&&&&{integer}: PartialEq<&&{integer}>`
+   = help: the trait `PartialEq<{integer}>` is not implemented for `&&{integer}`
    = note: required for `&&&{integer}` to implement `PartialEq<&{integer}>`
    = note: 1 redundant requirement hidden
    = note: required for `&&&&{integer}` to implement `PartialEq<&&{integer}>`
@@ -119,7 +119,7 @@ error[E0277]: can't compare `{integer}` with `&{integer}`
 LL |     _ = &0 == foo;
    |            ^^ no implementation for `{integer} == &{integer}`
    |
-   = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`, which is required by `&{integer}: PartialEq<&&{integer}>`
+   = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
    = note: required for `&{integer}` to implement `PartialEq<&&{integer}>`
 help: consider dereferencing here
    |
@@ -157,7 +157,7 @@ error[E0277]: can't compare `{integer}` with `&&{integer}`
 LL |     _ = &&0 == &&foo;
    |             ^^ no implementation for `{integer} == &&{integer}`
    |
-   = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}`, which is required by `&&{integer}: PartialEq<&&&&{integer}>`
+   = help: the trait `PartialEq<&&{integer}>` is not implemented for `{integer}`
    = note: required for `&{integer}` to implement `PartialEq<&&&{integer}>`
    = note: 1 redundant requirement hidden
    = note: required for `&&{integer}` to implement `PartialEq<&&&&{integer}>`
@@ -173,7 +173,7 @@ error[E0277]: can't compare `Box<Box<{integer}>>` with `&&{integer}`
 LL |     _ = &Box::new(Box::new(42)) == &foo;
    |                                 ^^ no implementation for `Box<Box<{integer}>> == &&{integer}`
    |
-   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<{integer}>>`, which is required by `&Box<Box<{integer}>>: PartialEq<&&&{integer}>`
+   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<{integer}>>`
    = note: required for `&Box<Box<{integer}>>` to implement `PartialEq<&&&{integer}>`
 help: consider dereferencing both sides of the expression
    |
@@ -187,7 +187,7 @@ error[E0277]: can't compare `Box<{integer}>` with `&&{integer}`
 LL |     _ = &Box::new(42) == &foo;
    |                       ^^ no implementation for `Box<{integer}> == &&{integer}`
    |
-   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>`, which is required by `&Box<{integer}>: PartialEq<&&&{integer}>`
+   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<{integer}>`
    = note: required for `&Box<{integer}>` to implement `PartialEq<&&&{integer}>`
 help: consider dereferencing both sides of the expression
    |
@@ -201,7 +201,7 @@ error[E0277]: can't compare `Box<Box<Box<Box<{integer}>>>>` with `&&{integer}`
 LL |     _ = &Box::new(Box::new(Box::new(Box::new(42)))) == &foo;
    |                                                     ^^ no implementation for `Box<Box<Box<Box<{integer}>>>> == &&{integer}`
    |
-   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<Box<Box<{integer}>>>>`, which is required by `&Box<Box<Box<Box<{integer}>>>>: PartialEq<&&&{integer}>`
+   = help: the trait `PartialEq<&&{integer}>` is not implemented for `Box<Box<Box<Box<{integer}>>>>`
    = note: required for `&Box<Box<Box<Box<{integer}>>>>` to implement `PartialEq<&&&{integer}>`
 help: consider dereferencing both sides of the expression
    |
@@ -215,7 +215,7 @@ error[E0277]: can't compare `&&{integer}` with `Box<Box<Box<Box<{integer}>>>>`
 LL |     _ = &foo == &Box::new(Box::new(Box::new(Box::new(42))));
    |              ^^ no implementation for `&&{integer} == Box<Box<Box<Box<{integer}>>>>`
    |
-   = help: the trait `PartialEq<Box<Box<Box<Box<{integer}>>>>>` is not implemented for `&&{integer}`, which is required by `&&&{integer}: PartialEq<&Box<Box<Box<Box<{integer}>>>>>`
+   = help: the trait `PartialEq<Box<Box<Box<Box<{integer}>>>>>` is not implemented for `&&{integer}`
    = note: required for `&&&{integer}` to implement `PartialEq<&Box<Box<Box<Box<{integer}>>>>>`
 help: consider dereferencing both sides of the expression
    |
diff --git a/tests/ui/block-result/issue-22645.stderr b/tests/ui/block-result/issue-22645.stderr
index 2a267ce792f..1064848f513 100644
--- a/tests/ui/block-result/issue-22645.stderr
+++ b/tests/ui/block-result/issue-22645.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `{integer}: Scalar` is not satisfied
   --> $DIR/issue-22645.rs:15:5
    |
 LL |   b + 3
-   |     ^ the trait `Scalar` is not implemented for `{integer}`, which is required by `Bob: Add<_>`
+   |     ^ the trait `Scalar` is not implemented for `{integer}`
    |
    = help: the trait `Scalar` is implemented for `f64`
 note: required for `Bob` to implement `Add<{integer}>`
diff --git a/tests/ui/cast/unsized-union-ice.stderr b/tests/ui/cast/unsized-union-ice.stderr
index 05f86457829..1c9450b8e18 100644
--- a/tests/ui/cast/unsized-union-ice.stderr
+++ b/tests/ui/cast/unsized-union-ice.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     val: std::mem::ManuallyDrop<[u8]>,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `ManuallyDrop<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `ManuallyDrop<[u8]>: Sized`
+   = help: within `ManuallyDrop<[u8]>`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `ManuallyDrop<[u8]>`
   --> $SRC_DIR/core/src/mem/manually_drop.rs:LL:COL
    = note: no field of a union may have a dynamically sized type
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index c21016e9290..7589551a87c 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra`
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 245 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 246 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index da790bbd528..b0ca09a59ed 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -174,7 +174,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `partword-atomics`, `pauth-lr`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `quadword-atomics`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-b16b16`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zaamo`, `zabha`, `zalrsc`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
diff --git a/tests/ui/closures/closure-move-sync.stderr b/tests/ui/closures/closure-move-sync.stderr
index 6cade0c09dd..2bb26b0c0b7 100644
--- a/tests/ui/closures/closure-move-sync.stderr
+++ b/tests/ui/closures/closure-move-sync.stderr
@@ -10,7 +10,7 @@ LL | |
 LL | |     });
    | |_____^ `std::sync::mpsc::Receiver<()>` cannot be shared between threads safely
    |
-   = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`, which is required by `{closure@$DIR/closure-move-sync.rs:6:27: 6:29}: Send`
+   = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>`
    = note: required for `&std::sync::mpsc::Receiver<()>` to implement `Send`
 note: required because it's used within this closure
   --> $DIR/closure-move-sync.rs:6:27
diff --git a/tests/ui/closures/closure-return-type-must-be-sized.stderr b/tests/ui/closures/closure-return-type-must-be-sized.stderr
index 167d326e26e..04ae7343bbe 100644
--- a/tests/ui/closures/closure-return-type-must-be-sized.stderr
+++ b/tests/ui/closures/closure-return-type-must-be-sized.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     a::foo::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
@@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     a::bar::<fn() -> dyn A, _>();
    |              ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 note: required by a bound in `a::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:14:19
@@ -27,7 +27,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     a::baz::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
@@ -36,7 +36,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     b::foo::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
@@ -45,7 +45,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     b::bar::<fn() -> dyn A, _>();
    |              ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: Fn()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 note: required by a bound in `b::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:28:19
@@ -59,7 +59,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     b::baz::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
@@ -68,7 +68,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     c::foo::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error[E0277]: the size for values of type `dyn A` cannot be known at compilation time
@@ -77,7 +77,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     c::bar::<fn() -> dyn A, _>();
    |              ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnMut()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 note: required by a bound in `c::bar`
   --> $DIR/closure-return-type-must-be-sized.rs:42:19
@@ -91,7 +91,7 @@ error[E0277]: the size for values of type `dyn A` cannot be known at compilation
 LL |     c::baz::<fn() -> dyn A>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`, which is required by `fn() -> dyn A: FnOnce()`
+   = help: within `fn() -> dyn A`, the trait `Sized` is not implemented for `dyn A`
    = note: required because it appears within the type `fn() -> dyn A`
 
 error: aborting due to 9 previous errors
diff --git a/tests/ui/coherence/deep-bad-copy-reason.stderr b/tests/ui/coherence/deep-bad-copy-reason.stderr
index fe5ae9b08b4..534f26c39c2 100644
--- a/tests/ui/coherence/deep-bad-copy-reason.stderr
+++ b/tests/ui/coherence/deep-bad-copy-reason.stderr
@@ -19,7 +19,7 @@ error[E0277]: the size for values of type `OpaqueListContents` cannot be known a
 LL | pub struct List<'tcx, T>(Interned<'tcx, ListS<T>>);
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `ListS<T>`, the trait `Sized` is not implemented for `OpaqueListContents`, which is required by `ListS<T>: Sized`
+   = help: within `ListS<T>`, the trait `Sized` is not implemented for `OpaqueListContents`
 note: required because it appears within the type `ListS<T>`
   --> $DIR/deep-bad-copy-reason.rs:7:12
    |
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
index 9852e181b9a..9220cd1f94e 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr
@@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad_empty_array.rs:10:13
    |
 LL |     check::<[NotParam; 0]>();
-   |             ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy_`
+   |             ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`
    |
    = note: required for `[NotParam; 0]` to implement `ConstParamTy_`
 note: required by a bound in `check`
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
index e63ae582fd5..d01aaffe8ae 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr
@@ -2,7 +2,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13
    |
 LL |     check::<&NotParam>();
-   |             ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: UnsizedConstParamTy`
+   |             ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`
    |
    = note: required for `&NotParam` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
@@ -15,7 +15,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13
    |
 LL |     check::<[NotParam]>();
-   |             ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: UnsizedConstParamTy`
+   |             ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`
    |
    = note: required for `[NotParam]` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
@@ -28,7 +28,7 @@ error[E0277]: `NotParam` can't be used as a const parameter type
   --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13
    |
 LL |     check::<[NotParam; 17]>();
-   |             ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: UnsizedConstParamTy`
+   |             ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`
    |
    = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy`
 note: required by a bound in `check`
diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr
index 1c30aa68e85..72f3fd9de90 100644
--- a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr
+++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr
@@ -64,7 +64,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
 LL |     nested: &'static Bar<dyn std::fmt::Debug>,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`, which is required by `&&'static Bar<(dyn Debug + 'static)>: Debug`
+   = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)`
    = help: the trait `Debug` is implemented for `Bar<T>`
 note: required for `Bar<(dyn Debug + 'static)>` to implement `Debug`
   --> $DIR/unsizing-wfcheck-issue-126272.rs:20:10
@@ -96,7 +96,7 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)]
    |                            -- in this derive macro expansion
 ...
 LL |     nested: &'static Bar<dyn std::fmt::Debug>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `dyn Debug`, which is required by `&'static Bar<dyn Debug>: Eq`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `dyn Debug`
    |
    = help: the trait `Eq` is implemented for `Bar<T>`
 note: required for `Bar<dyn Debug>` to implement `Eq`
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
index 4abe39eb598..6ff22ffa847 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-85848.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied
   --> $DIR/issue-85848.rs:24:29
    |
 LL |     writes_to_specific_path(&cap);
-   |     ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`, which is required by `&C: Delegates<()>`
+   |     ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/const-generics/issues/issue-67185-2.stderr b/tests/ui/const-generics/issues/issue-67185-2.stderr
index 5cc3bb673bc..82813a24f99 100644
--- a/tests/ui/const-generics/issues/issue-67185-2.stderr
+++ b/tests/ui/const-generics/issues/issue-67185-2.stderr
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied
   --> $DIR/issue-67185-2.rs:21:6
    |
 LL | impl Foo for FooImpl {}
-   |      ^^^ the trait `Bar` is not implemented for `[u16; 3]`, which is required by `<u8 as Baz>::Quaks: Bar`
+   |      ^^^ the trait `Bar` is not implemented for `[u16; 3]`
    |
    = help: the following other types implement trait `Bar`:
              [[u16; 3]; 3]
@@ -50,7 +50,7 @@ error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied
   --> $DIR/issue-67185-2.rs:21:6
    |
 LL | impl Foo for FooImpl {}
-   |      ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`, which is required by `[<u8 as Baz>::Quaks; 2]: Bar`
+   |      ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]`
    |
    = help: the following other types implement trait `Bar`:
              [[u16; 3]; 3]
diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr
index 80968ebea68..e13bc6ee058 100644
--- a/tests/ui/const-generics/kind_mismatch.stderr
+++ b/tests/ui/const-generics/kind_mismatch.stderr
@@ -18,7 +18,7 @@ error[E0277]: the trait bound `KeyHolder<0>: SubsetExcept<_>` is not satisfied
   --> $DIR/kind_mismatch.rs:22:45
    |
 LL |     let map: KeyHolder<0> = remove_key::<_, _>();
-   |                                             ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>`, which is required by `KeyHolder<0>: SubsetExcept<_>`
+   |                                             ^ the trait `ContainsKey<0>` is not implemented for `KeyHolder<0>`
    |
 note: required for `KeyHolder<0>` to implement `SubsetExcept<_>`
   --> $DIR/kind_mismatch.rs:15:28
diff --git a/tests/ui/consts/const-block-const-bound.stderr b/tests/ui/consts/const-block-const-bound.stderr
index 8cb91d78f6c..5e24959146b 100644
--- a/tests/ui/consts/const-block-const-bound.stderr
+++ b/tests/ui/consts/const-block-const-bound.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-block-const-bound.rs:8:22
+  --> $DIR/const-block-const-bound.rs:8:15
    |
 LL | const fn f<T: ~const Destruct>(x: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-block-const-bound.rs:8:22
+  --> $DIR/const-block-const-bound.rs:8:15
    |
 LL | const fn f<T: ~const Destruct>(x: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr
index 9dce29732ac..272c2f045e1 100644
--- a/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr
+++ b/tests/ui/consts/const-blocks/fn-call-in-non-const.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied
   --> $DIR/fn-call-in-non-const.rs:14:32
    |
 LL |     let _: [Option<Bar>; 2] = [no_copy(); 2];
-   |                                ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy`
+   |                                ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
diff --git a/tests/ui/consts/const-blocks/migrate-fail.stderr b/tests/ui/consts/const-blocks/migrate-fail.stderr
index 3887658f748..3c116026e58 100644
--- a/tests/ui/consts/const-blocks/migrate-fail.stderr
+++ b/tests/ui/consts/const-blocks/migrate-fail.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied
   --> $DIR/migrate-fail.rs:11:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                      ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
@@ -18,7 +18,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied
   --> $DIR/migrate-fail.rs:17:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                      ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
diff --git a/tests/ui/consts/const-blocks/nll-fail.stderr b/tests/ui/consts/const-blocks/nll-fail.stderr
index a2ea833f650..ff2b62da668 100644
--- a/tests/ui/consts/const-blocks/nll-fail.stderr
+++ b/tests/ui/consts/const-blocks/nll-fail.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied
   --> $DIR/nll-fail.rs:11:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                      ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
@@ -18,7 +18,7 @@ error[E0277]: the trait bound `Bar: Copy` is not satisfied
   --> $DIR/nll-fail.rs:17:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                      ^ the trait `Copy` is not implemented for `Bar`, which is required by `Option<Bar>: Copy`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required for `Option<Bar>` to implement `Copy`
    = note: the `Copy` trait is required because this value will be copied for each element of the array
diff --git a/tests/ui/consts/const-blocks/trait-error.stderr b/tests/ui/consts/const-blocks/trait-error.stderr
index 8f00f14dfb9..068720a53f6 100644
--- a/tests/ui/consts/const-blocks/trait-error.stderr
+++ b/tests/ui/consts/const-blocks/trait-error.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
 LL |     [Foo(String::new()); 4];
    |      ^^^^^^^^^^^^^^^^^^
    |      |
-   |      the trait `Copy` is not implemented for `String`, which is required by `Foo<String>: Copy`
+   |      the trait `Copy` is not implemented for `String`
    |      help: create an inline `const` block: `const { Foo(String::new()) }`
    |
 note: required for `Foo<String>` to implement `Copy`
diff --git a/tests/ui/consts/const-fn-in-vec.stderr b/tests/ui/consts/const-fn-in-vec.stderr
index 7c6b3bee940..b31e180fea2 100644
--- a/tests/ui/consts/const-fn-in-vec.stderr
+++ b/tests/ui/consts/const-fn-in-vec.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
 LL | static _MAYBE_STRINGS: [Option<String>; 5] = [None; 5];
    |                                               ^^^^
    |                                               |
-   |                                               the trait `Copy` is not implemented for `String`, which is required by `Option<String>: Copy`
+   |                                               the trait `Copy` is not implemented for `String`
    |                                               help: create an inline `const` block: `const { None }`
    |
    = note: required for `Option<String>` to implement `Copy`
@@ -27,7 +27,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
 LL |     let _maybe_strings: [Option<String>; 5] = [None; 5];
    |                                                ^^^^
    |                                                |
-   |                                                the trait `Copy` is not implemented for `String`, which is required by `Option<String>: Copy`
+   |                                                the trait `Copy` is not implemented for `String`
    |                                                help: create an inline `const` block: `const { None }`
    |
    = note: required for `Option<String>` to implement `Copy`
diff --git a/tests/ui/consts/constifconst-call-in-const-position.stderr b/tests/ui/consts/constifconst-call-in-const-position.stderr
index 2195cab3f4d..6add83dc52c 100644
--- a/tests/ui/consts/constifconst-call-in-const-position.stderr
+++ b/tests/ui/consts/constifconst-call-in-const-position.stderr
@@ -1,14 +1,15 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
+error[E0277]: the trait bound `T: const Tr` is not satisfied
   --> $DIR/constifconst-call-in-const-position.rs:17:38
    |
 LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
-   |                                      ^^^^^^ calling non-const function `<() as Tr>::a`
+   |                                      ^^^^^^
+
+error[E0277]: the trait bound `T: const Tr` is not satisfied
+  --> $DIR/constifconst-call-in-const-position.rs:18:9
+   |
+LL |     [0; T::a()]
+   |         ^^^^^^
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr
index 82b2b87c4a5..a686bc23c0f 100644
--- a/tests/ui/consts/fn_trait_refs.stderr
+++ b/tests/ui/consts/fn_trait_refs.stderr
@@ -11,168 +11,168 @@ LL | #![feature(const_cmp)]
    |            ^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:31
+  --> $DIR/fn_trait_refs.rs:13:24
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
+   |                        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:15
+  --> $DIR/fn_trait_refs.rs:13:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:13:31
+  --> $DIR/fn_trait_refs.rs:13:24
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
+   |                        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:15
+  --> $DIR/fn_trait_refs.rs:20:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:34
+  --> $DIR/fn_trait_refs.rs:20:27
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
+   |                           ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:15
+  --> $DIR/fn_trait_refs.rs:20:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:15
+  --> $DIR/fn_trait_refs.rs:20:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:20:34
+  --> $DIR/fn_trait_refs.rs:20:27
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
+   |                           ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:27:15
+  --> $DIR/fn_trait_refs.rs:27:8
    |
 LL |     T: ~const FnOnce<()>,
-   |               ^^^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:27:15
+  --> $DIR/fn_trait_refs.rs:27:8
    |
 LL |     T: ~const FnOnce<()>,
-   |               ^^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:27:15
+  --> $DIR/fn_trait_refs.rs:27:8
    |
 LL |     T: ~const FnOnce<()>,
-   |               ^^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:15
+  --> $DIR/fn_trait_refs.rs:34:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:31
+  --> $DIR/fn_trait_refs.rs:34:24
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
+   |                        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:15
+  --> $DIR/fn_trait_refs.rs:34:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:15
+  --> $DIR/fn_trait_refs.rs:34:8
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |               ^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:34:31
+  --> $DIR/fn_trait_refs.rs:34:24
    |
 LL |     T: ~const Fn<()> + ~const Destruct,
-   |                               ^^^^^^^^
+   |                        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:15
+  --> $DIR/fn_trait_refs.rs:48:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:34
+  --> $DIR/fn_trait_refs.rs:48:27
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
+   |                           ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:15
+  --> $DIR/fn_trait_refs.rs:48:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:15
+  --> $DIR/fn_trait_refs.rs:48:8
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |               ^^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/fn_trait_refs.rs:48:34
+  --> $DIR/fn_trait_refs.rs:48:27
    |
 LL |     T: ~const FnMut<()> + ~const Destruct,
-   |                                  ^^^^^^^^
+   |                           ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/consts/rustc-const-stability-require-const.rs b/tests/ui/consts/rustc-const-stability-require-const.rs
index 1c66f6e2aa5..6cc3f0f0da1 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.rs
+++ b/tests/ui/consts/rustc-const-stability-require-const.rs
@@ -47,16 +47,15 @@ pub const fn foobar() {}
 pub const fn barfoo() {}
 
 // `rustc_const_stable` also requires the function to be stable.
-// FIXME: these are disabled until <https://github.com/rust-lang/stdarch/pull/1654> propagates.
 
 #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
 const fn barfoo_unmarked() {}
-// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]`
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
 
 #[unstable(feature = "unstable", issue = "none")]
 #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
 pub const fn barfoo_unstable() {}
-// FIXME disabled ERROR can only be applied to functions that are declared `#[stable]`
+//~^ ERROR can only be applied to functions that are declared `#[stable]`
 
 // `#[rustc_const_stable_indirect]` also requires a const fn
 #[rustc_const_stable_indirect]
diff --git a/tests/ui/consts/rustc-const-stability-require-const.stderr b/tests/ui/consts/rustc-const-stability-require-const.stderr
index 09b96ce6f83..d9a7d37cbcd 100644
--- a/tests/ui/consts/rustc-const-stability-require-const.stderr
+++ b/tests/ui/consts/rustc-const-stability-require-const.stderr
@@ -70,17 +70,33 @@ help: make the function or method const
 LL | pub extern "C" fn foo_c() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+  --> $DIR/rustc-const-stability-require-const.rs:52:1
+   |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+   | ---------------------------------------------------------------- attribute specified here
+LL | const fn barfoo_unmarked() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
+  --> $DIR/rustc-const-stability-require-const.rs:57:1
+   |
+LL | #[rustc_const_stable(feature = "barfoo_const", since = "1.0.0")]
+   | ---------------------------------------------------------------- attribute specified here
+LL | pub const fn barfoo_unstable() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: attributes `#[rustc_const_unstable]`, `#[rustc_const_stable]` and `#[rustc_const_stable_indirect]` require the function or method to be `const`
-  --> $DIR/rustc-const-stability-require-const.rs:64:1
+  --> $DIR/rustc-const-stability-require-const.rs:63:1
    |
 LL | pub fn not_a_const_fn() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: make the function or method const
-  --> $DIR/rustc-const-stability-require-const.rs:64:1
+  --> $DIR/rustc-const-stability-require-const.rs:63:1
    |
 LL | pub fn not_a_const_fn() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
index e546694070d..2bdec1bf41b 100644
--- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr
+++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/unstable-const-fn-in-libcore.rs:19:39
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:32
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                       ^^^^^^^^^^^^^
+   |                                ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/unstable-const-fn-in-libcore.rs:19:39
+  --> $DIR/unstable-const-fn-in-libcore.rs:19:32
    |
 LL |     const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T {
-   |                                       ^^^^^^^^^^^^^
+   |                                ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/consts/zst_no_llvm_alloc.rs b/tests/ui/consts/zst_no_llvm_alloc.rs
index 48ef11e2b58..1e92e3bbd4c 100644
--- a/tests/ui/consts/zst_no_llvm_alloc.rs
+++ b/tests/ui/consts/zst_no_llvm_alloc.rs
@@ -17,8 +17,11 @@ fn main() {
 
     // The exact addresses returned by these library functions are not necessarily stable guarantees
     // but for now we assert that we're still matching.
-    assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
-    assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    #[allow(dangling_pointers_from_temporaries)]
+    {
+        assert_eq!(<Vec<i32>>::new().as_ptr(), <&[i32]>::default().as_ptr());
+        assert_eq!(<Box<[i32]>>::default().as_ptr(), (&[]).as_ptr());
+    };
 
     // statics must have a unique address (see https://github.com/rust-lang/rust/issues/18297, not
     // clear whether this is a stable guarantee)
diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr
index 5330d3bbd39..1256c97a02f 100644
--- a/tests/ui/coroutine/clone-impl.stderr
+++ b/tests/ui/coroutine/clone-impl.stderr
@@ -5,7 +5,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
 ...
 LL |     check_copy(&gen_clone_0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<u32>`
    |
 note: captured value does not implement `Copy`
   --> $DIR/clone-impl.rs:47:14
@@ -25,7 +25,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`
 ...
 LL |     check_copy(&gen_clone_0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}: Copy`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:43:5: 43:12}`, the trait `Copy` is not implemented for `Vec<char>`
    |
 note: coroutine does not implement `Copy` as this value is used across a yield
   --> $DIR/clone-impl.rs:45:9
@@ -47,7 +47,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
 ...
 LL |     check_copy(&gen_clone_1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<u32>`
    |
 note: captured value does not implement `Copy`
   --> $DIR/clone-impl.rs:68:14
@@ -67,7 +67,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`
 ...
 LL |     check_copy(&gen_clone_1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`, which is required by `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}: Copy`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:58:5: 58:12}`, the trait `Copy` is not implemented for `Vec<char>`
    |
 note: coroutine does not implement `Copy` as this value is used across a yield
   --> $DIR/clone-impl.rs:64:9
@@ -90,7 +90,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
 ...
 LL |     check_copy(&gen_non_clone);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Copy`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Copy` is not implemented for `NonClone`
    |
 note: captured value does not implement `Copy`
   --> $DIR/clone-impl.rs:81:14
@@ -115,7 +115,7 @@ LL |     move || {
    |     ------- within this `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`
 ...
 LL |     check_clone(&gen_non_clone);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`, which is required by `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}: Clone`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:79:5: 79:12}`, the trait `Clone` is not implemented for `NonClone`
    |
 note: captured value does not implement `Clone`
   --> $DIR/clone-impl.rs:81:14
diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr
index 5f8d8495e4f..51fc20070bf 100644
--- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr
+++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr
@@ -13,7 +13,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/drop-tracking-parent-expression.rs:21:22
    |
@@ -53,7 +53,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/drop-tracking-parent-expression.rs:21:22
    |
@@ -93,7 +93,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/drop-tracking-parent-expression.rs:21:22
    |
diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr
index 362c6e943ad..c5da35d9736 100644
--- a/tests/ui/coroutine/drop-yield-twice.stderr
+++ b/tests/ui/coroutine/drop-yield-twice.stderr
@@ -9,7 +9,7 @@ LL | |         yield;
 LL | |     })
    | |______^ coroutine is not `Send`
    |
-   = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo`, which is required by `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}: Send`
+   = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/drop-yield-twice.rs:9:9
    |
diff --git a/tests/ui/coroutine/issue-105084.stderr b/tests/ui/coroutine/issue-105084.stderr
index 6b1701f0c2a..11b5852b638 100644
--- a/tests/ui/coroutine/issue-105084.stderr
+++ b/tests/ui/coroutine/issue-105084.stderr
@@ -29,7 +29,7 @@ LL |     || {
    |     -- within this `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`
 ...
 LL |     let mut h = copy(g);
-   |                 ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`, which is required by `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}: Copy`
+   |                 ^^^^^^^ within `{coroutine@$DIR/issue-105084.rs:15:5: 15:7}`, the trait `Copy` is not implemented for `Box<(i32, ())>`
    |
 note: coroutine does not implement `Copy` as this value is used across a yield
   --> $DIR/issue-105084.rs:22:22
diff --git a/tests/ui/coroutine/issue-68112.stderr b/tests/ui/coroutine/issue-68112.stderr
index bcfcb5ec6e6..124537b971e 100644
--- a/tests/ui/coroutine/issue-68112.stderr
+++ b/tests/ui/coroutine/issue-68112.stderr
@@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely
 LL |     require_send(send_gen);
    |     ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:33:33: 33:35}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/issue-68112.rs:36:9
@@ -26,7 +26,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely
 LL |     require_send(send_gen);
    |     ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{coroutine@$DIR/issue-68112.rs:60:33: 60:35}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this coroutine
diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr
index 0f9cbdec130..c6d2ac0a557 100644
--- a/tests/ui/coroutine/not-send-sync.stderr
+++ b/tests/ui/coroutine/not-send-sync.stderr
@@ -9,7 +9,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Sync`
    |
-   = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}: Sync`
+   = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync`
 note: coroutine is not `Sync` as this value is used across a yield
   --> $DIR/not-send-sync.rs:17:9
    |
@@ -34,7 +34,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Send`
    |
-   = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend`, which is required by `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}: Send`
+   = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/not-send-sync.rs:24:9
    |
diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr
index 2d817f1bfd9..770ffda7a26 100644
--- a/tests/ui/coroutine/parent-expression.stderr
+++ b/tests/ui/coroutine/parent-expression.stderr
@@ -13,7 +13,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `derived_drop::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/parent-expression.rs:21:22
    |
@@ -53,7 +53,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `significant_drop::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/parent-expression.rs:21:22
    |
@@ -93,7 +93,7 @@ LL | |         };
 LL | |     );
    | |_____- in this macro invocation
    |
-   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`, which is required by `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}: Send`
+   = help: within `{coroutine@$DIR/parent-expression.rs:17:34: 17:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/parent-expression.rs:21:22
    |
diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
index daf88fc1f23..410189b9ab6 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-1.stderr
@@ -4,7 +4,7 @@ error: coroutine cannot be sent between threads safely
 LL |     require_send(send_gen);
    |     ^^^^^^^^^^^^^^^^^^^^^^ coroutine is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{test1::{closure#0} upvar_tys=() witness={test1::{closure#0}}}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-1.rs:35:9
@@ -25,7 +25,7 @@ error[E0277]: `RefCell<i32>` cannot be shared between threads safely
 LL |     require_send(send_gen);
    |     ^^^^^^^^^^^^^^^^^^^^^^ `RefCell<i32>` cannot be shared between threads safely
    |
-   = help: the trait `Sync` is not implemented for `RefCell<i32>`, which is required by `{test2::{closure#0} upvar_tys=() witness={test2::{closure#0}}}: Send`
+   = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Arc<RefCell<i32>>` to implement `Send`
 note: required because it's used within this coroutine
diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
index 0de53d9e1d7..2ab9d35f05a 100644
--- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
+++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr
@@ -9,7 +9,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Sync`
    |
-   = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`, which is required by `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}: Sync`
+   = help: within `{main::{closure#0} upvar_tys=() witness={main::{closure#0}}}`, the trait `Sync` is not implemented for `NotSync`
 note: coroutine is not `Sync` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-2.rs:20:9
    |
@@ -34,7 +34,7 @@ LL | |         drop(a);
 LL | |     });
    | |______^ coroutine is not `Send`
    |
-   = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`, which is required by `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}: Send`
+   = help: within `{main::{closure#1} upvar_tys=() witness={main::{closure#1}}}`, the trait `Send` is not implemented for `NotSend`
 note: coroutine is not `Send` as this value is used across a yield
   --> $DIR/coroutine-print-verbose-2.rs:27:9
    |
diff --git a/tests/ui/coroutine/ref-upvar-not-send.stderr b/tests/ui/coroutine/ref-upvar-not-send.stderr
index 4c7deab3f4c..892b5d261c2 100644
--- a/tests/ui/coroutine/ref-upvar-not-send.stderr
+++ b/tests/ui/coroutine/ref-upvar-not-send.stderr
@@ -10,7 +10,7 @@ LL | |         let _x = x;
 LL | |     });
    | |_____^ coroutine is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:15:30: 15:37}: Send`
+   = help: the trait `Sync` is not implemented for `*mut ()`
 note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
   --> $DIR/ref-upvar-not-send.rs:19:18
    |
@@ -34,7 +34,7 @@ LL | |         let _y = y;
 LL | |     });
    | |_____^ coroutine is not `Send`
    |
-   = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()`, which is required by `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}: Send`
+   = help: within `{coroutine@$DIR/ref-upvar-not-send.rs:23:30: 23:37}`, the trait `Send` is not implemented for `*mut ()`
 note: captured value is not `Send` because `&mut` references cannot be sent unless their referent is `Send`
   --> $DIR/ref-upvar-not-send.rs:27:18
    |
diff --git a/tests/ui/coroutine/resume-arg-outlives-2.rs b/tests/ui/coroutine/resume-arg-outlives-2.rs
new file mode 100644
index 00000000000..387b143ea27
--- /dev/null
+++ b/tests/ui/coroutine/resume-arg-outlives-2.rs
@@ -0,0 +1,34 @@
+// Regression test for 132104
+
+#![feature(coroutine_trait, coroutines)]
+
+use std::ops::Coroutine;
+use std::{thread, time};
+
+fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
+    let mut generator = Box::pin({
+        #[coroutine]
+        move |_ctx| {
+            let ctx: &'not_static str = yield;
+            yield;
+            dbg!(ctx);
+        }
+    });
+
+    // exploit:
+    generator.as_mut().resume("");
+    generator.as_mut().resume(s); // <- generator hoards it as `let ctx`.
+    //~^ ERROR borrowed data escapes outside of function
+    thread::spawn(move || {
+        thread::sleep(time::Duration::from_millis(200));
+        generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`.
+    })
+}
+
+fn main() {
+    let local = String::from("...");
+    let thread = demo(&local);
+    drop(local);
+    let _unrelated = String::from("UAF");
+    thread.join().unwrap();
+}
diff --git a/tests/ui/coroutine/resume-arg-outlives-2.stderr b/tests/ui/coroutine/resume-arg-outlives-2.stderr
new file mode 100644
index 00000000000..3d630d7e7e4
--- /dev/null
+++ b/tests/ui/coroutine/resume-arg-outlives-2.stderr
@@ -0,0 +1,17 @@
+error[E0521]: borrowed data escapes outside of function
+  --> $DIR/resume-arg-outlives-2.rs:20:5
+   |
+LL | fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
+   |         -----------  - `s` is a reference that is only valid in the function body
+   |         |
+   |         lifetime `'not_static` defined here
+...
+LL |     generator.as_mut().resume(s); // <- generator hoards it as `let ctx`.
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     `s` escapes the function body here
+   |     argument requires that `'not_static` must outlive `'static`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/tests/ui/coroutine/resume-arg-outlives.rs b/tests/ui/coroutine/resume-arg-outlives.rs
new file mode 100644
index 00000000000..258be28e063
--- /dev/null
+++ b/tests/ui/coroutine/resume-arg-outlives.rs
@@ -0,0 +1,27 @@
+// Regression test for 132104
+
+#![feature(coroutine_trait, coroutines)]
+
+use std::ops::Coroutine;
+use std::pin::Pin;
+
+fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> {
+    let mut generator = Box::pin({
+        #[coroutine]
+        move |ctx: &'not_static str| {
+            yield;
+            dbg!(ctx);
+        }
+    });
+    generator.as_mut().resume(s);
+    generator
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    let local = String::from("...");
+    let mut coro = demo(&local);
+    drop(local);
+    let _unrelated = String::from("UAF");
+    coro.as_mut().resume("");
+}
diff --git a/tests/ui/coroutine/resume-arg-outlives.stderr b/tests/ui/coroutine/resume-arg-outlives.stderr
new file mode 100644
index 00000000000..2a6337b4945
--- /dev/null
+++ b/tests/ui/coroutine/resume-arg-outlives.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/resume-arg-outlives.rs:17:5
+   |
+LL | fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> {
+   |         ----------- lifetime `'not_static` defined here
+...
+LL |     generator
+   |     ^^^^^^^^^ returning this value requires that `'not_static` must outlive `'static`
+   |
+help: consider changing `impl Coroutine<&'not_static str> + 'static`'s explicit `'static` bound to the lifetime of argument `s`
+   |
+LL | fn demo<'not_static>(s: &'not_static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'not_static>> {
+   |                                                                                         ~~~~~~~~~~~
+help: alternatively, add an explicit `'static` bound to this reference
+   |
+LL | fn demo<'not_static>(s: &'static str) -> Pin<Box<impl Coroutine<&'not_static str> + 'static>> {
+   |                         ~~~~~~~~~~~~
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/coroutine/unresolved-ct-var.stderr b/tests/ui/coroutine/unresolved-ct-var.stderr
index 8b87bac05ac..da2ec272f9f 100644
--- a/tests/ui/coroutine/unresolved-ct-var.stderr
+++ b/tests/ui/coroutine/unresolved-ct-var.stderr
@@ -8,7 +8,7 @@ LL |         let s = std::array::from_fn(|_| ()).await;
    |                 |                          help: remove the `.await`
    |                 this call returns `[(); _]`
    |
-   = help: the trait `Future` is not implemented for `[(); _]`, which is required by `[(); _]: IntoFuture`
+   = help: the trait `Future` is not implemented for `[(); _]`
    = note: [(); _] must be a future or must implement `IntoFuture` to be awaited
    = note: required for `[(); _]` to implement `IntoFuture`
 
diff --git a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr
index 921e8d5d47a..b288e581d88 100644
--- a/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr
+++ b/tests/ui/coroutine/yield-outside-coroutine-issue-78653.stderr
@@ -21,7 +21,7 @@ error[E0277]: `{integer}` is not an iterator
 LL |     yield || for i in 0 { }
    |                       ^ `{integer}` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `{integer}`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `{integer}` to implement `IntoIterator`
 
diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr
index 1c79a603503..2f64d23b8d2 100644
--- a/tests/ui/delegation/unsupported.stderr
+++ b/tests/ui/delegation/unsupported.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0391]: cycle detected when computing type of `opaque::<impl at $DIR/unsupported.rs:26:5: 26:24>::{synthetic#0}`
   --> $DIR/unsupported.rs:27:25
    |
@@ -89,7 +84,7 @@ LL |     reuse Trait::foo;
    |
    = note: cannot satisfy `_: effects::Trait`
 
-error: aborting due to 5 previous errors; 2 warnings emitted
+error: aborting due to 4 previous errors; 2 warnings emitted
 
 Some errors have detailed explanations: E0283, E0391.
 For more information about an error, try `rustc --explain E0283`.
diff --git a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr
index b10805ac8f0..3f6c39bf939 100644
--- a/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr
+++ b/tests/ui/derives/derives-span-Debug-enum-struct-variant.stderr
@@ -7,7 +7,7 @@ LL | #[derive(Debug)]
 LL |      x: Error
    |      ^^^^^^^^ `Error` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug`
+   = help: the trait `Debug` is not implemented for `Error`
    = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `Error` with `#[derive(Debug)]`
diff --git a/tests/ui/derives/derives-span-Debug-enum.stderr b/tests/ui/derives/derives-span-Debug-enum.stderr
index 03297443901..eaeffaeb849 100644
--- a/tests/ui/derives/derives-span-Debug-enum.stderr
+++ b/tests/ui/derives/derives-span-Debug-enum.stderr
@@ -7,7 +7,7 @@ LL | #[derive(Debug)]
 LL |      Error
    |      ^^^^^ `Error` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug`
+   = help: the trait `Debug` is not implemented for `Error`
    = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `Error` with `#[derive(Debug)]`
diff --git a/tests/ui/derives/derives-span-Debug-struct.stderr b/tests/ui/derives/derives-span-Debug-struct.stderr
index 369c0b56ac4..4a725e260de 100644
--- a/tests/ui/derives/derives-span-Debug-struct.stderr
+++ b/tests/ui/derives/derives-span-Debug-struct.stderr
@@ -7,7 +7,7 @@ LL | struct Struct {
 LL |     x: Error
    |     ^^^^^^^^ `Error` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug`
+   = help: the trait `Debug` is not implemented for `Error`
    = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `Error` with `#[derive(Debug)]`
diff --git a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr
index abfef9ef354..2f816e1c85b 100644
--- a/tests/ui/derives/derives-span-Debug-tuple-struct.stderr
+++ b/tests/ui/derives/derives-span-Debug-tuple-struct.stderr
@@ -7,7 +7,7 @@ LL | struct Struct(
 LL |     Error
    |     ^^^^^ `Error` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `Error`, which is required by `&Error: Debug`
+   = help: the trait `Debug` is not implemented for `Error`
    = note: add `#[derive(Debug)]` to `Error` or manually `impl Debug for Error`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `Error` with `#[derive(Debug)]`
diff --git a/tests/ui/deriving/auxiliary/another-proc-macro.rs b/tests/ui/deriving/auxiliary/another-proc-macro.rs
index a05175c9de9..c992cde4066 100644
--- a/tests/ui/deriving/auxiliary/another-proc-macro.rs
+++ b/tests/ui/deriving/auxiliary/another-proc-macro.rs
@@ -6,7 +6,7 @@
 
 extern crate proc_macro;
 
-use proc_macro::{quote, TokenStream};
+use proc_macro::{TokenStream, quote};
 
 #[proc_macro_derive(AnotherMacro, attributes(pointee))]
 pub fn derive(_input: TokenStream) -> TokenStream {
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs
index 41c95f63b13..6c473aefc5b 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.rs
+++ b/tests/ui/deriving/built-in-proc-macro-scope.rs
@@ -2,14 +2,14 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
 #[macro_use]
 extern crate another_proc_macro;
 
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: ?Sized> {
     data: &'a mut T,
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
index c649b7a9a57..07767dc229f 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.stdout
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -4,7 +4,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
@@ -13,7 +13,7 @@ extern crate std;
 #[macro_use]
 extern crate another_proc_macro;
 
-use another_proc_macro::{pointee, AnotherMacro};
+use another_proc_macro::{AnotherMacro, pointee};
 
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: ?Sized> {
diff --git a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
index 4cae1b32896..a1aabf1cb52 100644
--- a/tests/ui/deriving/smart-pointer-bounds-issue-127647.rs
+++ b/tests/ui/deriving/coerce-pointee-bounds-issue-127647.rs
@@ -1,8 +1,8 @@
 //@ check-pass
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr<'a, #[pointee] T: OnDrop + ?Sized, X> {
     data: &'a mut T,
@@ -13,7 +13,7 @@ pub trait OnDrop {
     fn on_drop(&mut self);
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr2<'a, #[pointee] T: ?Sized, X>
 where
@@ -25,7 +25,7 @@ where
 
 pub trait MyTrait<T: ?Sized> {}
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr3<'a, #[pointee] T: ?Sized, X>
 where
@@ -35,14 +35,14 @@ where
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr4<'a, #[pointee] T: MyTrait<T> + ?Sized, X> {
     data: &'a mut T,
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr5<'a, #[pointee] T: ?Sized, X>
 where
@@ -56,7 +56,7 @@ where
 pub struct Ptr5Companion<T: ?Sized>(core::marker::PhantomData<T>);
 pub struct Ptr5Companion2;
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize = 0> {
     data: &'a mut T,
@@ -65,7 +65,7 @@ pub struct Ptr6<'a, #[pointee] T: ?Sized, X: MyTrait<T> = (), const PARAM: usize
 
 // a reduced example from https://lore.kernel.org/all/20240402-linked-list-v1-1-b1c59ba7ae3b@google.com/
 #[repr(transparent)]
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 pub struct ListArc<#[pointee] T, const ID: u64 = 0>
 where
     T: ListArcSafe<ID> + ?Sized,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
index e48ad3dd4bc..94be7031fb7 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
@@ -1,17 +1,17 @@
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
-use std::marker::SmartPointer;
+#![feature(derive_coerce_pointee)]
+use std::marker::CoercePointee;
 
 pub trait MyTrait<T: ?Sized> {}
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
 
-#[derive(core::marker::SmartPointer)]
+#[derive(core::marker::CoercePointee)]
 #[repr(transparent)]
 pub struct MyPointer2<'a, Y, Z: MyTrait<T>, #[pointee] T: ?Sized + MyTrait<T>, X: MyTrait<T> = ()>
 where
@@ -21,7 +21,7 @@ where
     x: core::marker::PhantomData<X>,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointerWithoutPointee<'a, T: ?Sized> {
     ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
index 68ef17f2b05..d6eaca5cba1 100644
--- a/tests/ui/deriving/deriving-smart-pointer-expanded.stdout
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
@@ -2,12 +2,12 @@
 #![no_std]
 //@ check-pass
 //@ compile-flags: -Zunpretty=expanded
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
 
 pub trait MyTrait<T: ?Sized> {}
 
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
index 41d3039236f..deef35cdf70 100644
--- a/tests/ui/deriving/deriving-smart-pointer-neg.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
@@ -1,115 +1,131 @@
-#![feature(derive_smart_pointer, arbitrary_self_types)]
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
 
 extern crate core;
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
 
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
 enum NotStruct<'a, T: ?Sized> {
     Variant(&'a T),
 }
 
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
 #[repr(transparent)]
 struct NoField<'a, #[pointee] T: ?Sized> {}
 //~^ ERROR: lifetime parameter `'a` is never used
 //~| ERROR: type parameter `T` is never used
 
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with at least one field
 #[repr(transparent)]
 struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
 //~^ ERROR: lifetime parameter `'a` is never used
 //~| ERROR: type parameter `T` is never used
 
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
 #[repr(transparent)]
 struct NoGeneric<'a>(&'a u8);
 
-#[derive(SmartPointer)]
-//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
+#[derive(CoercePointee)]
+//~^ ERROR: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
 #[repr(transparent)]
 struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
     a: (&'a T1, &'a T2),
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
-//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
+//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
 
-#[derive(SmartPointer)]
-//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
+#[derive(CoercePointee)]
+//~^ ERROR: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
 struct NotTransparent<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct NoMaybeSized<'a, #[pointee] T> {
-    //~^ ERROR: `derive(SmartPointer)` requires T to be marked `?Sized`
+    //~^ ERROR: `derive(CoercePointee)` requires T to be marked `?Sized`
     ptr: &'a T,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct PointeeOnField<'a, #[pointee] T: ?Sized> {
     #[pointee]
     //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-    ptr: &'a T
+    ptr: &'a T,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
-struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+struct PointeeInTypeConstBlock<
+    'a,
+    T: ?Sized = [u32; const {
+                    struct UhOh<#[pointee] T>(T);
+                    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+                    10
+                }],
+> {
     ptr: &'a T,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct PointeeInConstConstBlock<
     'a,
     T: ?Sized,
-    const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
-{
+    const V: u32 = {
+        struct UhOh<#[pointee] T>(T);
+        //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+        10
+    },
+> {
     ptr: &'a T,
 }
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
-    ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
-    //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+    ptr: PointeeInConstConstBlock<
+        'a,
+        T,
+        {
+            struct UhOh<#[pointee] T>(T);
+            //~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
+            0
+        },
+    >,
 }
 
 // However, reordering attributes should work nevertheless.
 #[repr(transparent)]
-#[derive(SmartPointer)]
-struct ThisIsAPossibleSmartPointer<'a, #[pointee] T: ?Sized> {
+#[derive(CoercePointee)]
+struct ThisIsAPossibleCoercePointee<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
 
 // Also, these paths to Sized should work
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct StdSized<'a, #[pointee] T: ?std::marker::Sized> {
     ptr: &'a T,
 }
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct CoreSized<'a, #[pointee] T: ?core::marker::Sized> {
     ptr: &'a T,
 }
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct GlobalStdSized<'a, #[pointee] T: ?::std::marker::Sized> {
     ptr: &'a T,
 }
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct GlobalCoreSized<'a, #[pointee] T: ?::core::marker::Sized> {
     ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
new file mode 100644
index 00000000000..e590d636d0e
--- /dev/null
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
@@ -0,0 +1,119 @@
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-coerce-pointee-neg.rs:6:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-coerce-pointee-neg.rs:12:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s with at least one field
+  --> $DIR/deriving-coerce-pointee-neg.rs:19:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `CoercePointee` can only be derived on `struct`s that are generic over at least one type
+  --> $DIR/deriving-coerce-pointee-neg.rs:26:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: exactly one generic type parameter must be marked as #[pointee] to derive CoercePointee traits
+  --> $DIR/deriving-coerce-pointee-neg.rs:31:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: only one type parameter can be marked as `#[pointee]` when deriving CoercePointee traits
+  --> $DIR/deriving-coerce-pointee-neg.rs:40:39
+   |
+LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
+   |                                       ^                     ^
+
+error: `CoercePointee` can only be derived on `struct`s with `#[repr(transparent)]`
+  --> $DIR/deriving-coerce-pointee-neg.rs:43:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `derive(CoercePointee)` requires T to be marked `?Sized`
+  --> $DIR/deriving-coerce-pointee-neg.rs:51:36
+   |
+LL | struct NoMaybeSized<'a, #[pointee] T> {
+   |                                    ^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:59:5
+   |
+LL |     #[pointee]
+   |     ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:69:33
+   |
+LL |                     struct UhOh<#[pointee] T>(T);
+   |                                 ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:83:21
+   |
+LL |         struct UhOh<#[pointee] T>(T);
+   |                     ^^^^^^^^^^
+
+error: the `#[pointee]` attribute may only be used on generic parameters
+  --> $DIR/deriving-coerce-pointee-neg.rs:98:25
+   |
+LL |             struct UhOh<#[pointee] T>(T);
+   |                         ^^^^^^^^^^
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:15:16
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:15:31
+   |
+LL | struct NoField<'a, #[pointee] T: ?Sized> {}
+   |                               ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:22:20
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                    ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/deriving-coerce-pointee-neg.rs:22:35
+   |
+LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
+   |                                   ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 16 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-coerce-pointee.rs
index d34a502da68..26762e4d0fa 100644
--- a/tests/ui/deriving/deriving-smart-pointer.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee.rs
@@ -1,9 +1,9 @@
 //@ run-pass
-#![feature(derive_smart_pointer, arbitrary_self_types)]
+#![feature(derive_coerce_pointee, arbitrary_self_types)]
 
-use std::marker::SmartPointer;
+use std::marker::CoercePointee;
 
-#[derive(SmartPointer)]
+#[derive(CoercePointee)]
 #[repr(transparent)]
 struct MyPointer<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr
deleted file mode 100644
index 9ab117698c7..00000000000
--- a/tests/ui/deriving/deriving-smart-pointer-neg.stderr
+++ /dev/null
@@ -1,119 +0,0 @@
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-  --> $DIR/deriving-smart-pointer-neg.rs:6:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
-  --> $DIR/deriving-smart-pointer-neg.rs:12:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s with at least one field
-  --> $DIR/deriving-smart-pointer-neg.rs:19:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
-  --> $DIR/deriving-smart-pointer-neg.rs:26:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: exactly one generic type parameter must be marked as #[pointee] to derive SmartPointer traits
-  --> $DIR/deriving-smart-pointer-neg.rs:31:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
-  --> $DIR/deriving-smart-pointer-neg.rs:40:39
-   |
-LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
-   |                                       ^                     ^
-
-error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
-  --> $DIR/deriving-smart-pointer-neg.rs:43:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `derive(SmartPointer)` requires T to be marked `?Sized`
-  --> $DIR/deriving-smart-pointer-neg.rs:51:36
-   |
-LL | struct NoMaybeSized<'a, #[pointee] T> {
-   |                                    ^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:59:5
-   |
-LL |     #[pointee]
-   |     ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:66:74
-   |
-LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
-   |                                                                          ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:76:34
-   |
-LL |     const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
-   |                                  ^^^^^^^^^^
-
-error: the `#[pointee]` attribute may only be used on generic parameters
-  --> $DIR/deriving-smart-pointer-neg.rs:85:56
-   |
-LL |     ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
-   |                                                        ^^^^^^^^^^
-
-error[E0392]: lifetime parameter `'a` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:15:16
-   |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
-   |                ^^ unused lifetime parameter
-   |
-   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:15:31
-   |
-LL | struct NoField<'a, #[pointee] T: ?Sized> {}
-   |                               ^ unused type parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: lifetime parameter `'a` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:22:20
-   |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-   |                    ^^ unused lifetime parameter
-   |
-   = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
-
-error[E0392]: type parameter `T` is never used
-  --> $DIR/deriving-smart-pointer-neg.rs:22:35
-   |
-LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
-   |                                   ^ unused type parameter
-   |
-   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-
-error: aborting due to 16 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/deriving/issue-103157.stderr b/tests/ui/deriving/issue-103157.stderr
index 612a7aff225..9754b0289c0 100644
--- a/tests/ui/deriving/issue-103157.stderr
+++ b/tests/ui/deriving/issue-103157.stderr
@@ -5,7 +5,7 @@ LL | #[derive(PartialEq, Eq)]
    |                     -- in this derive macro expansion
 ...
 LL |     Float(Option<f64>),
-   |           ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`, which is required by `Option<f64>: Eq`
+   |           ^^^^^^^^^^^ the trait `Eq` is not implemented for `f64`
    |
    = help: the following other types implement trait `Eq`:
              i128
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs
index 489665ebeb5..80a0d068ce7 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.rs
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs
@@ -1,5 +1,5 @@
 // This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
 // `#[pointee]`.
 // The scoping rule should allow the use of the said two attributes when external proc-macros
 // are in scope.
@@ -8,7 +8,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 
 #[macro_use]
 extern crate another_proc_macro;
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
index f314f6efbe2..03128c6c957 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -1,7 +1,7 @@
 #![feature(prelude_import)]
 #![no_std]
 // This test certify that we can mix attribute macros from Rust and external proc-macros.
-// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(SmartPointer)]` uses
+// For instance, `#[derive(Default)]` uses `#[default]` and `#[derive(CoercePointee)]` uses
 // `#[pointee]`.
 // The scoping rule should allow the use of the said two attributes when external proc-macros
 // are in scope.
@@ -10,7 +10,7 @@
 //@ aux-build: another-proc-macro.rs
 //@ compile-flags: -Zunpretty=expanded
 
-#![feature(derive_smart_pointer)]
+#![feature(derive_coerce_pointee)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index 29b68d666fc..7a999c7c330 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -4,8 +4,8 @@
 //@ [edition2021] edition: 2021
 //@ [edition2024] compile-flags: -Z unstable-options
 //@ [edition2024] edition: 2024
+
 #![feature(let_chains)]
-#![cfg_attr(edition2024, feature(if_let_rescope))]
 
 use std::cell::RefCell;
 use std::convert::TryInto;
diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs
index ae9f381820e..cea84bbaa2b 100644
--- a/tests/ui/drop/drop_order_if_let_rescope.rs
+++ b/tests/ui/drop/drop_order_if_let_rescope.rs
@@ -3,7 +3,6 @@
 //@ compile-flags: -Z validate-mir -Zunstable-options
 
 #![feature(let_chains)]
-#![feature(if_let_rescope)]
 
 use std::cell::RefCell;
 use std::convert::TryInto;
diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
index 2476f7cf258..e055c20d777 100644
--- a/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
+++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.rs
@@ -1,7 +1,6 @@
 //@ edition: 2024
 //@ compile-flags: -Z validate-mir -Zunstable-options
 
-#![feature(if_let_rescope)]
 #![deny(if_let_rescope)]
 
 struct Droppy;
diff --git a/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr
index 0c6f1ea28d2..3c87e196af6 100644
--- a/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr
+++ b/tests/ui/drop/if-let-rescope-borrowck-suggestions.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:39
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:21:39
    |
 LL |     do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 });
    |                                       ^^^^^^                   - temporary value is freed at the end of this statement
@@ -7,7 +7,7 @@ LL |     do_something(if let Some(value) = Droppy.get_ref() { value } else { &0
    |                                       creates a temporary value which is freed while still in use
    |
 note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:22:64
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:21:64
    |
 LL |     do_something(if let Some(value) = Droppy.get_ref() { value } else { &0 });
    |                                                                ^
@@ -22,7 +22,7 @@ LL |     do_something({ match Droppy.get_ref()  { Some(value) => { value } _ =>
    |                  ~~~~~~~                   ++++++++++++++++           ~~~~       ++
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:24:39
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:23:39
    |
 LL |     do_something(if let Some(value) = Droppy.get_ref() {
    |                                       ^^^^^^ creates a temporary value which is freed while still in use
@@ -31,7 +31,7 @@ LL |     } else if let Some(value) = Droppy.get_ref() {
    |     - temporary value is freed at the end of this statement
    |
 note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:5
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:26:5
    |
 LL |     } else if let Some(value) = Droppy.get_ref() {
    |     ^
@@ -53,7 +53,7 @@ LL ~     }}});
    |
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:27:33
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:26:33
    |
 LL |     } else if let Some(value) = Droppy.get_ref() {
    |                                 ^^^^^^ creates a temporary value which is freed while still in use
@@ -62,7 +62,7 @@ LL |     } else {
    |     - temporary value is freed at the end of this statement
    |
 note: lifetimes for temporaries generated in `if let`s have been shortened in Edition 2024 so that they are dropped here instead
-  --> $DIR/if-let-rescope-borrowck-suggestions.rs:30:5
+  --> $DIR/if-let-rescope-borrowck-suggestions.rs:29:5
    |
 LL |     } else {
    |     ^
diff --git a/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
index 48b7f3e11a6..48b7f3e11a6 100644
--- a/tests/ui/drop/lint-if-let-rescope-gated.with_feature_gate.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
diff --git a/tests/ui/drop/lint-if-let-rescope-gated.rs b/tests/ui/drop/lint-if-let-rescope-gated.rs
index cef5de5a8fe..ba0246573b4 100644
--- a/tests/ui/drop/lint-if-let-rescope-gated.rs
+++ b/tests/ui/drop/lint-if-let-rescope-gated.rs
@@ -1,13 +1,13 @@
 // This test checks that the lint `if_let_rescope` only actions
-// when the feature gate is enabled.
-// Edition 2021 is used here because the lint should work especially
-// when edition migration towards 2024 is run.
+// when Edition 2021 or prior is targeted here because the lint should work especially
+// when edition migration towards 2024 is executed.
 
-//@ revisions: with_feature_gate without_feature_gate
-//@ [without_feature_gate] check-pass
-//@ edition: 2021
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ [edition2024] compile-flags: -Zunstable-options
+//@ [edition2024] check-pass
 
-#![cfg_attr(with_feature_gate, feature(if_let_rescope))]
 #![deny(if_let_rescope)]
 #![allow(irrefutable_let_patterns)]
 
@@ -25,10 +25,10 @@ impl Droppy {
 
 fn main() {
     if let Some(_value) = Droppy.get() {
-        //[with_feature_gate]~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
-        //[with_feature_gate]~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
-        //[with_feature_gate]~| WARN: this changes meaning in Rust 2024
+        //[edition2021]~^ ERROR: `if let` assigns a shorter lifetime since Edition 2024
+        //[edition2021]~| HELP: a `match` with a single arm can preserve the drop order up to Edition 2021
+        //[edition2021]~| WARN: this changes meaning in Rust 2024
     } else {
-        //[with_feature_gate]~^ HELP: the value is now dropped here in Edition 2024
+        //[edition2021]~^ HELP: the value is now dropped here in Edition 2024
     }
 }
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.rs b/tests/ui/drop/lint-if-let-rescope-with-macro.rs
index 282b3320d30..e7aeb81f4d1 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.rs
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.rs
@@ -4,7 +4,6 @@
 //@ edition:2021
 //@ compile-flags: -Z unstable-options
 
-#![feature(if_let_rescope)]
 #![deny(if_let_rescope)]
 #![allow(irrefutable_let_patterns)]
 
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
index 5fd0c61d17a..de6cf6e8500 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
@@ -1,5 +1,5 @@
 error: `if let` assigns a shorter lifetime since Edition 2024
-  --> $DIR/lint-if-let-rescope-with-macro.rs:13:12
+  --> $DIR/lint-if-let-rescope-with-macro.rs:12:12
    |
 LL |           if let $p = $e { $($conseq)* } else { $($alt)* }
    |              ^^^
@@ -16,7 +16,7 @@ LL | |     };
    = warning: this changes meaning in Rust 2024
    = note: for more information, see issue #124085 <https://github.com/rust-lang/rust/issues/124085>
 help: the value is now dropped here in Edition 2024
-  --> $DIR/lint-if-let-rescope-with-macro.rs:13:38
+  --> $DIR/lint-if-let-rescope-with-macro.rs:12:38
    |
 LL |           if let $p = $e { $($conseq)* } else { $($alt)* }
    |                                        ^
@@ -29,7 +29,7 @@ LL | |         {}
 LL | |     };
    | |_____- in this macro invocation
 note: the lint level is defined here
-  --> $DIR/lint-if-let-rescope-with-macro.rs:8:9
+  --> $DIR/lint-if-let-rescope-with-macro.rs:7:9
    |
 LL | #![deny(if_let_rescope)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/drop/lint-if-let-rescope.fixed b/tests/ui/drop/lint-if-let-rescope.fixed
index 199068d0fd2..fec2e3b2ae7 100644
--- a/tests/ui/drop/lint-if-let-rescope.fixed
+++ b/tests/ui/drop/lint-if-let-rescope.fixed
@@ -1,7 +1,7 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope, stmt_expr_attributes)]
+#![feature(stmt_expr_attributes)]
 #![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
diff --git a/tests/ui/drop/lint-if-let-rescope.rs b/tests/ui/drop/lint-if-let-rescope.rs
index 4c043c0266c..ee184695b97 100644
--- a/tests/ui/drop/lint-if-let-rescope.rs
+++ b/tests/ui/drop/lint-if-let-rescope.rs
@@ -1,7 +1,7 @@
 //@ run-rustfix
 
 #![deny(if_let_rescope)]
-#![feature(if_let_rescope, stmt_expr_attributes)]
+#![feature(stmt_expr_attributes)]
 #![allow(irrefutable_let_patterns, unused_parens)]
 
 fn droppy() -> Droppy {
diff --git a/tests/ui/dropck/const_drop_is_valid.stderr b/tests/ui/dropck/const_drop_is_valid.stderr
index f15b7ba946d..2383a6668a8 100644
--- a/tests/ui/dropck/const_drop_is_valid.stderr
+++ b/tests/ui/dropck/const_drop_is_valid.stderr
@@ -17,11 +17,6 @@ LL | #![feature(effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `Drop` which is not marked with `#[const_trait]`
   --> $DIR/const_drop_is_valid.rs:6:12
    |
@@ -39,7 +34,7 @@ LL | impl const Drop for A {}
    |
    = help: implement the missing item: `fn drop(&mut self) { todo!() }`
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0046, E0658.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/dst/dst-bad-deep-2.stderr b/tests/ui/dst/dst-bad-deep-2.stderr
index 554e81bee10..c7e9854340f 100644
--- a/tests/ui/dst/dst-bad-deep-2.stderr
+++ b/tests/ui/dst/dst-bad-deep-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati
 LL |     let h: &(([isize],),) = &(*g,);
    |                              ^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]`, which is required by `(([isize],),): Sized`
+   = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]`
    = note: required because it appears within the type `([isize],)`
    = note: required because it appears within the type `(([isize],),)`
    = note: tuples must have a statically known size to be initialized
diff --git a/tests/ui/dst/dst-bad-deep.stderr b/tests/ui/dst/dst-bad-deep.stderr
index 4f180e593f8..1b0f9738ab0 100644
--- a/tests/ui/dst/dst-bad-deep.stderr
+++ b/tests/ui/dst/dst-bad-deep.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati
 LL |     let h: &Fat<Fat<[isize]>> = &Fat { ptr: *g };
    |                                  ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Fat<Fat<[isize]>>`, the trait `Sized` is not implemented for `[isize]`, which is required by `Fat<Fat<[isize]>>: Sized`
+   = help: within `Fat<Fat<[isize]>>`, the trait `Sized` is not implemented for `[isize]`
 note: required because it appears within the type `Fat<[isize]>`
   --> $DIR/dst-bad-deep.rs:6:8
    |
diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
index 07104bdf217..4751d280467 100644
--- a/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.rs
@@ -13,8 +13,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // OK
diff --git a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
index 39944622d07..2519a9fded2 100644
--- a/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2015-2015-parsing.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:16:31
    |
 LL |     r#async = consumes_async!(r#async);
@@ -10,7 +10,7 @@ note: while trying to match `async`
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected `async`
   --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
index 3c294f95cd2..4404ea26fb3 100644
--- a/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.rs
@@ -13,8 +13,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // OK
diff --git a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
index fa83908e666..0c0e5738415 100644
--- a/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2015-2018-parsing.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:16:31
    |
 LL |     r#async = consumes_async!(r#async);
@@ -10,7 +10,7 @@ note: while trying to match `async`
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected `async`
   --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
index 59184543274..c346be50856 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.rs
@@ -17,8 +17,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 42db75f6659..aed5837abea 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier
 LL |     module::r#async();
    |             ++
 
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:20:31
    |
 LL |     r#async = consumes_async!(r#async);
    |                               ^^^^^^^ no rules expected this token in macro call
    |
-note: while trying to match `async`
+note: while trying to match keyword `async`
   --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6
    |
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected keyword `async`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
index 4975246fa94..b75b68b3feb 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.rs
@@ -24,8 +24,8 @@ pub fn check_async() {
     let mut r#async = 1; // OK
 
     r#async = consumes_async!(async); // OK
-    r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
-    r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
+    r#async = consumes_async!(r#async); //~ ERROR no rules expected `r#async`
+    r#async = consumes_async_raw!(async); //~ ERROR no rules expected keyword `async`
     r#async = consumes_async_raw!(r#async); // OK
 
     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index 4bbe1597233..6503e9cc73c 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -20,19 +20,19 @@ help: escape `async` to use it as an identifier
 LL |     module::r#async();
    |             ++
 
-error: no rules expected the token `r#async`
+error: no rules expected `r#async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:27:31
    |
 LL |     r#async = consumes_async!(r#async);
    |                               ^^^^^^^ no rules expected this token in macro call
    |
-note: while trying to match `async`
+note: while trying to match keyword `async`
   --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6
    |
 LL |     (async) => (1)
    |      ^^^^^
 
-error: no rules expected the token `async`
+error: no rules expected keyword `async`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:28:35
    |
 LL |     r#async = consumes_async_raw!(async);
diff --git a/tests/ui/error-codes/E0277-2.stderr b/tests/ui/error-codes/E0277-2.stderr
index f4e18e3bb53..9a262f75590 100644
--- a/tests/ui/error-codes/E0277-2.stderr
+++ b/tests/ui/error-codes/E0277-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: `*const u8` cannot be sent between threads safely
 LL |     is_send::<Foo>();
    |               ^^^ `*const u8` cannot be sent between threads safely
    |
-   = help: within `Foo`, the trait `Send` is not implemented for `*const u8`, which is required by `Foo: Send`
+   = help: within `Foo`, the trait `Send` is not implemented for `*const u8`
 note: required because it appears within the type `Baz`
   --> $DIR/E0277-2.rs:9:8
    |
diff --git a/tests/ui/error-codes/E0277.stderr b/tests/ui/error-codes/E0277.stderr
index 52ada36574e..a9ae8971df4 100644
--- a/tests/ui/error-codes/E0277.stderr
+++ b/tests/ui/error-codes/E0277.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL | fn f(p: Path) { }
    |         ^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized`
+   = help: within `Path`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `Path`
   --> $SRC_DIR/std/src/path.rs:LL:COL
    = help: unsized fn params are gated as an unstable feature
diff --git a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
index bd4e9348227..9228a047e87 100644
--- a/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
+++ b/tests/ui/errors/trait-bound-error-spans/blame-trait-error.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:53:46
    |
 LL |     want(Wrapper { value: Burrito { filling: q } });
-   |     ----                                     ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Burrito<Q>>: T1`
+   |     ----                                     ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -38,7 +38,7 @@ LL |     want(Some(()));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Iterator` is not implemented for `()`, which is required by `Option<()>: T1`
+   = help: the trait `Iterator` is not implemented for `()`
    = help: the trait `T1` is implemented for `Option<It>`
 note: required for `Option<()>` to implement `T1`
   --> $DIR/blame-trait-error.rs:21:20
@@ -109,7 +109,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:65:45
    |
 LL |     want(&ExampleTuple::ExampleTupleVariant(q));
-   |     ----                                    ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1`
+   |     ----                                    ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -134,7 +134,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:68:31
    |
 LL |     want(&ExampleTupleVariant(q));
-   |     ----                      ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1`
+   |     ----                      ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -159,7 +159,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:71:50
    |
 LL |     want(&ExampleOtherTuple::ExampleTupleVariant(q));
-   |     ----                                         ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1`
+   |     ----                                         ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -184,7 +184,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:74:44
    |
 LL |     want(&ExampleDifferentTupleVariantName(q));
-   |     ----                                   ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1`
+   |     ----                                   ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -209,7 +209,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:77:45
    |
 LL |     want(&ExampleYetAnotherTupleVariantName(q));
-   |     ----                                    ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleTuple<Q>: T1`
+   |     ----                                    ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -234,7 +234,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:80:56
    |
 LL |     want(&ExampleStruct::ExampleStructVariant { field: q });
-   |     ---- required by a bound introduced by this call   ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1`
+   |     ---- required by a bound introduced by this call   ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `ExampleStruct<Q>` to implement `T1`
   --> $DIR/blame-trait-error.rs:45:9
@@ -257,7 +257,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:83:41
    |
 LL |     want(&ExampleStructVariant { field: q });
-   |     ----                                ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1`
+   |     ----                                ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -282,7 +282,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:86:61
    |
 LL |     want(&ExampleOtherStruct::ExampleStructVariant { field: q });
-   |     ---- required by a bound introduced by this call        ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1`
+   |     ---- required by a bound introduced by this call        ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `ExampleStruct<Q>` to implement `T1`
   --> $DIR/blame-trait-error.rs:45:9
@@ -305,7 +305,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:89:54
    |
 LL |     want(&ExampleDifferentStructVariantName { field: q });
-   |     ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1`
+   |     ---- required by a bound introduced by this call ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `ExampleStruct<Q>` to implement `T1`
   --> $DIR/blame-trait-error.rs:45:9
@@ -328,7 +328,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:92:55
    |
 LL |     want(&ExampleYetAnotherStructVariantName { field: q });
-   |     ---- required by a bound introduced by this call  ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleStruct<Q>: T1`
+   |     ---- required by a bound introduced by this call  ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `ExampleStruct<Q>` to implement `T1`
   --> $DIR/blame-trait-error.rs:45:9
@@ -351,7 +351,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:95:38
    |
 LL |     want(&ExampleActuallyTupleStruct(q, 0));
-   |     ----                             ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct<Q>: T1`
+   |     ----                             ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -376,7 +376,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error.rs:98:43
    |
 LL |     want(&ExampleActuallyTupleStructOther(q, 0));
-   |     ----                                  ^ the trait `T3` is not implemented for `Q`, which is required by `&ExampleActuallyTupleStruct<Q>: T1`
+   |     ----                                  ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
index a2df6843f43..b6a24e12bcc 100644
--- a/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
+++ b/tests/ui/errors/traits/blame-trait-error-spans-on-exprs.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:81:60
    |
 LL |     want(Wrapper { value: Burrito { spicy: false, filling: q } });
-   |     ---- required by a bound introduced by this call       ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Burrito<Q>>: T1`
+   |     ---- required by a bound introduced by this call       ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `Burrito<Q>` to implement `T2`
   --> $DIR/blame-trait-error-spans-on-exprs.rs:22:13
@@ -32,7 +32,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:85:84
    |
 LL |     want(Wrapper { value: BurritoKinds::SmallBurrito { spicy: true, small_filling: q } });
-   |     ---- required by a bound introduced by this call                               ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<BurritoKinds<Q>>: T1`
+   |     ---- required by a bound introduced by this call                               ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `BurritoKinds<Q>` to implement `T2`
   --> $DIR/blame-trait-error-spans-on-exprs.rs:32:13
@@ -62,7 +62,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:89:39
    |
 LL |     want(Wrapper { value: Taco(false, q) });
-   |     ----                              ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<Taco<Q>>: T1`
+   |     ----                              ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -94,7 +94,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:93:53
    |
 LL |     want(Wrapper { value: TacoKinds::OneTaco(false, q) });
-   |     ----                                            ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<TacoKinds<Q>>: T1`
+   |     ----                                            ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -126,7 +126,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:97:74
    |
 LL |     want(Wrapper { value: GenericBurrito { spiciness: NotSpicy, filling: q } });
-   |     ---- required by a bound introduced by this call                     ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<GenericBurrito<NotSpicy, Q>>: T1`
+   |     ---- required by a bound introduced by this call                     ^ the trait `T3` is not implemented for `Q`
    |
 note: required for `GenericBurrito<NotSpicy, Q>` to implement `T2`
   --> $DIR/blame-trait-error-spans-on-exprs.rs:47:16
@@ -156,7 +156,7 @@ error[E0277]: the trait bound `Q: T2` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:101:14
    |
 LL |     want((3, q));
-   |     ----     ^ the trait `T2` is not implemented for `Q`, which is required by `({integer}, Q): T1`
+   |     ----     ^ the trait `T2` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -181,7 +181,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:105:31
    |
 LL |     want(Wrapper { value: (3, q) });
-   |     ----                      ^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<({integer}, Q)>: T1`
+   |     ----                      ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -213,7 +213,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:109:15
    |
 LL |     want(((3, q), 5));
-   |     ----      ^ the trait `T3` is not implemented for `Q`, which is required by `(({integer}, Q), {integer}): T1`
+   |     ----      ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -245,7 +245,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:112:49
    |
 LL |     want(DoubleWrapper { item: Wrapper { value: q } });
-   |     ----                                        ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper<Q>: T1`
+   |     ----                                        ^ the trait `T1` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -270,7 +270,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:115:88
    |
 LL |     want(DoubleWrapper { item: Wrapper { value: DoubleWrapper { item: Wrapper { value: q } } } });
-   |     ---- required by a bound introduced by this call                                   ^ the trait `T1` is not implemented for `Q`, which is required by `DoubleWrapper<DoubleWrapper<Q>>: T1`
+   |     ---- required by a bound introduced by this call                                   ^ the trait `T1` is not implemented for `Q`
    |
 note: required for `DoubleWrapper<Q>` to implement `T1`
   --> $DIR/blame-trait-error-spans-on-exprs.rs:72:13
@@ -295,7 +295,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:119:27
    |
 LL |     want(Wrapper { value: AliasBurrito { spiciness: q, filling: q } });
-   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`, which is required by `Wrapper<GenericBurrito<Q, Q>>: T1`
+   |     ----                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -327,7 +327,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:122:35
    |
 LL |     want(Two { a: Two { a: (), b: q }, b: () });
-   |     ----                          ^ the trait `T1` is not implemented for `Q`, which is required by `Two<Two<(), Q>, ()>: T1`
+   |     ----                          ^ the trait `T1` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
@@ -354,7 +354,7 @@ error[E0277]: the trait bound `Q: T1` is not satisfied
 LL |     want(
    |     ---- required by a bound introduced by this call
 LL |         Two { a: Two { a: (), b: Two { a: Two { a: (), b: q }, b: () } }, b: () },
-   |                                                           ^ the trait `T1` is not implemented for `Q`, which is required by `Two<Two<(), Two<Two<(), Q>, ()>>, ()>: T1`
+   |                                                           ^ the trait `T1` is not implemented for `Q`
    |
 note: required for `Two<Two<(), Q>, ()>` to implement `T1`
   --> $DIR/blame-trait-error-spans-on-exprs.rs:66:19
@@ -379,7 +379,7 @@ error[E0277]: the trait bound `Q: T3` is not satisfied
   --> $DIR/blame-trait-error-spans-on-exprs.rs:133:44
    |
 LL |     want(&Burrito { spicy: false, filling: q });
-   |     ----                                   ^ the trait `T3` is not implemented for `Q`, which is required by `&Burrito<Q>: T1`
+   |     ----                                   ^ the trait `T3` is not implemented for `Q`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr
index 7428e6a60b5..a587d4dda55 100644
--- a/tests/ui/extern/extern-types-unsized.stderr
+++ b/tests/ui/extern/extern-types-unsized.stderr
@@ -21,7 +21,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
 LL |     assert_sized::<Foo>();
    |                    ^^^ doesn't have a size known at compile-time
    |
-   = help: within `Foo`, the trait `Sized` is not implemented for `A`, which is required by `Foo: Sized`
+   = help: within `Foo`, the trait `Sized` is not implemented for `A`
 note: required because it appears within the type `Foo`
   --> $DIR/extern-types-unsized.rs:9:8
    |
@@ -43,7 +43,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
 LL |     assert_sized::<Bar<A>>();
    |                    ^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Bar<A>`, the trait `Sized` is not implemented for `A`, which is required by `Bar<A>: Sized`
+   = help: within `Bar<A>`, the trait `Sized` is not implemented for `A`
 note: required because it appears within the type `Bar<A>`
   --> $DIR/extern-types-unsized.rs:14:8
    |
@@ -65,7 +65,7 @@ error[E0277]: the size for values of type `A` cannot be known at compilation tim
 LL |     assert_sized::<Bar<Bar<A>>>();
    |                    ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Bar<Bar<A>>`, the trait `Sized` is not implemented for `A`, which is required by `Bar<Bar<A>>: Sized`
+   = help: within `Bar<Bar<A>>`, the trait `Sized` is not implemented for `A`
 note: required because it appears within the type `Bar<A>`
   --> $DIR/extern-types-unsized.rs:14:8
    |
diff --git a/tests/ui/fail-simple.rs b/tests/ui/fail-simple.rs
index cd81a5d0a0f..55e547ee72b 100644
--- a/tests/ui/fail-simple.rs
+++ b/tests/ui/fail-simple.rs
@@ -1,3 +1,3 @@
 fn main() {
-    panic!(@); //~ ERROR no rules expected the token `@`
+    panic!(@); //~ ERROR no rules expected `@`
 }
diff --git a/tests/ui/fail-simple.stderr b/tests/ui/fail-simple.stderr
index 39fec3e2517..50c350b3ef5 100644
--- a/tests/ui/fail-simple.stderr
+++ b/tests/ui/fail-simple.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `@`
+error: no rules expected `@`
   --> $DIR/fail-simple.rs:2:12
    |
 LL |     panic!(@);
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
new file mode 100644
index 00000000000..69bc70e8666
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.rs
@@ -0,0 +1,9 @@
+use std::marker::CoercePointee; //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+
+#[derive(CoercePointee)] //~ ERROR use of unstable library feature 'derive_coerce_pointee'
+#[repr(transparent)]
+struct MyPointer<'a, #[pointee] T: ?Sized> {
+    ptr: &'a T,
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
new file mode 100644
index 00000000000..0b52ceb782a
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-derive-coerce-pointee.stderr
@@ -0,0 +1,23 @@
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+  --> $DIR/feature-gate-derive-coerce-pointee.rs:3:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+   = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature 'derive_coerce_pointee'
+  --> $DIR/feature-gate-derive-coerce-pointee.rs:1:5
+   |
+LL | use std::marker::CoercePointee;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
+   = help: add `#![feature(derive_coerce_pointee)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
deleted file mode 100644
index 7b4764ee768..00000000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer'
-
-#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
-#[repr(transparent)]
-struct MyPointer<'a, #[pointee] T: ?Sized> {
-    ptr: &'a T,
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
deleted file mode 100644
index ea4d1271b7c..00000000000
--- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
-  --> $DIR/feature-gate-derive-smart-pointer.rs:3:10
-   |
-LL | #[derive(SmartPointer)]
-   |          ^^^^^^^^^^^^
-   |
-   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
-   = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature 'derive_smart_pointer'
-  --> $DIR/feature-gate-derive-smart-pointer.rs:1:5
-   |
-LL | use std::marker::SmartPointer;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #123430 <https://github.com/rust-lang/rust/issues/123430> for more information
-   = help: add `#![feature(derive_smart_pointer)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.rs b/tests/ui/feature-gates/feature-gate-if-let-rescope.rs
deleted file mode 100644
index bd1efd4fb7c..00000000000
--- a/tests/ui/feature-gates/feature-gate-if-let-rescope.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// This test shows the code that could have been accepted by enabling #![feature(if_let_rescope)]
-
-struct A;
-struct B<'a, T>(&'a mut T);
-
-impl A {
-    fn f(&mut self) -> Option<B<'_, Self>> {
-        Some(B(self))
-    }
-}
-
-impl<'a, T> Drop for B<'a, T> {
-    fn drop(&mut self) {
-        // this is needed to keep NLL's hands off and to ensure
-        // the inner mutable borrow stays alive
-    }
-}
-
-fn main() {
-    let mut a = A;
-    if let None = a.f().as_ref() {
-        unreachable!()
-    } else {
-        a.f().unwrap();
-        //~^ ERROR cannot borrow `a` as mutable more than once at a time
-    };
-}
diff --git a/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr b/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr
deleted file mode 100644
index ff1846ae0b1..00000000000
--- a/tests/ui/feature-gates/feature-gate-if-let-rescope.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error[E0499]: cannot borrow `a` as mutable more than once at a time
-  --> $DIR/feature-gate-if-let-rescope.rs:24:9
-   |
-LL |     if let None = a.f().as_ref() {
-   |                   -----
-   |                   |
-   |                   first mutable borrow occurs here
-   |                   a temporary with access to the first borrow is created here ...
-...
-LL |         a.f().unwrap();
-   |         ^ second mutable borrow occurs here
-LL |
-LL |     };
-   |      - ... and the first borrow might be used here, when that temporary is dropped and runs the destructor for type `Option<B<'_, A>>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0499`.
diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr
index 5cf34a897f4..ae8d50344d5 100644
--- a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr
+++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr
@@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation
 LL |     offset_of!(T, y);
    |     ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `S`, the trait `Sized` is not implemented for `[i32]`, which is required by `S: Sized`
+   = help: within `S`, the trait `Sized` is not implemented for `[i32]`
 note: required because it appears within the type `S`
   --> $DIR/feature-gate-offset-of-slice.rs:3:8
    |
diff --git a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr
index 0ee2d93fb26..7d9c5b81651 100644
--- a/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr
+++ b/tests/ui/feature-gates/feature-gate-trivial_bounds.stderr
@@ -120,7 +120,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at
 LL | fn unsized_local() where Dst<dyn A>: Sized {
    |                          ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)`, which is required by `Dst<(dyn A + 'static)>: Sized`
+   = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)`
 note: required because it appears within the type `Dst<(dyn A + 'static)>`
   --> $DIR/feature-gate-trivial_bounds.rs:48:8
    |
diff --git a/tests/ui/fmt/ifmt-unimpl.stderr b/tests/ui/fmt/ifmt-unimpl.stderr
index f83e7c87728..b8d4425a4a7 100644
--- a/tests/ui/fmt/ifmt-unimpl.stderr
+++ b/tests/ui/fmt/ifmt-unimpl.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `str: UpperHex` is not satisfied
   --> $DIR/ifmt-unimpl.rs:2:21
    |
 LL |     format!("{:X}", "3");
-   |              ----   ^^^ the trait `UpperHex` is not implemented for `str`, which is required by `&str: UpperHex`
+   |              ----   ^^^ the trait `UpperHex` is not implemented for `str`
    |              |
    |              required by a bound introduced by this call
    |
diff --git a/tests/ui/for/for-c-in-str.stderr b/tests/ui/for/for-c-in-str.stderr
index 2544df64629..475cf8c8874 100644
--- a/tests/ui/for/for-c-in-str.stderr
+++ b/tests/ui/for/for-c-in-str.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&str` is not an iterator
 LL |     for c in "asdf" {
    |              ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
    |
-   = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&str`
    = note: required for `&str` to implement `IntoIterator`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for/for-loop-bogosity.stderr
index 143e4a4efd1..194a2fa08ce 100644
--- a/tests/ui/for/for-loop-bogosity.stderr
+++ b/tests/ui/for/for-loop-bogosity.stderr
@@ -4,7 +4,7 @@ error[E0277]: `MyStruct` is not an iterator
 LL |     for x in bogus {
    |              ^^^^^ `MyStruct` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `MyStruct`, which is required by `MyStruct: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `MyStruct`
    = note: required for `MyStruct` to implement `IntoIterator`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/function-pointer/unsized-ret.stderr b/tests/ui/function-pointer/unsized-ret.stderr
index 81d603f4b20..66116273ff4 100644
--- a/tests/ui/function-pointer/unsized-ret.stderr
+++ b/tests/ui/function-pointer/unsized-ret.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL |     foo::<fn() -> str, _>(None, ());
    |           ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`, which is required by `fn() -> str: Fn<_>`
+   = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`
    = note: required because it appears within the type `fn() -> str`
 note: required by a bound in `foo`
   --> $DIR/unsized-ret.rs:5:11
@@ -18,7 +18,7 @@ error[E0277]: the size for values of type `(dyn std::fmt::Display + 'a)` cannot
 LL |     foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&(),));
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`, which is required by `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a): Fn<_>`
+   = help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
    = note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
 note: required by a bound in `foo`
   --> $DIR/unsized-ret.rs:5:11
diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr
index c5c4f2c4d23..8779bab593a 100644
--- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr
+++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.current.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied
   --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30
    |
 LL |     type Bar<T>: Baz<Self> = i32;
-   |                              ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`, which is required by `i32: Baz<Self>`
+   |                              ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`
    |
 note: required for `i32` to implement `Baz<Self>`
   --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23
diff --git a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
index c5c4f2c4d23..8779bab593a 100644
--- a/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
+++ b/tests/ui/generic-associated-types/assume-gat-normalization-for-nested-goals.next.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `<Self as Foo>::Bar<()>: Eq<i32>` is not satisfied
   --> $DIR/assume-gat-normalization-for-nested-goals.rs:9:30
    |
 LL |     type Bar<T>: Baz<Self> = i32;
-   |                              ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`, which is required by `i32: Baz<Self>`
+   |                              ^^^ the trait `Eq<i32>` is not implemented for `<Self as Foo>::Bar<()>`
    |
 note: required for `i32` to implement `Baz<Self>`
   --> $DIR/assume-gat-normalization-for-nested-goals.rs:16:23
diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr
index c3b119e2144..261070d1db4 100644
--- a/tests/ui/generic-associated-types/impl_bounds.stderr
+++ b/tests/ui/generic-associated-types/impl_bounds.stderr
@@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/impl_bounds.rs:18:33
    |
 LL |     type C = String where Self: Copy;
-   |                                 ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy<T>: Copy`
+   |                                 ^^^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `Fooy<T>` to implement `Copy`
   --> $DIR/impl_bounds.rs:10:10
@@ -50,7 +50,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/impl_bounds.rs:20:24
    |
 LL |     fn d() where Self: Copy {}
-   |                        ^^^^ the trait `Copy` is not implemented for `T`, which is required by `Fooy<T>: Copy`
+   |                        ^^^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `Fooy<T>` to implement `Copy`
   --> $DIR/impl_bounds.rs:10:10
diff --git a/tests/ui/generic-associated-types/issue-101020.stderr b/tests/ui/generic-associated-types/issue-101020.stderr
index 7faab4e5274..9c3753c2d18 100644
--- a/tests/ui/generic-associated-types/issue-101020.stderr
+++ b/tests/ui/generic-associated-types/issue-101020.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a mut (): Foo<&'a mut ()>` is not satis
   --> $DIR/issue-101020.rs:31:22
    |
 LL |     (&mut EmptyIter).consume(());
-   |                      ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`, which is required by `for<'a> &'a mut (): FuncInput<'a, &'a mut ()>`
+   |                      ^^^^^^^ the trait `for<'a> Foo<&'a mut ()>` is not implemented for `&'a mut ()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/issue-101020.rs:28:1
diff --git a/tests/ui/generic-associated-types/issue-74824.current.stderr b/tests/ui/generic-associated-types/issue-74824.current.stderr
index b06c7f127ac..231136612a0 100644
--- a/tests/ui/generic-associated-types/issue-74824.current.stderr
+++ b/tests/ui/generic-associated-types/issue-74824.current.stderr
@@ -14,7 +14,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/issue-74824.rs:10:26
    |
 LL |     type Copy<T>: Copy = Box<T>;
-   |                          ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `<Self as UnsafeCopy>::Copy<T>: Copy`
+   |                          ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Box<T>` to implement `Clone`
    = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
diff --git a/tests/ui/generic-associated-types/issue-74824.next.stderr b/tests/ui/generic-associated-types/issue-74824.next.stderr
index b06c7f127ac..231136612a0 100644
--- a/tests/ui/generic-associated-types/issue-74824.next.stderr
+++ b/tests/ui/generic-associated-types/issue-74824.next.stderr
@@ -14,7 +14,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/issue-74824.rs:10:26
    |
 LL |     type Copy<T>: Copy = Box<T>;
-   |                          ^^^^^^ the trait `Clone` is not implemented for `T`, which is required by `<Self as UnsafeCopy>::Copy<T>: Copy`
+   |                          ^^^^^^ the trait `Clone` is not implemented for `T`
    |
    = note: required for `Box<T>` to implement `Clone`
    = note: required for `<Self as UnsafeCopy>::Copy<T>` to implement `Copy`
diff --git a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
index 761fd9045a1..7fe803550bd 100644
--- a/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
   --> $DIR/issue-89118.rs:19:8
    |
 LL |     C: StackContext,
-   |        ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>`
+   |        ^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/issue-89118.rs:1:1
@@ -29,7 +29,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
   --> $DIR/issue-89118.rs:29:9
    |
 LL | impl<C> EthernetWorker<C> {}
-   |         ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>`
+   |         ^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/issue-89118.rs:1:1
@@ -56,7 +56,7 @@ error[E0277]: the trait bound `for<'a> &'a (): BufferMut` is not satisfied
   --> $DIR/issue-89118.rs:22:20
    |
 LL |     type Handler = Ctx<C::Dispatcher>;
-   |                    ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`, which is required by `for<'a> Ctx<()>: BufferUdpStateContext<&'a ()>`
+   |                    ^^^^^^^^^^^^^^^^^^ the trait `for<'a> BufferMut` is not implemented for `&'a ()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/issue-89118.rs:1:1
diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leak2.stderr
index 1fcde0372fc..52fa28145d6 100644
--- a/tests/ui/impl-trait/auto-trait-leak2.stderr
+++ b/tests/ui/impl-trait/auto-trait-leak2.stderr
@@ -9,7 +9,7 @@ LL |     send(before());
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `impl Fn(i32): Send`
+   = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
 note: required because it's used within this closure
   --> $DIR/auto-trait-leak2.rs:10:5
    |
@@ -37,7 +37,7 @@ LL |     send(after());
 LL | fn after() -> impl Fn(i32) {
    |               ------------ within this `impl Fn(i32)`
    |
-   = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`, which is required by `impl Fn(i32): Send`
+   = help: within `impl Fn(i32)`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
 note: required because it's used within this closure
   --> $DIR/auto-trait-leak2.rs:38:5
    |
diff --git a/tests/crashes/126850.rs b/tests/ui/impl-trait/closure-in-type.rs
index 0ddc24c8bb1..1e06e6e21fd 100644
--- a/tests/crashes/126850.rs
+++ b/tests/ui/impl-trait/closure-in-type.rs
@@ -1,4 +1,5 @@
-//@ known-bug: rust-lang/rust#126850
+//@ check-pass
+
 fn bug<T>() -> impl Iterator<
     Item = [(); {
                |found: &String| Some(false);
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
new file mode 100644
index 00000000000..f1c196a154d
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs
@@ -0,0 +1,20 @@
+//@ only-linux
+//@ compile-flags: --error-format=human --color=always
+//@ error-pattern: the trait bound
+
+trait Foo<T>: Bar<T> {}
+
+trait Bar<T> {}
+
+struct Struct;
+
+impl<T, K> Foo<K> for T where T: Bar<K>
+{}
+
+impl<'a> Bar<()> for Struct {}
+
+fn foo() -> impl Foo<i32> {
+    Struct
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
new file mode 100644
index 00000000000..a18fc11a1e3
--- /dev/null
+++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg
@@ -0,0 +1,62 @@
+<svg width="1104px" height="344px" xmlns="http://www.w3.org/2000/svg">
+  <style>
+    .fg { fill: #AAAAAA }
+    .bg { background: #000000 }
+    .fg-ansi256-009 { fill: #FF5555 }
+    .fg-ansi256-010 { fill: #55FF55 }
+    .fg-ansi256-012 { fill: #5555FF }
+    .fg-magenta { fill: #AA00AA }
+    .container {
+      padding: 0 10px;
+      line-height: 18px;
+    }
+    .bold { font-weight: bold; }
+    tspan {
+      font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+      white-space: pre;
+      line-height: 18px;
+    }
+  </style>
+
+  <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+  <text xml:space="preserve" class="container fg">
+    <tspan x="10px" y="28px"><tspan class="fg-ansi256-009 bold">error[E0277]</tspan><tspan class="bold">: the trait bound `Struct: Foo&lt;i32&gt;` is not satisfied</tspan>
+</tspan>
+    <tspan x="10px" y="46px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:16:13</tspan>
+</tspan>
+    <tspan x="10px" y="64px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> fn foo() -&gt; impl Foo&lt;i32&gt; {</tspan>
+</tspan>
+    <tspan x="10px" y="100px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>             </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar&lt;i32&gt;` is not implemented for `Struct`</tspan>
+</tspan>
+    <tspan x="10px" y="118px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="136px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: the trait `Bar&lt;()&gt;` </tspan><tspan class="fg-magenta bold">is</tspan><tspan> implemented for `Struct`</tspan>
+</tspan>
+    <tspan x="10px" y="154px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">= </tspan><tspan class="bold">help</tspan><tspan>: for that trait implementation, expected `</tspan><tspan class="fg-magenta bold">()</tspan><tspan>`, found `</tspan><tspan class="fg-magenta bold">i32</tspan><tspan>`</tspan>
+</tspan>
+    <tspan x="10px" y="172px"><tspan class="fg-ansi256-010 bold">note</tspan><tspan>: required for `Struct` to implement `Foo&lt;i32&gt;`</tspan>
+</tspan>
+    <tspan x="10px" y="190px"><tspan>  </tspan><tspan class="fg-ansi256-012 bold">--&gt; </tspan><tspan>$DIR/highlight-difference-between-expected-trait-and-found-trait.rs:11:12</tspan>
+</tspan>
+    <tspan x="10px" y="208px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan>
+</tspan>
+    <tspan x="10px" y="226px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> impl&lt;T, K&gt; Foo&lt;K&gt; for T where T: Bar&lt;K&gt;</tspan>
+</tspan>
+    <tspan x="10px" y="244px"><tspan>   </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan>            </tspan><tspan class="fg-ansi256-010 bold">^^^^^^</tspan><tspan>     </tspan><tspan class="fg-ansi256-010 bold">^</tspan><tspan>          </tspan><tspan class="fg-ansi256-012 bold">------</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">unsatisfied trait bound introduced here</tspan>
+</tspan>
+    <tspan x="10px" y="262px">
+</tspan>
+    <tspan x="10px" y="280px"><tspan class="fg-ansi256-009 bold">error</tspan><tspan class="bold">: aborting due to 1 previous error</tspan>
+</tspan>
+    <tspan x="10px" y="298px">
+</tspan>
+    <tspan x="10px" y="316px"><tspan class="bold">For more information about this error, try `rustc --explain E0277`.</tspan>
+</tspan>
+    <tspan x="10px" y="334px">
+</tspan>
+  </text>
+
+</svg>
diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index 9c546659564..8716088ccbd 100644
--- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -16,7 +16,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) }
    |             |
    |             doesn't have a size known at compile-time
    |
-   = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized`
+   = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
@@ -38,7 +38,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) }
    |             |
    |             doesn't have a size known at compile-time
    |
-   = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`, which is required by `(usize, (dyn Trait + 'static)): Sized`
+   = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)`
    = note: required because it appears within the type `(usize, (dyn Trait + 'static))`
    = note: the return type of a function must have a statically known size
 
diff --git a/tests/ui/impl-trait/impl_trait_projections.rs b/tests/ui/impl-trait/impl_trait_projections.rs
index 365ac85e2f6..2c277aee06d 100644
--- a/tests/ui/impl-trait/impl_trait_projections.rs
+++ b/tests/ui/impl-trait/impl_trait_projections.rs
@@ -10,30 +10,27 @@ fn path_parametrized_type_is_allowed() -> option::Option<impl Debug> {
 }
 
 fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_is_disallowed(mut x: impl Iterator)
     -> <impl Iterator as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     x.next().unwrap()
 }
 
 fn projection_with_named_trait_inside_path_is_disallowed()
     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
-//~| ERROR `impl Debug: Step` is not satisfied
+//~^ ERROR `impl Trait` is not allowed in paths
 {
-    //~^ ERROR `impl Debug: Step` is not satisfied
     (1i32..100).next().unwrap()
 }
 
 fn projection_from_impl_trait_inside_dyn_trait_is_disallowed()
     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 {
     panic!()
 }
diff --git a/tests/ui/impl-trait/impl_trait_projections.stderr b/tests/ui/impl-trait/impl_trait_projections.stderr
index d62e3ac4183..5e0b80fcd59 100644
--- a/tests/ui/impl-trait/impl_trait_projections.stderr
+++ b/tests/ui/impl-trait/impl_trait_projections.stderr
@@ -1,73 +1,35 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
   --> $DIR/impl_trait_projections.rs:12:51
    |
 LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
    |                                                   ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:19:9
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:18:9
    |
 LL |     -> <impl Iterator as Iterator>::Item
    |         ^^^^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:26:27
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:25:27
    |
 LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
    |                           ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:35:29
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/impl_trait_projections.rs:32:29
    |
 LL |     -> <dyn Iterator<Item = impl Debug> as Iterator>::Item
    |                             ^^^^^^^^^^
-
-error[E0667]: `impl Trait` is not allowed in path parameters
-  --> $DIR/impl_trait_projections.rs:12:51
-   |
-LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item {
-   |                                                   ^^^^^^^^^^^^^
-
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:26:8
-   |
-LL |     -> <::std::ops::Range<impl Debug> as Iterator>::Item
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
-   |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
-
-error[E0277]: the trait bound `impl Debug: Step` is not satisfied
-  --> $DIR/impl_trait_projections.rs:29:1
-   |
-LL | / {
-LL | |
-LL | |     (1i32..100).next().unwrap()
-LL | | }
-   | |_^ the trait `Step` is not implemented for `impl Debug`, which is required by `std::ops::Range<impl Debug>: Iterator`
    |
-   = help: the following other types implement trait `Step`:
-             Char
-             Ipv4Addr
-             Ipv6Addr
-             char
-             i128
-             i16
-             i32
-             i64
-           and 8 others
-   = note: required for `std::ops::Range<impl Debug>` to implement `Iterator`
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
-error: aborting due to 7 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0277, E0667.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
new file mode 100644
index 00000000000..c2c22cd1abf
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.rs
@@ -0,0 +1,22 @@
+// issue: rust-lang/rust#126725
+
+trait Foo {
+    fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+    //~^ ERROR `impl Trait` is not allowed in paths
+}
+
+trait Bar {
+    type Output;
+}
+
+impl<'a> Bar for &'a () {
+    type Output = &'a i32;
+}
+
+impl Foo for () {
+    fn foo<'a>() -> <&'a Self as Bar>::Output {
+        &0
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
new file mode 100644
index 00000000000..bea7ccd1a18
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/bad-projection-from-opaque.stderr
@@ -0,0 +1,11 @@
+error[E0562]: `impl Trait` is not allowed in paths
+  --> $DIR/bad-projection-from-opaque.rs:4:26
+   |
+LL |     fn foo<'a>() -> <&'a impl Sized as Bar>::Output;
+   |                          ^^^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
index 058517f0014..38c7a9ea16e 100644
--- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
+++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr
@@ -8,7 +8,7 @@ LL | |
 ...  |
 LL | |     where
 LL | |         F: Callback<Self::CallbackArg>,
-   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -26,7 +26,7 @@ error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
   --> $DIR/false-positive-predicate-entailment-error.rs:36:30
    |
 LL |     fn autobatch<F>(self) -> impl Trait
-   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -58,7 +58,7 @@ LL | |
 ...  |
 LL | |     where
 LL | |         F: Callback<Self::CallbackArg>,
-   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -77,7 +77,7 @@ error[E0277]: the trait bound `F: MyFn<i32>` is not satisfied
   --> $DIR/false-positive-predicate-entailment-error.rs:36:30
    |
 LL |     fn autobatch<F>(self) -> impl Trait
-   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |                              ^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -91,7 +91,7 @@ error[E0277]: the trait bound `F: Callback<i32>` is not satisfied
   --> $DIR/false-positive-predicate-entailment-error.rs:27:12
    |
 LL |         F: Callback<Self::CallbackArg>;
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
@@ -111,7 +111,7 @@ LL | |
 ...  |
 LL | |     where
 LL | |         F: Callback<Self::CallbackArg>,
-   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`, which is required by `F: Callback<i32>`
+   | |_______________________________________^ the trait `MyFn<i32>` is not implemented for `F`
    |
 note: required for `F` to implement `Callback<i32>`
   --> $DIR/false-positive-predicate-entailment-error.rs:14:21
diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.rs b/tests/ui/impl-trait/in-trait/return-type-notation.rs
new file mode 100644
index 00000000000..3945eb9bdee
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/return-type-notation.rs
@@ -0,0 +1,9 @@
+#![allow(incomplete_features)]
+#![feature(return_type_notation)]
+
+trait IntFactory {
+    fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
+    //~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream`
+}
+
+pub fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/return-type-notation.stderr b/tests/ui/impl-trait/in-trait/return-type-notation.stderr
new file mode 100644
index 00000000000..d9fd780cdff
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/return-type-notation.stderr
@@ -0,0 +1,27 @@
+error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream`
+  --> $DIR/return-type-notation.rs:5:5
+   |
+LL |     fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: ...which requires computing function signature of `IntFactory::stream`...
+  --> $DIR/return-type-notation.rs:5:5
+   |
+LL |     fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires looking up late bound vars inside `IntFactory::stream`...
+  --> $DIR/return-type-notation.rs:5:5
+   |
+LL |     fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle
+note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}`
+  --> $DIR/return-type-notation.rs:5:25
+   |
+LL |     fn stream(&self) -> impl IntFactory<stream(..): IntFactory<stream(..): Send> + Send>;
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs
index 19905c608e3..cd2f43fca9a 100644
--- a/tests/ui/impl-trait/in-trait/variance.rs
+++ b/tests/ui/impl-trait/in-trait/variance.rs
@@ -4,7 +4,7 @@
 
 trait Foo<'i> {
     fn implicit_capture_early<'a: 'a>() -> impl Sized {}
-    //~^ [Self: o, 'i: o, 'a: *, 'a: o, 'i: o]
+    //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o]
 
     fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {}
     //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o]
@@ -13,12 +13,12 @@ trait Foo<'i> {
     //~^ [Self: o, 'i: o, 'a: *, 'i: o]
 
     fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
-    //~^ [Self: o, 'i: o, 'a: o, 'i: o]
+    //~^ [Self: o, 'i: o, 'i: o, 'a: o]
 
     fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {}
     //~^ [Self: o, 'i: o, 'i: o, 'a: o]
 
-    fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {}
+    fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {}
     //~^ [Self: o, 'i: o, 'i: o]
 }
 
diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr
index f65174e1c35..d45cca982e9 100644
--- a/tests/ui/impl-trait/in-trait/variance.stderr
+++ b/tests/ui/impl-trait/in-trait/variance.stderr
@@ -1,4 +1,4 @@
-error: [Self: o, 'i: o, 'a: *, 'a: o, 'i: o]
+error: [Self: o, 'i: o, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:6:44
    |
 LL |     fn implicit_capture_early<'a: 'a>() -> impl Sized {}
@@ -16,7 +16,7 @@ error: [Self: o, 'i: o, 'a: *, 'i: o]
 LL |     fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {}
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: [Self: o, 'i: o, 'a: o, 'i: o]
+error: [Self: o, 'i: o, 'i: o, 'a: o]
   --> $DIR/variance.rs:15:48
    |
 LL |     fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {}
@@ -31,7 +31,7 @@ LL |     fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Sel
 error: [Self: o, 'i: o, 'i: o]
   --> $DIR/variance.rs:21:44
    |
-LL |     fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {}
+LL |     fn not_captured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {}
    |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/impl-trait/issue-55872-1.stderr b/tests/ui/impl-trait/issue-55872-1.stderr
index 0c86824e622..8912cce1b4b 100644
--- a/tests/ui/impl-trait/issue-55872-1.stderr
+++ b/tests/ui/impl-trait/issue-55872-1.stderr
@@ -11,7 +11,7 @@ error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)`
   --> $DIR/issue-55872-1.rs:12:29
    |
 LL |     fn foo<T: Default>() -> Self::E {
-   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`, which is required by `(S, T): Copy`
+   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S`
    |
    = note: required because it appears within the type `(S, T)`
 help: consider further restricting this bound
@@ -23,7 +23,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)`
   --> $DIR/issue-55872-1.rs:12:29
    |
 LL |     fn foo<T: Default>() -> Self::E {
-   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`, which is required by `(S, T): Copy`
+   |                             ^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `(S, T)`
 help: consider further restricting this bound
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
index c5ecd1caae1..9466668b1dc 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs
@@ -6,7 +6,7 @@
 pub trait Bar { }
 pub trait Quux<T> { type Assoc; }
 pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
-//~^ ERROR `impl Trait` is not allowed in path parameters
+//~^ ERROR `impl Trait` is not allowed in paths
 impl<T> Quux<T> for () { type Assoc = u32; }
 
 fn main() { }
diff --git a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
index 55f47785f0e..25547dfa66f 100644
--- a/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
+++ b/tests/ui/impl-trait/issues/issue-57979-impl-trait-in-path.stderr
@@ -1,9 +1,11 @@
-error[E0667]: `impl Trait` is not allowed in path parameters
+error[E0562]: `impl Trait` is not allowed in paths
   --> $DIR/issue-57979-impl-trait-in-path.rs:8:48
    |
 LL | pub fn demo(_: impl Quux<(), Assoc=<() as Quux<impl Bar>>::Assoc>) { }
    |                                                ^^^^^^^^
+   |
+   = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0667`.
+For more information about this error, try `rustc --explain E0562`.
diff --git a/tests/ui/impl-trait/nested_impl_trait.stderr b/tests/ui/impl-trait/nested_impl_trait.stderr
index 83d1347aff4..31c3e0c9013 100644
--- a/tests/ui/impl-trait/nested_impl_trait.stderr
+++ b/tests/ui/impl-trait/nested_impl_trait.stderr
@@ -46,7 +46,7 @@ error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfie
   --> $DIR/nested_impl_trait.rs:6:46
    |
 LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                              ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
@@ -55,7 +55,7 @@ error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfie
   --> $DIR/nested_impl_trait.rs:19:34
    |
 LL |     fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
-   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`, which is required by `impl Into<u32>: Into<impl Debug>`
+   |                                  ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
    |
    = help: the trait `Into<U>` is implemented for `T`
    = note: required for `impl Into<u32>` to implement `Into<impl Debug>`
diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr
index b370a5d7eb1..f9142664f1b 100644
--- a/tests/ui/impl-trait/normalize-tait-in-const.stderr
+++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr
@@ -1,28 +1,28 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:42
+  --> $DIR/normalize-tait-in-const.rs:26:35
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                          ^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:69
+  --> $DIR/normalize-tait-in-const.rs:26:62
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                                                     ^^^^^^^^
+   |                                                              ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:42
+  --> $DIR/normalize-tait-in-const.rs:26:35
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                          ^^^^^^^^^^^^^^^^^
+   |                                   ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/normalize-tait-in-const.rs:26:69
+  --> $DIR/normalize-tait-in-const.rs:26:62
    |
 LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) {
-   |                                                                     ^^^^^^^^
+   |                                                              ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/indexing/index-help.stderr b/tests/ui/indexing/index-help.stderr
index 1291bf2a461..4ec28ddf871 100644
--- a/tests/ui/indexing/index-help.stderr
+++ b/tests/ui/indexing/index-help.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32`
 LL |     x[0i32];
    |       ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`, which is required by `Vec<{integer}>: Index<_>`
+   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32`
    = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i32`
    = note: required for `Vec<{integer}>` to implement `Index<i32>`
diff --git a/tests/ui/indexing/indexing-requires-a-uint.stderr b/tests/ui/indexing/indexing-requires-a-uint.stderr
index 38e7881dcc6..3041c2c99a1 100644
--- a/tests/ui/indexing/indexing-requires-a-uint.stderr
+++ b/tests/ui/indexing/indexing-requires-a-uint.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8`
 LL |     [0][0u8];
    |         ^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`, which is required by `[{integer}; 1]: Index<_>`
+   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8`
    = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `u8`
    = note: required for `[{integer}]` to implement `Index<u8>`
diff --git a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr
index df4d7cc0683..4cced22789f 100644
--- a/tests/ui/indexing/point-at-index-for-obligation-failure.stderr
+++ b/tests/ui/indexing/point-at-index-for-obligation-failure.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: Borrow<&str>` is not satisfied
   --> $DIR/point-at-index-for-obligation-failure.rs:5:9
    |
 LL |         &s
-   |         ^^ the trait `Borrow<&str>` is not implemented for `String`, which is required by `HashMap<String, String>: Index<&_>`
+   |         ^^ the trait `Borrow<&str>` is not implemented for `String`
    |
    = help: the trait `Borrow<str>` is implemented for `String`
    = help: for that trait implementation, expected `str`, found `&str`
diff --git a/tests/ui/integral-indexing.stderr b/tests/ui/integral-indexing.stderr
index ad2c3af424b..97e658617cf 100644
--- a/tests/ui/integral-indexing.stderr
+++ b/tests/ui/integral-indexing.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8`
 LL |     v[3u8];
    |       ^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[isize]>` is not implemented for `u8`, which is required by `Vec<isize>: Index<_>`
+   = help: the trait `SliceIndex<[isize]>` is not implemented for `u8`
    = help: the trait `SliceIndex<[isize]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `u8`
    = note: required for `Vec<isize>` to implement `Index<u8>`
@@ -15,7 +15,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i8`
 LL |     v[3i8];
    |       ^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[isize]>` is not implemented for `i8`, which is required by `Vec<isize>: Index<_>`
+   = help: the trait `SliceIndex<[isize]>` is not implemented for `i8`
    = help: the trait `SliceIndex<[isize]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i8`
    = note: required for `Vec<isize>` to implement `Index<i8>`
@@ -26,7 +26,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `u32`
 LL |     v[3u32];
    |       ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[isize]>` is not implemented for `u32`, which is required by `Vec<isize>: Index<_>`
+   = help: the trait `SliceIndex<[isize]>` is not implemented for `u32`
    = help: the trait `SliceIndex<[isize]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `u32`
    = note: required for `Vec<isize>` to implement `Index<u32>`
@@ -37,7 +37,7 @@ error[E0277]: the type `[isize]` cannot be indexed by `i32`
 LL |     v[3i32];
    |       ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[isize]>` is not implemented for `i32`, which is required by `Vec<isize>: Index<_>`
+   = help: the trait `SliceIndex<[isize]>` is not implemented for `i32`
    = help: the trait `SliceIndex<[isize]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i32`
    = note: required for `Vec<isize>` to implement `Index<i32>`
@@ -48,7 +48,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u8`
 LL |     s.as_bytes()[3u8];
    |                  ^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[u8]>` is not implemented for `u8`, which is required by `[u8]: Index<_>`
+   = help: the trait `SliceIndex<[u8]>` is not implemented for `u8`
    = help: the trait `SliceIndex<[u8]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `u8`
    = note: required for `[u8]` to implement `Index<u8>`
@@ -59,7 +59,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i8`
 LL |     s.as_bytes()[3i8];
    |                  ^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[u8]>` is not implemented for `i8`, which is required by `[u8]: Index<_>`
+   = help: the trait `SliceIndex<[u8]>` is not implemented for `i8`
    = help: the trait `SliceIndex<[u8]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i8`
    = note: required for `[u8]` to implement `Index<i8>`
@@ -70,7 +70,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `u32`
 LL |     s.as_bytes()[3u32];
    |                  ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[u8]>` is not implemented for `u32`, which is required by `[u8]: Index<_>`
+   = help: the trait `SliceIndex<[u8]>` is not implemented for `u32`
    = help: the trait `SliceIndex<[u8]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `u32`
    = note: required for `[u8]` to implement `Index<u32>`
@@ -81,7 +81,7 @@ error[E0277]: the type `[u8]` cannot be indexed by `i32`
 LL |     s.as_bytes()[3i32];
    |                  ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[u8]>` is not implemented for `i32`, which is required by `[u8]: Index<_>`
+   = help: the trait `SliceIndex<[u8]>` is not implemented for `i32`
    = help: the trait `SliceIndex<[u8]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i32`
    = note: required for `[u8]` to implement `Index<i32>`
diff --git a/tests/ui/interior-mutability/interior-mutability.stderr b/tests/ui/interior-mutability/interior-mutability.stderr
index 29b250c1b07..cfc64445bf3 100644
--- a/tests/ui/interior-mutability/interior-mutability.stderr
+++ b/tests/ui/interior-mutability/interior-mutability.stderr
@@ -6,7 +6,7 @@ LL |     catch_unwind(|| { x.set(23); });
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `{closure@$DIR/interior-mutability.rs:5:18: 5:20}: UnwindSafe`
+   = help: within `Cell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
 note: required because it appears within the type `Cell<i32>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
    = note: required for `&Cell<i32>` to implement `UnwindSafe`
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
index 55983a445a4..c59e357b275 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.effects.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `size_of`
   --> $DIR/safe-intrinsic-mismatch.rs:11:5
    |
@@ -47,6 +42,6 @@ LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
    = note: expected signature `unsafe fn(_, _, _)`
               found signature `fn(_, _, _)`
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/issues/issue-21763.stderr b/tests/ui/issues/issue-21763.stderr
index aa4938a0c0b..135b705eeef 100644
--- a/tests/ui/issues/issue-21763.stderr
+++ b/tests/ui/issues/issue-21763.stderr
@@ -4,7 +4,7 @@ error[E0277]: `Rc<()>` cannot be sent between threads safely
 LL |     foo::<HashMap<Rc<()>, Rc<()>>>();
    |           ^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely
    |
-   = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`, which is required by `HashMap<Rc<()>, Rc<()>>: Send`
+   = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>`
    = note: required because it appears within the type `(Rc<()>, Rc<()>)`
    = note: required for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` to implement `Send`
 note: required because it appears within the type `hashbrown::map::HashMap<Rc<()>, Rc<()>, RandomState>`
diff --git a/tests/ui/issues/issue-22872.stderr b/tests/ui/issues/issue-22872.stderr
index 03e5393da48..6ff710b1133 100644
--- a/tests/ui/issues/issue-22872.stderr
+++ b/tests/ui/issues/issue-22872.stderr
@@ -4,7 +4,7 @@ error[E0277]: `<P as Process<'_>>::Item` is not an iterator
 LL |     let _: Box<dyn for<'b> Wrap<'b>> = Box::new(Wrapper(process));
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^ `<P as Process<'_>>::Item` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `<P as Process<'_>>::Item`, which is required by `for<'b> Wrapper<P>: Wrap<'b>`
+   = help: the trait `Iterator` is not implemented for `<P as Process<'_>>::Item`
 note: required for `Wrapper<P>` to implement `for<'b> Wrap<'b>`
   --> $DIR/issue-22872.rs:7:13
    |
diff --git a/tests/ui/issues/issue-22874.stderr b/tests/ui/issues/issue-22874.stderr
index 29ddf9756ff..7d5b601ed49 100644
--- a/tests/ui/issues/issue-22874.stderr
+++ b/tests/ui/issues/issue-22874.stderr
@@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[String]` cannot be known at compilat
 LL |     &table.rows[0]
    |      ^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `[String]`, which is required by `[_]: Index<_>`
+   = help: the trait `Sized` is not implemented for `[String]`
    = note: required for `[[String]]` to implement `Index<_>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/issues/issue-40827.stderr b/tests/ui/issues/issue-40827.stderr
index 44ae90cbc0f..7f5c578ae4f 100644
--- a/tests/ui/issues/issue-40827.stderr
+++ b/tests/ui/issues/issue-40827.stderr
@@ -6,7 +6,7 @@ LL |     f(Foo(Arc::new(Bar::B(None))));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`, which is required by `Foo: Send`
+   = help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
 note: required because it appears within the type `Bar`
   --> $DIR/issue-40827.rs:6:6
    |
@@ -32,7 +32,7 @@ LL |     f(Foo(Arc::new(Bar::B(None))));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`, which is required by `Foo: Send`
+   = help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
 note: required because it appears within the type `Bar`
   --> $DIR/issue-40827.rs:6:6
    |
diff --git a/tests/ui/issues/issue-7364.stderr b/tests/ui/issues/issue-7364.stderr
index d5b6dde1f10..65ec1d75053 100644
--- a/tests/ui/issues/issue-7364.stderr
+++ b/tests/ui/issues/issue-7364.stderr
@@ -4,7 +4,7 @@ error[E0277]: `RefCell<isize>` cannot be shared between threads safely
 LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
    |               ^^^^^^^^^^^^^^^^^^^ `RefCell<isize>` cannot be shared between threads safely
    |
-   = help: the trait `Sync` is not implemented for `RefCell<isize>`, which is required by `Box<RefCell<isize>>: Sync`
+   = help: the trait `Sync` is not implemented for `RefCell<isize>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead
    = note: required for `Unique<RefCell<isize>>` to implement `Sync`
 note: required because it appears within the type `Box<RefCell<isize>>`
diff --git a/tests/ui/iterators/float_iterator_hint.stderr b/tests/ui/iterators/float_iterator_hint.stderr
index 29319b9400f..c3cb00c3c68 100644
--- a/tests/ui/iterators/float_iterator_hint.stderr
+++ b/tests/ui/iterators/float_iterator_hint.stderr
@@ -4,7 +4,7 @@ error[E0277]: `{float}` is not an iterator
 LL |     for i in 0.2 {
    |              ^^^ `{float}` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `{float}`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `{float}` to implement `IntoIterator`
 
diff --git a/tests/ui/iterators/integral.stderr b/tests/ui/iterators/integral.stderr
index 74bbe28d6b7..c142fec8da0 100644
--- a/tests/ui/iterators/integral.stderr
+++ b/tests/ui/iterators/integral.stderr
@@ -4,7 +4,7 @@ error[E0277]: `{integer}` is not an iterator
 LL |     for _ in 42 {}
    |              ^^ `{integer}` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `{integer}`, which is required by `{integer}: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `{integer}`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `{integer}` to implement `IntoIterator`
 
@@ -14,7 +14,7 @@ error[E0277]: `u8` is not an iterator
 LL |     for _ in 42 as u8 {}
    |              ^^^^^^^^ `u8` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `u8`, which is required by `u8: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `u8`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `u8` to implement `IntoIterator`
 
@@ -24,7 +24,7 @@ error[E0277]: `i8` is not an iterator
 LL |     for _ in 42 as i8 {}
    |              ^^^^^^^^ `i8` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `i8`, which is required by `i8: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `i8`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `i8` to implement `IntoIterator`
 
@@ -34,7 +34,7 @@ error[E0277]: `u16` is not an iterator
 LL |     for _ in 42 as u16 {}
    |              ^^^^^^^^^ `u16` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `u16`, which is required by `u16: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `u16`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `u16` to implement `IntoIterator`
 
@@ -44,7 +44,7 @@ error[E0277]: `i16` is not an iterator
 LL |     for _ in 42 as i16 {}
    |              ^^^^^^^^^ `i16` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `i16`, which is required by `i16: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `i16`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `i16` to implement `IntoIterator`
 
@@ -54,7 +54,7 @@ error[E0277]: `u32` is not an iterator
 LL |     for _ in 42 as u32 {}
    |              ^^^^^^^^^ `u32` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `u32`, which is required by `u32: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `u32`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `u32` to implement `IntoIterator`
 
@@ -64,7 +64,7 @@ error[E0277]: `i32` is not an iterator
 LL |     for _ in 42 as i32 {}
    |              ^^^^^^^^^ `i32` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `i32`, which is required by `i32: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `i32`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `i32` to implement `IntoIterator`
 
@@ -74,7 +74,7 @@ error[E0277]: `u64` is not an iterator
 LL |     for _ in 42 as u64 {}
    |              ^^^^^^^^^ `u64` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `u64`, which is required by `u64: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `u64`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `u64` to implement `IntoIterator`
 
@@ -84,7 +84,7 @@ error[E0277]: `i64` is not an iterator
 LL |     for _ in 42 as i64 {}
    |              ^^^^^^^^^ `i64` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `i64`, which is required by `i64: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `i64`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `i64` to implement `IntoIterator`
 
@@ -94,7 +94,7 @@ error[E0277]: `usize` is not an iterator
 LL |     for _ in 42 as usize {}
    |              ^^^^^^^^^^^ `usize` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `usize`, which is required by `usize: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `usize`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `usize` to implement `IntoIterator`
 
@@ -104,7 +104,7 @@ error[E0277]: `isize` is not an iterator
 LL |     for _ in 42 as isize {}
    |              ^^^^^^^^^^^ `isize` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `isize`, which is required by `isize: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `isize`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `isize` to implement `IntoIterator`
 
@@ -114,7 +114,7 @@ error[E0277]: `{float}` is not an iterator
 LL |     for _ in 42.0 {}
    |              ^^^^ `{float}` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `{float}`, which is required by `{float}: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `{float}`
    = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end`
    = note: required for `{float}` to implement `IntoIterator`
 
diff --git a/tests/ui/iterators/issue-28098.stderr b/tests/ui/iterators/issue-28098.stderr
index 3cb1b2f7270..a724f03ad4a 100644
--- a/tests/ui/iterators/issue-28098.stderr
+++ b/tests/ui/iterators/issue-28098.stderr
@@ -14,7 +14,7 @@ error[E0277]: `bool` is not an iterator
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `bool`
    = note: required for `bool` to implement `IntoIterator`
 
 error[E0277]: `()` is not an iterator
@@ -61,7 +61,7 @@ error[E0277]: `bool` is not an iterator
 LL |     for _ in false {}
    |              ^^^^^ `bool` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `bool`
    = note: required for `bool` to implement `IntoIterator`
 
 error[E0277]: `()` is not an iterator
diff --git a/tests/ui/iterators/ranges.stderr b/tests/ui/iterators/ranges.stderr
index a5d43ecbb63..b9fbcd5304b 100644
--- a/tests/ui/iterators/ranges.stderr
+++ b/tests/ui/iterators/ranges.stderr
@@ -4,7 +4,7 @@ error[E0277]: `RangeTo<{integer}>` is not an iterator
 LL |     for _ in ..10 {}
    |              ^^^^ if you meant to iterate until a value, add a starting value
    |
-   = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>`, which is required by `RangeTo<{integer}>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>`
    = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end`
    = note: required for `RangeTo<{integer}>` to implement `IntoIterator`
 
@@ -14,7 +14,7 @@ error[E0277]: `RangeToInclusive<{integer}>` is not an iterator
 LL |     for _ in ..=10 {}
    |              ^^^^^ if you meant to iterate until a value (including it), add a starting value
    |
-   = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`, which is required by `RangeToInclusive<{integer}>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>`
    = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end`
    = note: required for `RangeToInclusive<{integer}>` to implement `IntoIterator`
 
diff --git a/tests/ui/iterators/string.stderr b/tests/ui/iterators/string.stderr
index 29f560677c0..ddfe0169b84 100644
--- a/tests/ui/iterators/string.stderr
+++ b/tests/ui/iterators/string.stderr
@@ -4,7 +4,7 @@ error[E0277]: `String` is not an iterator
 LL |     for _ in "".to_owned() {}
    |              ^^^^^^^^^^^^^ `String` is not an iterator; try calling `.chars()` or `.bytes()`
    |
-   = help: the trait `Iterator` is not implemented for `String`, which is required by `String: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `String`
    = note: required for `String` to implement `IntoIterator`
 
 error[E0277]: `&str` is not an iterator
@@ -13,7 +13,7 @@ error[E0277]: `&str` is not an iterator
 LL |     for _ in "" {}
    |              ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
    |
-   = help: the trait `Iterator` is not implemented for `&str`, which is required by `&str: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&str`
    = note: required for `&str` to implement `IntoIterator`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/kindck/kindck-impl-type-params-2.stderr b/tests/ui/kindck/kindck-impl-type-params-2.stderr
index a7d169d3ac4..38dc94f9104 100644
--- a/tests/ui/kindck/kindck-impl-type-params-2.stderr
+++ b/tests/ui/kindck/kindck-impl-type-params-2.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-impl-type-params-2.rs:13:16
    |
 LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo`
+   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr
index 5892596dc6a..da9a8e5532c 100644
--- a/tests/ui/kindck/kindck-impl-type-params.stderr
+++ b/tests/ui/kindck/kindck-impl-type-params.stderr
@@ -21,7 +21,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:16:13
    |
 LL |     let a = &t as &dyn Gettable<T>;
-   |             ^^ the trait `Copy` is not implemented for `T`, which is required by `S<T>: Gettable<T>`
+   |             ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
   --> $DIR/kindck-impl-type-params.rs:12:32
@@ -59,7 +59,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:23:31
    |
 LL |     let a: &dyn Gettable<T> = &t;
-   |                               ^^ the trait `Copy` is not implemented for `T`, which is required by `S<T>: Gettable<T>`
+   |                               ^^ the trait `Copy` is not implemented for `T`
    |
 note: required for `S<T>` to implement `Gettable<T>`
   --> $DIR/kindck-impl-type-params.rs:12:32
@@ -78,7 +78,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:36:13
    |
 LL |     let a = t as Box<dyn Gettable<String>>;
-   |             ^ the trait `Copy` is not implemented for `String`, which is required by `S<String>: Gettable<String>`
+   |             ^ the trait `Copy` is not implemented for `String`
    |
    = help: the trait `Gettable<T>` is implemented for `S<T>`
 note: required for `S<String>` to implement `Gettable<String>`
@@ -94,7 +94,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied
   --> $DIR/kindck-impl-type-params.rs:44:37
    |
 LL |     let a: Box<dyn Gettable<Foo>> = t;
-   |                                     ^ the trait `Copy` is not implemented for `Foo`, which is required by `S<Foo>: Gettable<Foo>`
+   |                                     ^ the trait `Copy` is not implemented for `Foo`
    |
    = help: the trait `Gettable<T>` is implemented for `S<T>`
 note: required for `S<Foo>` to implement `Gettable<Foo>`
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
index e797ca01f4b..c392879db3e 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo`
+   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
index b4424f4750e..34dcad13af3 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
   --> $DIR/kindck-inherited-copy-bound.rs:21:16
    |
 LL |     take_param(&x);
-   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`, which is required by `Box<{integer}>: Foo`
+   |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/kindck/kindck-nonsendable-1.stderr b/tests/ui/kindck/kindck-nonsendable-1.stderr
index 8cc931bc48e..8bb784d1d49 100644
--- a/tests/ui/kindck/kindck-nonsendable-1.stderr
+++ b/tests/ui/kindck/kindck-nonsendable-1.stderr
@@ -8,7 +8,7 @@ LL |     bar(move|| foo(x));
    |     |   within this `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`
    |     required by a bound introduced by this call
    |
-   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>`, which is required by `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}: Send`
+   = help: within `{closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:15}`, the trait `Send` is not implemented for `Rc<usize>`
 note: required because it's used within this closure
   --> $DIR/kindck-nonsendable-1.rs:9:9
    |
diff --git a/tests/ui/kindck/kindck-send-object.stderr b/tests/ui/kindck/kindck-send-object.stderr
index 7d0c711abc4..0e2ff1730c8 100644
--- a/tests/ui/kindck/kindck-send-object.stderr
+++ b/tests/ui/kindck/kindck-send-object.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa
 LL |     assert_send::<&'static (dyn Dummy + 'static)>();
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
    |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
    = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
 note: required by a bound in `assert_send`
   --> $DIR/kindck-send-object.rs:5:18
@@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely
 LL |     assert_send::<Box<dyn Dummy>>();
    |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box<dyn Dummy>: Send`
+   = help: the trait `Send` is not implemented for `dyn Dummy`
    = note: required for `Unique<dyn Dummy>` to implement `Send`
 note: required because it appears within the type `Box<dyn Dummy>`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/tests/ui/kindck/kindck-send-object1.stderr b/tests/ui/kindck/kindck-send-object1.stderr
index 7f39dab2086..e3ff2eb9ff4 100644
--- a/tests/ui/kindck/kindck-send-object1.stderr
+++ b/tests/ui/kindck/kindck-send-object1.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
 LL |     assert_send::<&'a dyn Dummy>();
    |                   ^^^^^^^^^^^^^ `&'a (dyn Dummy + 'a)` cannot be sent between threads safely
    |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`, which is required by `&'a (dyn Dummy + 'a): Send`
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)`
    = note: required for `&'a (dyn Dummy + 'a)` to implement `Send`
 note: required by a bound in `assert_send`
   --> $DIR/kindck-send-object1.rs:5:18
@@ -18,7 +18,7 @@ error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely
 LL |     assert_send::<Box<dyn Dummy + 'a>>();
    |                   ^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`, which is required by `Box<(dyn Dummy + 'a)>: Send`
+   = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)`
    = note: required for `Unique<(dyn Dummy + 'a)>` to implement `Send`
 note: required because it appears within the type `Box<(dyn Dummy + 'a)>`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/tests/ui/kindck/kindck-send-object2.stderr b/tests/ui/kindck/kindck-send-object2.stderr
index a481a132cce..8898bf5b3fa 100644
--- a/tests/ui/kindck/kindck-send-object2.stderr
+++ b/tests/ui/kindck/kindck-send-object2.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&'static (dyn Dummy + 'static)` cannot be sent between threads sa
 LL |     assert_send::<&'static dyn Dummy>();
    |                   ^^^^^^^^^^^^^^^^^^ `&'static (dyn Dummy + 'static)` cannot be sent between threads safely
    |
-   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`, which is required by `&'static (dyn Dummy + 'static): Send`
+   = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)`
    = note: required for `&'static (dyn Dummy + 'static)` to implement `Send`
 note: required by a bound in `assert_send`
   --> $DIR/kindck-send-object2.rs:3:18
@@ -18,7 +18,7 @@ error[E0277]: `dyn Dummy` cannot be sent between threads safely
 LL |     assert_send::<Box<dyn Dummy>>();
    |                   ^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `dyn Dummy`, which is required by `Box<dyn Dummy>: Send`
+   = help: the trait `Send` is not implemented for `dyn Dummy`
    = note: required for `Unique<dyn Dummy>` to implement `Send`
 note: required because it appears within the type `Box<dyn Dummy>`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/tests/ui/kindck/kindck-send-owned.stderr b/tests/ui/kindck/kindck-send-owned.stderr
index 4bc0212089b..860a9391bbb 100644
--- a/tests/ui/kindck/kindck-send-owned.stderr
+++ b/tests/ui/kindck/kindck-send-owned.stderr
@@ -4,7 +4,7 @@ error[E0277]: `*mut u8` cannot be sent between threads safely
 LL |     assert_send::<Box<*mut u8>>();
    |                   ^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely
    |
-   = help: the trait `Send` is not implemented for `*mut u8`, which is required by `Box<*mut u8>: Send`
+   = help: the trait `Send` is not implemented for `*mut u8`
    = note: required for `Unique<*mut u8>` to implement `Send`
 note: required because it appears within the type `Box<*mut u8>`
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr
deleted file mode 100644
index 23e017cb012..00000000000
--- a/tests/ui/linkage-attr/framework.omit.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: linking with `LINKER` failed: exit status: 1
-   |
-           ld: Undefined symbols:
-             _CFRunLoopGetTypeID, referenced from:
-           clang: error: linker command failed with exit code 1 (use -v to see invocation)
-
-
-error: aborting due to 1 previous error
diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs
deleted file mode 100644
index 08f4394db21..00000000000
--- a/tests/ui/linkage-attr/framework.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Check that linking frameworks on Apple platforms works.
-//@ only-apple
-//@ revisions: omit link weak both
-//@ [omit]build-fail
-//@ [link]run-pass
-//@ [weak]run-pass
-//@ [both]run-pass
-
-// The linker's exact error output changes between Xcode versions, depends on
-// linker invocation details, and the linker sometimes outputs more warnings.
-//@ compare-output-lines-by-subset
-//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed"
-//@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:"
-//@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID,"
-
-#![cfg_attr(any(weak, both), feature(link_arg_attribute))]
-
-#[cfg_attr(any(link, both), link(name = "CoreFoundation", kind = "framework"))]
-#[cfg_attr(
-    any(weak, both),
-    link(name = "-weak_framework", kind = "link-arg", modifiers = "+verbatim"),
-    link(name = "CoreFoundation", kind = "link-arg", modifiers = "+verbatim")
-)]
-extern "C" {
-    fn CFRunLoopGetTypeID() -> core::ffi::c_ulong;
-}
-
-pub fn main() {
-    unsafe {
-        CFRunLoopGetTypeID();
-    }
-}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
new file mode 100644
index 00000000000..d892ebdf606
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs
@@ -0,0 +1,23 @@
+#![allow(dangling_pointers_from_temporaries)]
+
+fn main() {
+    dbg!(String::new().as_ptr());
+    // ^ no error
+
+    #[deny(dangling_pointers_from_temporaries)]
+    {
+        dbg!(String::new().as_ptr());
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+    S.foo()
+}
+
+struct S;
+
+impl S {
+    #[warn(dangling_pointers_from_temporaries)]
+    fn foo(self) {
+        dbg!(String::new().as_ptr());
+        //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
new file mode 100644
index 00000000000..fd434eacf3d
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr
@@ -0,0 +1,34 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/allow.rs:9:28
+   |
+LL |         dbg!(String::new().as_ptr());
+   |              ------------- ^^^^^^ this pointer will immediately be invalid
+   |              |
+   |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/allow.rs:7:12
+   |
+LL |     #[deny(dangling_pointers_from_temporaries)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/allow.rs:20:28
+   |
+LL |         dbg!(String::new().as_ptr());
+   |              ------------- ^^^^^^ this pointer will immediately be invalid
+   |              |
+   |              this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/allow.rs:18:12
+   |
+LL |     #[warn(dangling_pointers_from_temporaries)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
new file mode 100644
index 00000000000..b376582a886
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::ffi::{c_char, CString};
+
+fn cstring() -> CString {
+    CString::new("hello").unwrap()
+}
+
+fn consume(ptr: *const c_char) {
+    let c = unsafe { ptr.read() };
+    dbg!(c);
+}
+
+// None of these should trigger the lint.
+fn ok() {
+    consume(cstring().as_ptr());
+    consume({ cstring() }.as_ptr());
+    consume({ cstring().as_ptr() });
+    consume(cstring().as_ptr().cast());
+    consume({ cstring() }.as_ptr().cast());
+    consume({ cstring().as_ptr() }.cast());
+}
+
+// All of these should trigger the lint.
+fn not_ok() {
+    {
+        let ptr = cstring().as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+        consume(ptr);
+    }
+    consume({
+        let ptr = cstring().as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+        ptr
+    });
+    consume({
+        let s = cstring();
+        s.as_ptr()
+        //^ FIXME: should error
+    });
+    let _ptr: *const u8 = cstring().as_ptr().cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+}
+
+fn main() {
+    ok();
+    not_ok();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
new file mode 100644
index 00000000000..d1615b76d82
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr
@@ -0,0 +1,62 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:27:29
+   |
+LL |         let ptr = cstring().as_ptr();
+   |                   --------- ^^^^^^ this pointer will immediately be invalid
+   |                   |
+   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/calls.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:32:29
+   |
+LL |         let ptr = cstring().as_ptr();
+   |                   --------- ^^^^^^ this pointer will immediately be invalid
+   |                   |
+   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:41:37
+   |
+LL |     let _ptr: *const u8 = cstring().as_ptr().cast();
+   |                           --------- ^^^^^^ this pointer will immediately be invalid
+   |                           |
+   |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:43:41
+   |
+LL |     let _ptr: *const u8 = { cstring() }.as_ptr().cast();
+   |                           ------------- ^^^^^^ this pointer will immediately be invalid
+   |                           |
+   |                           this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/calls.rs:45:39
+   |
+LL |     let _ptr: *const u8 = { cstring().as_ptr() }.cast();
+   |                             --------- ^^^^^^ this pointer will immediately be invalid
+   |                             |
+   |                             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
index 9f5805367e4..fb6ed363272 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-param.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.rs
@@ -1,4 +1,7 @@
+//@ check-pass
+
 #![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
 
 use std::ffi::CString;
 use std::os::raw::c_char;
@@ -7,5 +10,4 @@ fn some_function(data: *const c_char) {}
 
 fn main() {
     some_function(CString::new("").unwrap().as_ptr());
-    //~^ ERROR getting the inner pointer of a temporary `CString`
 }
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
new file mode 100644
index 00000000000..dd54b4971dd
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-param.stderr
@@ -0,0 +1,10 @@
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> $DIR/cstring-as-param.rs:3:9
+   |
+LL | #![deny(temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
index fab792f1284..a98378794ab 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.rs
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs
@@ -1,17 +1,18 @@
 // this program is not technically incorrect, but is an obscure enough style to be worth linting
 #![deny(temporary_cstring_as_ptr)]
+//~^ WARNING lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
 
 use std::ffi::CString;
 
 macro_rules! mymacro {
     () => {
         let s = CString::new("some text").unwrap().as_ptr();
-        //~^ ERROR getting the inner pointer of a temporary `CString`
+        //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
     }
 }
 
 fn main() {
     let s = CString::new("some text").unwrap().as_ptr();
-    //~^ ERROR getting the inner pointer of a temporary `CString`
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
     mymacro!();
 }
diff --git a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
index 4e5c8aa0693..5289fbb8723 100644
--- a/tests/ui/lint/lint-temporary-cstring-as-ptr.stderr
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr
@@ -1,24 +1,32 @@
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:14:48
+warning: lint `temporary_cstring_as_ptr` has been renamed to `dangling_pointers_from_temporaries`
+  --> $DIR/cstring-as-ptr.rs:2:9
+   |
+LL | #![deny(temporary_cstring_as_ptr)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `dangling_pointers_from_temporaries`
+   |
+   = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/cstring-as-ptr.rs:15:48
    |
 LL |     let s = CString::new("some text").unwrap().as_ptr();
-   |             ---------------------------------- ^^^^^^ this pointer will be invalid
+   |             ---------------------------------- ^^^^^^ this pointer will immediately be invalid
    |             |
    |             this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
 note: the lint level is defined here
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:2:9
+  --> $DIR/cstring-as-ptr.rs:2:9
    |
 LL | #![deny(temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-ptr.rs:8:52
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/cstring-as-ptr.rs:9:52
    |
 LL |         let s = CString::new("some text").unwrap().as_ptr();
-   |                 ---------------------------------- ^^^^^^ this pointer will be invalid
+   |                 ---------------------------------- ^^^^^^ this pointer will immediately be invalid
    |                 |
    |                 this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
 ...
@@ -26,8 +34,8 @@ LL |     mymacro!();
    |     ---------- in this macro invocation
    |
    = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
    = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
new file mode 100644
index 00000000000..b9b7bd3ade1
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/emacs.rs
@@ -0,0 +1,19 @@
+//@ check-pass
+
+#![deny(dangling_pointers_from_temporaries)]
+
+// The original code example comes from bindgen-produced code for emacs.
+// Hence the name of the test.
+// https://github.com/rust-lang/rust/pull/128985#issuecomment-2338951363
+
+use std::ffi::{c_char, CString};
+
+fn read(ptr: *const c_char) -> c_char {
+    unsafe { ptr.read() }
+}
+
+fn main() {
+    let fnptr: Option<fn(ptr: *const c_char) -> c_char> = Some(read);
+    let x = fnptr.unwrap()(CString::new("foo").unwrap().as_ptr());
+    assert_eq!(x as u8, b'f');
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
new file mode 100644
index 00000000000..0fb07a3f3bc
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs
@@ -0,0 +1,13 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+const MAX_PATH: usize = 260;
+fn main() {
+    let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    unsafe {
+        std::ptr::copy_nonoverlapping(str2, str1, 30);
+        println!("{:?}", String::from_raw_parts(str1, 30, 30));
+    }
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
new file mode 100644
index 00000000000..0de794f6ae2
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/example-from-issue123613.rs:5:48
+   |
+LL |     let str1 = String::with_capacity(MAX_PATH).as_mut_ptr();
+   |                ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid
+   |                |
+   |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/example-from-issue123613.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/example-from-issue123613.rs:7:70
+   |
+LL |     let str2 = String::from("TotototototototototototototototototoT").as_ptr();
+   |                ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |                |
+   |                this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
new file mode 100644
index 00000000000..a5e84d36090
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs
@@ -0,0 +1,32 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::fmt::Debug;
+
+trait Ext1 {
+    fn dbg(self) -> Self
+    where
+        Self: Sized + Debug,
+    {
+        dbg!(&self);
+        self
+    }
+}
+
+impl<T> Ext1 for *const T {}
+
+trait Ext2 {
+    fn foo(self);
+}
+
+impl Ext2 for *const u32 {
+    fn foo(self) {
+        dbg!(unsafe { self.read() });
+    }
+}
+
+fn main() {
+    let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+    let _ptr2 = vec![0].as_ptr().foo();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
new file mode 100644
index 00000000000..5d401c89c0c
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+  --> $DIR/ext.rs:28:35
+   |
+LL |     let _ptr1 = Vec::<u32>::new().as_ptr().dbg();
+   |                 ----------------- ^^^^^^ this pointer will immediately be invalid
+   |                 |
+   |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/ext.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u32>` will be dropped
+  --> $DIR/ext.rs:30:25
+   |
+LL |     let _ptr2 = vec![0].as_ptr().foo();
+   |                 ------- ^^^^^^ this pointer will immediately be invalid
+   |                 |
+   |                 this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
new file mode 100644
index 00000000000..26019b376d3
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs
@@ -0,0 +1,8 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+fn main() {
+    vec![0u8].as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+    vec![0u8].as_mut_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
new file mode 100644
index 00000000000..11c052c158e
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr
@@ -0,0 +1,29 @@
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/methods.rs:4:15
+   |
+LL |     vec![0u8].as_ptr();
+   |     --------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/methods.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/methods.rs:6:15
+   |
+LL |     vec![0u8].as_mut_ptr();
+   |     --------- ^^^^^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
new file mode 100644
index 00000000000..1f216586ae8
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs
@@ -0,0 +1,136 @@
+#![allow(unused)]
+#![deny(dangling_pointers_from_temporaries)]
+
+fn string() -> String {
+    "hello".into()
+}
+
+struct Wrapper(String);
+
+fn main() {
+    // ConstBlock
+    const { String::new() }.as_ptr();
+
+    // Array
+    {
+        [string()].as_ptr(); // False negative
+        [true].as_ptr();
+    }
+
+    // Call
+    string().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // MethodCall
+    "hello".to_string().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Tup
+    // impossible
+
+    // Binary
+    (string() + "hello").as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Path
+    {
+        let x = string();
+        x.as_ptr();
+    }
+
+    // Unary
+    {
+        let x = string();
+        let x: &String = &x;
+        (*x).as_ptr();
+        (&[0u8]).as_ptr();
+        (&string()).as_ptr(); // False negative
+        (*&string()).as_ptr(); // False negative
+    }
+
+    // Lit
+    "hello".as_ptr();
+
+    // Cast
+    // impossible
+
+    // Type
+    // impossible
+
+    // DropTemps
+    // impossible
+
+    // Let
+    // impossible
+
+    // If
+    {
+        (if true { String::new() } else { "hello".into() }).as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Loop
+    {
+        (loop {
+            break String::new();
+        })
+        .as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Match
+    {
+        match string() {
+            s => s,
+        }
+        .as_ptr();
+        //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    }
+
+    // Closure
+    // impossible
+
+    // Block
+    { string() }.as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+
+    // Assign, AssignOp
+    // impossible
+
+    // Field
+    {
+        Wrapper(string()).0.as_ptr(); // False negative
+        let x = Wrapper(string());
+        x.0.as_ptr();
+    }
+
+    // Index
+    {
+        vec![string()][0].as_ptr(); // False negative
+        let x = vec![string()];
+        x[0].as_ptr();
+    }
+
+    // AddrOf, InlineAsm, OffsetOf
+    // impossible
+
+    // Break, Continue, Ret
+    // are !
+
+    // Become, Yield
+    // unstable, are !
+
+    // Repeat
+    [0u8; 100].as_ptr();
+    [const { String::new() }; 100].as_ptr();
+
+    // Struct
+    // Cannot test this without access to private fields of the linted types.
+
+    // Err
+    // impossible
+
+    // Macro
+    vec![0u8].as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
new file mode 100644
index 00000000000..d2e9ac8c4e9
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr
@@ -0,0 +1,99 @@
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:21:14
+   |
+LL |     string().as_ptr();
+   |     -------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/temporaries.rs:2:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:25:25
+   |
+LL |     "hello".to_string().as_ptr();
+   |     ------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:32:26
+   |
+LL |     (string() + "hello").as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:68:61
+   |
+LL |         (if true { String::new() } else { "hello".into() }).as_ptr();
+   |         --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |         |
+   |         this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:77:10
+   |
+LL | /         (loop {
+LL | |             break String::new();
+LL | |         })
+   | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL |           .as_ptr();
+   |            ^^^^^^ this pointer will immediately be invalid
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:86:10
+   |
+LL | /         match string() {
+LL | |             s => s,
+LL | |         }
+   | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+LL |           .as_ptr();
+   |            ^^^^^^ this pointer will immediately be invalid
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/temporaries.rs:94:18
+   |
+LL |     { string() }.as_ptr();
+   |     ------------ ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/temporaries.rs:134:15
+   |
+LL |     vec![0u8].as_ptr();
+   |     --------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
new file mode 100644
index 00000000000..2b515d3e6d5
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs
@@ -0,0 +1,52 @@
+#![deny(dangling_pointers_from_temporaries)]
+
+use std::cell::Cell;
+use std::ffi::{CStr, CString};
+use std::mem::MaybeUninit;
+
+struct AsPtrFake;
+
+impl AsPtrFake {
+    fn as_ptr(&self) -> *const () {
+        std::ptr::null()
+    }
+}
+
+fn declval<T>() -> T {
+    loop {}
+}
+
+fn main() {
+    declval::<CString>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped
+    declval::<String>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped
+    declval::<Vec<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+    declval::<Box<CString>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+    declval::<Box<[u8]>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+    declval::<Box<str>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+    declval::<Box<CStr>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+    declval::<[u8; 10]>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+    declval::<Box<[u8; 10]>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+    declval::<Box<Vec<u8>>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+    declval::<Box<String>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+    declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+    declval::<Cell<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+    declval::<MaybeUninit<u8>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+    declval::<Vec<AsPtrFake>>().as_ptr();
+    //~^ ERROR a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+    declval::<Box<AsPtrFake>>().as_ptr();
+    declval::<AsPtrFake>().as_ptr();
+}
diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
new file mode 100644
index 00000000000..c582a4c6540
--- /dev/null
+++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr
@@ -0,0 +1,172 @@
+error: a dangling pointer will be produced because the temporary `CString` will be dropped
+  --> $DIR/types.rs:20:26
+   |
+LL |     declval::<CString>().as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+note: the lint level is defined here
+  --> $DIR/types.rs:1:9
+   |
+LL | #![deny(dangling_pointers_from_temporaries)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: a dangling pointer will be produced because the temporary `String` will be dropped
+  --> $DIR/types.rs:22:25
+   |
+LL |     declval::<String>().as_ptr();
+   |     ------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped
+  --> $DIR/types.rs:24:26
+   |
+LL |     declval::<Vec<u8>>().as_ptr();
+   |     -------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped
+  --> $DIR/types.rs:26:31
+   |
+LL |     declval::<Box<CString>>().as_ptr();
+   |     ------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped
+  --> $DIR/types.rs:28:28
+   |
+LL |     declval::<Box<[u8]>>().as_ptr();
+   |     ---------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped
+  --> $DIR/types.rs:30:27
+   |
+LL |     declval::<Box<str>>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped
+  --> $DIR/types.rs:32:28
+   |
+LL |     declval::<Box<CStr>>().as_ptr();
+   |     ---------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped
+  --> $DIR/types.rs:34:27
+   |
+LL |     declval::<[u8; 10]>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped
+  --> $DIR/types.rs:36:32
+   |
+LL |     declval::<Box<[u8; 10]>>().as_ptr();
+   |     -------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped
+  --> $DIR/types.rs:38:31
+   |
+LL |     declval::<Box<Vec<u8>>>().as_ptr();
+   |     ------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped
+  --> $DIR/types.rs:40:30
+   |
+LL |     declval::<Box<String>>().as_ptr();
+   |     ------------------------ ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped
+  --> $DIR/types.rs:42:43
+   |
+LL |     declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr();
+   |     ------------------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped
+  --> $DIR/types.rs:44:27
+   |
+LL |     declval::<Cell<u8>>().as_ptr();
+   |     --------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped
+  --> $DIR/types.rs:46:34
+   |
+LL |     declval::<MaybeUninit<u8>>().as_ptr();
+   |     ---------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped
+  --> $DIR/types.rs:48:33
+   |
+LL |     declval::<Vec<AsPtrFake>>().as_ptr();
+   |     --------------------------- ^^^^^^ this pointer will immediately be invalid
+   |     |
+   |     this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+   |
+   = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+   = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html>
+
+error: aborting due to 15 previous errors
+
diff --git a/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
new file mode 100644
index 00000000000..08d6733d3e2
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/auxiliary/multi_file_submod.rs
@@ -0,0 +1,10 @@
+// Submodule file used by test `../multi-file.rs`.
+
+// Keywords reserved from Rust 2018:
+fn async() {}
+fn await() {}
+fn try() {}
+fn dyn() {}
+
+// Keywords reserved from Rust 2024:
+fn gen() {}
diff --git a/tests/ui/lint/keyword-idents/multi-file.rs b/tests/ui/lint/keyword-idents/multi-file.rs
new file mode 100644
index 00000000000..703e13f9ef6
--- /dev/null
+++ b/tests/ui/lint/keyword-idents/multi-file.rs
@@ -0,0 +1,14 @@
+#![deny(keyword_idents)] // Should affect the submodule, but doesn't.
+//@ edition: 2015
+//@ known-bug: #132218
+//@ check-pass (known bug; should be check-fail)
+
+// Because `keyword_idents_2018` and `keyword_idents_2024` are pre-expansion
+// lints, configuring them via lint attributes doesn't propagate to submodules
+// in other files.
+// <https://github.com/rust-lang/rust/issues/132218>
+
+#[path = "./auxiliary/multi_file_submod.rs"]
+mod multi_file_submod;
+
+fn main() {}
diff --git a/tests/ui/lint/lint-temporary-cstring-as-param.stderr b/tests/ui/lint/lint-temporary-cstring-as-param.stderr
deleted file mode 100644
index 7aa21f2560c..00000000000
--- a/tests/ui/lint/lint-temporary-cstring-as-param.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: getting the inner pointer of a temporary `CString`
-  --> $DIR/lint-temporary-cstring-as-param.rs:9:45
-   |
-LL |     some_function(CString::new("").unwrap().as_ptr());
-   |                   ------------------------- ^^^^^^ this pointer will be invalid
-   |                   |
-   |                   this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
-   |
-   = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
-   = help: for more information, see https://doc.rust-lang.org/reference/destructors.html
-note: the lint level is defined here
-  --> $DIR/lint-temporary-cstring-as-param.rs:1:9
-   |
-LL | #![deny(temporary_cstring_as_ptr)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.cdylib_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.dylib_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.lib_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.proc_macro_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rlib_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs
index 097b246c165..6f701cd27c6 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs
@@ -10,10 +10,17 @@
 
 // But should fire on non-binary crates.
 
-//@[cdylib_] ignore-musl (dylibs are not supported)
-//@[dylib_] ignore-musl (dylibs are not supported)
-//@[dylib_] ignore-wasm (dylib is not supported)
-//@[proc_macro_] ignore-wasm (dylib is not supported)
+// FIXME(#132309): dylib crate type is not supported on wasm; we need a proper
+// supports-crate-type directive. Also, needs-dynamic-linking should rule out
+// musl since it supports neither dylibs nor cdylibs.
+//@[dylib_] ignore-wasm
+//@[dylib_] ignore-musl
+//@[cdylib_] ignore-musl
+
+//@[dylib_] needs-dynamic-linking
+//@[cdylib_] needs-dynamic-linking
+//@[proc_macro_] force-host
+//@[proc_macro_] no-prefer-dynamic
 
 //@[cdylib_] compile-flags: --crate-type=cdylib
 //@[dylib_] compile-flags: --crate-type=dylib
diff --git a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr
index 140d72b9742..1192b690e29 100644
--- a/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr
+++ b/tests/ui/lint/non-snake-case/lint-non-snake-case-crate.staticlib_.stderr
@@ -1,11 +1,11 @@
 error: crate `NonSnakeCase` should have a snake case name
-  --> $DIR/lint-non-snake-case-crate.rs:29:18
+  --> $DIR/lint-non-snake-case-crate.rs:36:18
    |
 LL | #![crate_name = "NonSnakeCase"]
    |                  ^^^^^^^^^^^^ help: convert the identifier to snake case: `non_snake_case`
    |
 note: the lint level is defined here
-  --> $DIR/lint-non-snake-case-crate.rs:31:9
+  --> $DIR/lint-non-snake-case-crate.rs:38:9
    |
 LL | #![deny(non_snake_case)]
    |         ^^^^^^^^^^^^^^
diff --git a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
index 1e73320e439..7582c8e8659 100644
--- a/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
+++ b/tests/ui/macros/assert-trailing-junk.with-generic-asset.stderr
@@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some`
 LL |     assert!(true some extra junk);
    |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:15:30
    |
 LL |     assert!(true, "whatever" blah);
@@ -28,7 +28,7 @@ LL |     assert!(true "whatever" blah);
    |                 |
    |                 help: try adding a comma
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:18:29
    |
 LL |     assert!(true "whatever" blah);
diff --git a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
index 1e73320e439..7582c8e8659 100644
--- a/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
+++ b/tests/ui/macros/assert-trailing-junk.without-generic-asset.stderr
@@ -10,7 +10,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some`
 LL |     assert!(true some extra junk);
    |                  ^^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:15:30
    |
 LL |     assert!(true, "whatever" blah);
@@ -28,7 +28,7 @@ LL |     assert!(true "whatever" blah);
    |                 |
    |                 help: try adding a comma
 
-error: no rules expected the token `blah`
+error: no rules expected `blah`
   --> $DIR/assert-trailing-junk.rs:18:29
    |
 LL |     assert!(true "whatever" blah);
diff --git a/tests/ui/macros/best-failure.rs b/tests/ui/macros/best-failure.rs
index bbdd465d5ec..1b73066c874 100644
--- a/tests/ui/macros/best-failure.rs
+++ b/tests/ui/macros/best-failure.rs
@@ -2,7 +2,7 @@ macro_rules! number {
     (neg false, $self:ident) => { $self };
     ($signed:tt => $ty:ty;) => {
         number!(neg $signed, $self);
-        //~^ ERROR no rules expected the token `$`
+        //~^ ERROR no rules expected `$`
     };
 }
 
diff --git a/tests/ui/macros/best-failure.stderr b/tests/ui/macros/best-failure.stderr
index c5f8b9abc19..914ff7fd820 100644
--- a/tests/ui/macros/best-failure.stderr
+++ b/tests/ui/macros/best-failure.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `$`
+error: no rules expected `$`
   --> $DIR/best-failure.rs:4:30
    |
 LL | macro_rules! number {
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
index 22d662aaaf2..bf7eb3888b3 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021`
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:24:12
    |
 LL | macro_rules! m2024 {
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
index 2555e4f757a..1028ddc4267 100644
--- a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `const`
+error: no rules expected keyword `const`
   --> $DIR/expr_2021_inline_const.rs:23:12
    |
 LL | macro_rules! m2021 {
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
index 39a542fe4d9..312256f1879 100644
--- a/tests/ui/macros/expr_2021_inline_const.rs
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -20,8 +20,8 @@ macro_rules! test {
 }
 
 fn main() {
-    m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
-    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
+    m2021!(const { 1 }); //~ ERROR: no rules expected keyword `const`
+    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected keyword `const`
 
     test!(expr);
 }
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
index 34df20a69ef..7b3ca54bb71 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2021.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$e:expr_2021`
 LL |     ($e:expr_2021) => {
    |      ^^^^^^^^^^^^
 
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:20:12
    |
 LL | macro_rules! m2024 {
diff --git a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
index 372c5d8637c..59104dafa18 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
+++ b/tests/ui/macros/expr_2024_underscore_expr.edi2024.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/expr_2024_underscore_expr.rs:19:12
    |
 LL | macro_rules! m2021 {
diff --git a/tests/ui/macros/expr_2024_underscore_expr.rs b/tests/ui/macros/expr_2024_underscore_expr.rs
index 86e31374506..6f8ec139109 100644
--- a/tests/ui/macros/expr_2024_underscore_expr.rs
+++ b/tests/ui/macros/expr_2024_underscore_expr.rs
@@ -16,6 +16,6 @@ macro_rules! m2024 {
 }
 
 fn main() {
-    m2021!(_); //~ ERROR: no rules expected the token `_`
-    m2024!(_); //[edi2021]~ ERROR: no rules expected the token `_`
+    m2021!(_); //~ ERROR: no rules expected reserved identifier `_`
+    m2024!(_); //[edi2021]~ ERROR: no rules expected reserved identifier `_`
 }
diff --git a/tests/ui/macros/issue-118786.rs b/tests/ui/macros/issue-118786.rs
index a41372e4ea8..a73b737fe07 100644
--- a/tests/ui/macros/issue-118786.rs
+++ b/tests/ui/macros/issue-118786.rs
@@ -5,7 +5,7 @@
 macro_rules! make_macro {
     ($macro_name:tt) => {
         macro_rules! $macro_name {
-        //~^ ERROR macro expansion ignores token `{` and any following
+        //~^ ERROR macro expansion ignores `{` and any tokens following
         //~| ERROR cannot find macro `macro_rules` in this scope
         //~| put a macro name here
             () => {}
diff --git a/tests/ui/macros/issue-118786.stderr b/tests/ui/macros/issue-118786.stderr
index 256b742ee16..7fa5c2b83dd 100644
--- a/tests/ui/macros/issue-118786.stderr
+++ b/tests/ui/macros/issue-118786.stderr
@@ -13,7 +13,7 @@ help: add a semicolon
 LL |         macro_rules! $macro_name; {
    |                                 +
 
-error: macro expansion ignores token `{` and any following
+error: macro expansion ignores `{` and any tokens following
   --> $DIR/issue-118786.rs:7:34
    |
 LL |         macro_rules! $macro_name {
diff --git a/tests/ui/macros/issue-30007.rs b/tests/ui/macros/issue-30007.rs
index 918a821bae9..e36e47a3e7c 100644
--- a/tests/ui/macros/issue-30007.rs
+++ b/tests/ui/macros/issue-30007.rs
@@ -1,5 +1,5 @@
 macro_rules! t {
-    () => ( String ; );     //~ ERROR macro expansion ignores token `;`
+    () => ( String ; );     //~ ERROR macro expansion ignores `;`
 }
 
 fn main() {
diff --git a/tests/ui/macros/issue-30007.stderr b/tests/ui/macros/issue-30007.stderr
index f303221cf8a..129733ed69a 100644
--- a/tests/ui/macros/issue-30007.stderr
+++ b/tests/ui/macros/issue-30007.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/issue-30007.rs:2:20
    |
 LL |     () => ( String ; );
diff --git a/tests/ui/macros/issue-54441.rs b/tests/ui/macros/issue-54441.rs
index b24d7e1f6be..37ab4e63647 100644
--- a/tests/ui/macros/issue-54441.rs
+++ b/tests/ui/macros/issue-54441.rs
@@ -1,6 +1,6 @@
 macro_rules! m {
     () => {
-        let //~ ERROR macro expansion ignores token `let` and any following
+        let //~ ERROR macro expansion ignores keyword `let` and any tokens following
     };
 }
 
diff --git a/tests/ui/macros/issue-54441.stderr b/tests/ui/macros/issue-54441.stderr
index fb2c103139b..f5f8b8ca2b2 100644
--- a/tests/ui/macros/issue-54441.stderr
+++ b/tests/ui/macros/issue-54441.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `let` and any following
+error: macro expansion ignores keyword `let` and any tokens following
   --> $DIR/issue-54441.rs:3:9
    |
 LL |         let
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.rs b/tests/ui/macros/macro-at-most-once-rep-2015.rs
index 8f2531a25ae..08967b82531 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2015.rs
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.rs
@@ -22,21 +22,21 @@ macro_rules! barstar {
 pub fn main() {
     foo!();
     foo!(a);
-    foo!(a?); //~ ERROR no rules expected the token `?`
-    foo!(a?a); //~ ERROR no rules expected the token `?`
-    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?); //~ ERROR no rules expected `?`
+    foo!(a?a); //~ ERROR no rules expected `?`
+    foo!(a?a?a); //~ ERROR no rules expected `?`
 
     barplus!(); //~ERROR unexpected end of macro invocation
     barplus!(a); //~ERROR unexpected end of macro invocation
-    barplus!(a?); //~ ERROR no rules expected the token `?`
-    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a?); //~ ERROR no rules expected `?`
+    barplus!(a?a); //~ ERROR no rules expected `?`
     barplus!(a+);
     barplus!(+);
 
     barstar!(); //~ERROR unexpected end of macro invocation
     barstar!(a); //~ERROR unexpected end of macro invocation
-    barstar!(a?); //~ ERROR no rules expected the token `?`
-    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a?); //~ ERROR no rules expected `?`
+    barstar!(a?a); //~ ERROR no rules expected `?`
     barstar!(a*);
     barstar!(*);
 }
diff --git a/tests/ui/macros/macro-at-most-once-rep-2015.stderr b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
index 7c45b85bc8d..7f161cdc8d0 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2015.stderr
+++ b/tests/ui/macros/macro-at-most-once-rep-2015.stderr
@@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator
 LL |     ($(a),?) => {};
    |          ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:25:11
    |
 LL | macro_rules! foo {
@@ -15,7 +15,7 @@ LL |     foo!(a?);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:26:11
    |
 LL | macro_rules! foo {
@@ -26,7 +26,7 @@ LL |     foo!(a?a);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:27:11
    |
 LL | macro_rules! foo {
@@ -67,7 +67,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:31:15
    |
 LL | macro_rules! barplus {
@@ -82,7 +82,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:32:15
    |
 LL | macro_rules! barplus {
@@ -127,7 +127,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:38:15
    |
 LL | macro_rules! barstar {
@@ -142,7 +142,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2015.rs:39:15
    |
 LL | macro_rules! barstar {
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.rs b/tests/ui/macros/macro-at-most-once-rep-2018.rs
index 7f43055ded6..98fbb2ad207 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2018.rs
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.rs
@@ -22,21 +22,21 @@ macro_rules! barstar {
 pub fn main() {
     foo!();
     foo!(a);
-    foo!(a?); //~ ERROR no rules expected the token `?`
-    foo!(a?a); //~ ERROR no rules expected the token `?`
-    foo!(a?a?a); //~ ERROR no rules expected the token `?`
+    foo!(a?); //~ ERROR no rules expected `?`
+    foo!(a?a); //~ ERROR no rules expected `?`
+    foo!(a?a?a); //~ ERROR no rules expected `?`
 
     barplus!(); //~ERROR unexpected end of macro invocation
     barplus!(a); //~ERROR unexpected end of macro invocation
-    barplus!(a?); //~ ERROR no rules expected the token `?`
-    barplus!(a?a); //~ ERROR no rules expected the token `?`
+    barplus!(a?); //~ ERROR no rules expected `?`
+    barplus!(a?a); //~ ERROR no rules expected `?`
     barplus!(a+);
     barplus!(+);
 
     barstar!(); //~ERROR unexpected end of macro invocation
     barstar!(a); //~ERROR unexpected end of macro invocation
-    barstar!(a?); //~ ERROR no rules expected the token `?`
-    barstar!(a?a); //~ ERROR no rules expected the token `?`
+    barstar!(a?); //~ ERROR no rules expected `?`
+    barstar!(a?a); //~ ERROR no rules expected `?`
     barstar!(a*);
     barstar!(*);
 }
diff --git a/tests/ui/macros/macro-at-most-once-rep-2018.stderr b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
index 696520b2826..f165a199b10 100644
--- a/tests/ui/macros/macro-at-most-once-rep-2018.stderr
+++ b/tests/ui/macros/macro-at-most-once-rep-2018.stderr
@@ -4,7 +4,7 @@ error: the `?` macro repetition operator does not take a separator
 LL |     ($(a),?) => {};
    |          ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:25:11
    |
 LL | macro_rules! foo {
@@ -15,7 +15,7 @@ LL |     foo!(a?);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:26:11
    |
 LL | macro_rules! foo {
@@ -26,7 +26,7 @@ LL |     foo!(a?a);
    |
    = note: while trying to match sequence end
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:27:11
    |
 LL | macro_rules! foo {
@@ -67,7 +67,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:31:15
    |
 LL | macro_rules! barplus {
@@ -82,7 +82,7 @@ note: while trying to match `+`
 LL |     ($(a)?+) => {}; // ok. matches "a+" and "+"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:32:15
    |
 LL | macro_rules! barplus {
@@ -127,7 +127,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:38:15
    |
 LL | macro_rules! barstar {
@@ -142,7 +142,7 @@ note: while trying to match `*`
 LL |     ($(a)?*) => {}; // ok. matches "a*" and "*"
    |           ^
 
-error: no rules expected the token `?`
+error: no rules expected `?`
   --> $DIR/macro-at-most-once-rep-2018.rs:39:15
    |
 LL | macro_rules! barstar {
diff --git a/tests/ui/macros/macro-context.rs b/tests/ui/macros/macro-context.rs
index d09fdf118e6..a31470263a0 100644
--- a/tests/ui/macros/macro-context.rs
+++ b/tests/ui/macros/macro-context.rs
@@ -1,9 +1,9 @@
 // (typeof used because it's surprisingly hard to find an unparsed token after a stmt)
 macro_rules! m {
     () => ( i ; typeof );   //~ ERROR expected expression, found reserved keyword `typeof`
-                            //~| ERROR macro expansion ignores token `typeof`
-                            //~| ERROR macro expansion ignores token `;`
-                            //~| ERROR macro expansion ignores token `;`
+                            //~| ERROR macro expansion ignores reserved keyword `typeof`
+                            //~| ERROR macro expansion ignores `;`
+                            //~| ERROR macro expansion ignores `;`
                             //~| ERROR cannot find type `i` in this scope
                             //~| ERROR cannot find value `i` in this scope
                             //~| WARN trailing semicolon in macro
diff --git a/tests/ui/macros/macro-context.stderr b/tests/ui/macros/macro-context.stderr
index 7785f415946..4820a43f00c 100644
--- a/tests/ui/macros/macro-context.stderr
+++ b/tests/ui/macros/macro-context.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/macro-context.rs:3:15
    |
 LL |     () => ( i ; typeof );
@@ -9,7 +9,7 @@ LL |     let a: m!();
    |
    = note: the usage of `m!` is likely invalid in type context
 
-error: macro expansion ignores token `typeof` and any following
+error: macro expansion ignores reserved keyword `typeof` and any tokens following
   --> $DIR/macro-context.rs:3:17
    |
 LL |     () => ( i ; typeof );
@@ -20,7 +20,7 @@ LL |     let i = m!();
    |
    = note: the usage of `m!` is likely invalid in expression context
 
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/macro-context.rs:3:15
    |
 LL |     () => ( i ; typeof );
diff --git a/tests/ui/macros/macro-in-expression-context.fixed b/tests/ui/macros/macro-in-expression-context.fixed
index f4d04ca37bf..7c830707ffd 100644
--- a/tests/ui/macros/macro-in-expression-context.fixed
+++ b/tests/ui/macros/macro-in-expression-context.fixed
@@ -11,7 +11,7 @@ macro_rules! foo {
         //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
         assert_eq!("B", "B");
     }
-    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
     //~| NOTE the usage of `foo!` is likely invalid in expression context
 }
 
diff --git a/tests/ui/macros/macro-in-expression-context.rs b/tests/ui/macros/macro-in-expression-context.rs
index 8921a056377..da95017aa5f 100644
--- a/tests/ui/macros/macro-in-expression-context.rs
+++ b/tests/ui/macros/macro-in-expression-context.rs
@@ -11,7 +11,7 @@ macro_rules! foo {
         //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default
         assert_eq!("B", "B");
     }
-    //~^^ ERROR macro expansion ignores token `assert_eq` and any following
+    //~^^ ERROR macro expansion ignores `assert_eq` and any tokens following
     //~| NOTE the usage of `foo!` is likely invalid in expression context
 }
 
diff --git a/tests/ui/macros/macro-in-expression-context.stderr b/tests/ui/macros/macro-in-expression-context.stderr
index 2eee63f307a..43419f2678c 100644
--- a/tests/ui/macros/macro-in-expression-context.stderr
+++ b/tests/ui/macros/macro-in-expression-context.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `assert_eq` and any following
+error: macro expansion ignores `assert_eq` and any tokens following
   --> $DIR/macro-in-expression-context.rs:12:9
    |
 LL |         assert_eq!("B", "B");
diff --git a/tests/ui/macros/macro-non-lifetime.rs b/tests/ui/macros/macro-non-lifetime.rs
index 26e1f2afa91..3defffd2960 100644
--- a/tests/ui/macros/macro-non-lifetime.rs
+++ b/tests/ui/macros/macro-non-lifetime.rs
@@ -4,5 +4,5 @@ macro_rules! m { ($x:lifetime) => { } }
 
 fn main() {
     m!(a);
-    //~^ ERROR no rules expected the token `a`
+    //~^ ERROR no rules expected `a`
 }
diff --git a/tests/ui/macros/macro-non-lifetime.stderr b/tests/ui/macros/macro-non-lifetime.stderr
index 9ff3d741c01..35040a2229b 100644
--- a/tests/ui/macros/macro-non-lifetime.stderr
+++ b/tests/ui/macros/macro-non-lifetime.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `a`
+error: no rules expected `a`
   --> $DIR/macro-non-lifetime.rs:6:8
    |
 LL | macro_rules! m { ($x:lifetime) => { } }
diff --git a/tests/ui/macros/missing-comma.rs b/tests/ui/macros/missing-comma.rs
index 92f8a779505..64cfb0db31a 100644
--- a/tests/ui/macros/missing-comma.rs
+++ b/tests/ui/macros/missing-comma.rs
@@ -19,16 +19,16 @@ fn main() {
     println!("{}" a);
     //~^ ERROR expected `,`, found `a`
     foo!(a b);
-    //~^ ERROR no rules expected the token `b`
+    //~^ ERROR no rules expected `b`
     foo!(a, b, c, d e);
-    //~^ ERROR no rules expected the token `e`
+    //~^ ERROR no rules expected `e`
     foo!(a, b, c d, e);
-    //~^ ERROR no rules expected the token `d`
+    //~^ ERROR no rules expected `d`
     foo!(a, b, c d e);
-    //~^ ERROR no rules expected the token `d`
+    //~^ ERROR no rules expected `d`
     bar!(Level::Error, );
     //~^ ERROR unexpected end of macro invocation
     check!(<str as Debug>::fmt, "fmt");
     check!(<str as Debug>::fmt, "fmt",);
-    //~^ ERROR no rules expected the token `,`
+    //~^ ERROR no rules expected `,`
 }
diff --git a/tests/ui/macros/missing-comma.stderr b/tests/ui/macros/missing-comma.stderr
index 81877a29ed8..9913ba34919 100644
--- a/tests/ui/macros/missing-comma.stderr
+++ b/tests/ui/macros/missing-comma.stderr
@@ -4,7 +4,7 @@ error: expected `,`, found `a`
 LL |     println!("{}" a);
    |                   ^ expected `,`
 
-error: no rules expected the token `b`
+error: no rules expected `b`
   --> $DIR/missing-comma.rs:21:12
    |
 LL | macro_rules! foo {
@@ -21,7 +21,7 @@ note: while trying to match meta-variable `$a:ident`
 LL |     ($a:ident) => ();
    |      ^^^^^^^^
 
-error: no rules expected the token `e`
+error: no rules expected `e`
   --> $DIR/missing-comma.rs:23:21
    |
 LL | macro_rules! foo {
@@ -38,7 +38,7 @@ note: while trying to match meta-variable `$d:ident`
 LL |     ($a:ident, $b:ident, $c:ident, $d:ident) => ();
    |                                    ^^^^^^^^
 
-error: no rules expected the token `d`
+error: no rules expected `d`
   --> $DIR/missing-comma.rs:25:18
    |
 LL | macro_rules! foo {
@@ -55,7 +55,7 @@ note: while trying to match meta-variable `$c:ident`
 LL |     ($a:ident, $b:ident, $c:ident) => ();
    |                          ^^^^^^^^
 
-error: no rules expected the token `d`
+error: no rules expected `d`
   --> $DIR/missing-comma.rs:27:18
    |
 LL | macro_rules! foo {
@@ -85,7 +85,7 @@ note: while trying to match meta-variable `$arg:tt`
 LL |     ($lvl:expr, $($arg:tt)+) => {}
    |                   ^^^^^^^
 
-error: no rules expected the token `,`
+error: no rules expected `,`
   --> $DIR/missing-comma.rs:32:38
    |
 LL | macro_rules! check {
diff --git a/tests/ui/macros/nonterminal-matching.rs b/tests/ui/macros/nonterminal-matching.rs
index 5f0d6b2f90e..a655b665103 100644
--- a/tests/ui/macros/nonterminal-matching.rs
+++ b/tests/ui/macros/nonterminal-matching.rs
@@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) {
         struct S;
     }
 
-    n!(a $nt_item b); //~ ERROR no rules expected the token `enum E {}`
+    n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}`
 }
 
 simple_nonterminal!(a, 'a, (x, y, z)); // OK
@@ -29,10 +29,10 @@ macro_rules! foo {
     (ident $x:ident) => { bar!(ident $x); };
     (lifetime $x:lifetime) => { bar!(lifetime $x); };
     (tt $x:tt) => { bar!(tt $x); };
-    (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected the token `3`
-    (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected the token `4`
-    (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected the token `a::b::c`
-    (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected the token `let abc = 0`
+    (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3`
+    (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4`
+    (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected path `a::b::c`
+    (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0`
 }
 
 macro_rules! bar {
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
index 3ee88b5f52e..e283dfcb8fd 100644
--- a/tests/ui/macros/nonterminal-matching.stderr
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `enum E {}`
+error: no rules expected item `enum E {}`
   --> $DIR/nonterminal-matching.rs:19:10
    |
 LL |     macro n(a $nt_item b) {
@@ -10,7 +10,7 @@ LL |     n!(a $nt_item b);
 LL | complex_nonterminal!(enum E {});
    | ------------------------------- in this macro invocation
    |
-note: while trying to match `enum E {}`
+note: while trying to match item `enum E {}`
   --> $DIR/nonterminal-matching.rs:15:15
    |
 LL |     macro n(a $nt_item b) {
@@ -23,7 +23,7 @@ LL | complex_nonterminal!(enum E {});
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `3`
+error: no rules expected expression `3`
   --> $DIR/nonterminal-matching.rs:32:35
    |
 LL |     (expr $x:expr) => { bar!(expr $x); };
@@ -45,7 +45,7 @@ LL |     (expr 3) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `4`
+error: no rules expected literal `4`
   --> $DIR/nonterminal-matching.rs:33:44
    |
 LL |     (literal $x:literal) => { bar!(literal $x); };
@@ -67,7 +67,7 @@ LL |     (literal 4) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `a::b::c`
+error: no rules expected path `a::b::c`
   --> $DIR/nonterminal-matching.rs:34:35
    |
 LL |     (path $x:path) => { bar!(path $x); };
@@ -89,7 +89,7 @@ LL |     (path a::b::c) => {};
    = help: try using `:tt` instead in the macro definition
    = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: no rules expected the token `let abc = 0`
+error: no rules expected statement `let abc = 0`
   --> $DIR/nonterminal-matching.rs:35:35
    |
 LL |     (stmt $x:stmt) => { bar!(stmt $x); };
@@ -101,7 +101,7 @@ LL | macro_rules! bar {
 LL | foo!(stmt let abc = 0);
    | ---------------------- in this macro invocation
    |
-note: while trying to match `let`
+note: while trying to match keyword `let`
   --> $DIR/nonterminal-matching.rs:45:11
    |
 LL |     (stmt let abc = 0) => {};
diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs
index f6178c137db..016e4def284 100644
--- a/tests/ui/macros/syntax-error-recovery.rs
+++ b/tests/ui/macros/syntax-error-recovery.rs
@@ -10,7 +10,7 @@ macro_rules! values {
     };
 }
 //~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found type `(String)`
-//~| ERROR macro expansion ignores token `(String)` and any following
+//~| ERROR macro expansion ignores type `(String)` and any tokens following
 
 values!(STRING(1) as (String) => cfg(test),);
 //~^ ERROR expected one of `!` or `::`, found `<eof>`
diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr
index 6218bf43a1e..3cfbd8ce82b 100644
--- a/tests/ui/macros/syntax-error-recovery.stderr
+++ b/tests/ui/macros/syntax-error-recovery.stderr
@@ -10,7 +10,7 @@ LL | values!(STRING(1) as (String) => cfg(test),);
    = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
    = note: this error originates in the macro `values` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro expansion ignores token `(String)` and any following
+error: macro expansion ignores type `(String)` and any tokens following
   --> $DIR/syntax-error-recovery.rs:7:26
    |
 LL |                 $token $($inner)? = $value,
diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr
index 66d7b76bb07..10ad3faab16 100644
--- a/tests/ui/macros/trace_faulty_macros.stderr
+++ b/tests/ui/macros/trace_faulty_macros.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `bcd`
+error: no rules expected `bcd`
   --> $DIR/trace_faulty_macros.rs:7:26
    |
 LL | macro_rules! my_faulty_macro {
diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs
index daf0a62fc85..92199625207 100644
--- a/tests/ui/mir/mir_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_let_chains_drop_order.rs
@@ -8,7 +8,6 @@
 // See `mir_drop_order.rs` for more information
 
 #![feature(let_chains)]
-#![cfg_attr(edition2024, feature(if_let_rescope))]
 #![allow(irrefutable_let_patterns)]
 
 use std::cell::RefCell;
diff --git a/tests/ui/modules/issue-107649.stderr b/tests/ui/modules/issue-107649.stderr
index d5405c6576a..0d203c1aacb 100644
--- a/tests/ui/modules/issue-107649.stderr
+++ b/tests/ui/modules/issue-107649.stderr
@@ -4,7 +4,7 @@ error[E0277]: `Dummy` doesn't implement `Debug`
 105 |     dbg!(lib::Dummy);
     |     ^^^^^^^^^^^^^^^^ `Dummy` cannot be formatted using `{:?}`
     |
-    = help: the trait `Debug` is not implemented for `Dummy`, which is required by `&Dummy: Debug`
+    = help: the trait `Debug` is not implemented for `Dummy`
     = note: add `#[derive(Debug)]` to `Dummy` or manually `impl Debug for Dummy`
     = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `Dummy` with `#[derive(Debug)]`
diff --git a/tests/ui/mut/mutable-enum-indirect.stderr b/tests/ui/mut/mutable-enum-indirect.stderr
index d7af327df5a..0b7783b3318 100644
--- a/tests/ui/mut/mutable-enum-indirect.stderr
+++ b/tests/ui/mut/mutable-enum-indirect.stderr
@@ -6,7 +6,7 @@ LL |     bar(&x);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `&Foo: Sync`
+   = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`
 note: required because it appears within the type `Foo`
   --> $DIR/mutable-enum-indirect.rs:11:6
    |
diff --git a/tests/ui/nll/issue-54556-niconii.edition2021.stderr b/tests/ui/nll/issue-54556-niconii.edition2021.stderr
index 31a03abbc98..abee09ed950 100644
--- a/tests/ui/nll/issue-54556-niconii.edition2021.stderr
+++ b/tests/ui/nll/issue-54556-niconii.edition2021.stderr
@@ -1,5 +1,5 @@
 error[E0597]: `counter` does not live long enough
-  --> $DIR/issue-54556-niconii.rs:30:20
+  --> $DIR/issue-54556-niconii.rs:28:20
    |
 LL |     let counter = Mutex;
    |         ------- binding `counter` declared here
diff --git a/tests/ui/nll/issue-54556-niconii.rs b/tests/ui/nll/issue-54556-niconii.rs
index 1a7ad17cc84..f01e0523cbf 100644
--- a/tests/ui/nll/issue-54556-niconii.rs
+++ b/tests/ui/nll/issue-54556-niconii.rs
@@ -12,8 +12,6 @@
 //@ [edition2024] compile-flags: -Z unstable-options
 //@ [edition2024] check-pass
 
-#![cfg_attr(edition2024, feature(if_let_rescope))]
-
 struct Mutex;
 struct MutexGuard<'a>(&'a Mutex);
 
diff --git a/tests/ui/no-send-res-ports.stderr b/tests/ui/no-send-res-ports.stderr
index c71d8ecba37..9c30261e5cb 100644
--- a/tests/ui/no-send-res-ports.stderr
+++ b/tests/ui/no-send-res-ports.stderr
@@ -13,7 +13,7 @@ LL | |         println!("{:?}", y);
 LL | |     });
    | |_____^ `Rc<()>` cannot be sent between threads safely
    |
-   = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>`, which is required by `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}: Send`
+   = help: within `{closure@$DIR/no-send-res-ports.rs:25:19: 25:25}`, the trait `Send` is not implemented for `Rc<()>`
 note: required because it appears within the type `Port<()>`
   --> $DIR/no-send-res-ports.rs:5:8
    |
diff --git a/tests/ui/no_send-enum.stderr b/tests/ui/no_send-enum.stderr
index e24f79c7dd6..3b66c7db545 100644
--- a/tests/ui/no_send-enum.stderr
+++ b/tests/ui/no_send-enum.stderr
@@ -6,7 +6,7 @@ LL |     bar(x);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Foo`, the trait `Send` is not implemented for `NoSend`, which is required by `Foo: Send`
+   = help: within `Foo`, the trait `Send` is not implemented for `NoSend`
 note: required because it appears within the type `Foo`
   --> $DIR/no_send-enum.rs:8:6
    |
diff --git a/tests/ui/no_share-enum.stderr b/tests/ui/no_share-enum.stderr
index 5b6c8bf0b4f..89939216d5b 100644
--- a/tests/ui/no_share-enum.stderr
+++ b/tests/ui/no_share-enum.stderr
@@ -6,7 +6,7 @@ LL |     bar(x);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Foo`, the trait `Sync` is not implemented for `NoSync`, which is required by `Foo: Sync`
+   = help: within `Foo`, the trait `Sync` is not implemented for `NoSync`
 note: required because it appears within the type `Foo`
   --> $DIR/no_share-enum.rs:8:6
    |
diff --git a/tests/ui/not-clone-closure.stderr b/tests/ui/not-clone-closure.stderr
index 9b557b15582..783c165eeb2 100644
--- a/tests/ui/not-clone-closure.stderr
+++ b/tests/ui/not-clone-closure.stderr
@@ -5,7 +5,7 @@ LL |     let hello = move || {
    |                 ------- within this `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`
 ...
 LL |     let hello = hello.clone();
-   |                       ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S`, which is required by `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}: Clone`
+   |                       ^^^^^ within `{closure@$DIR/not-clone-closure.rs:7:17: 7:24}`, the trait `Clone` is not implemented for `S`
    |
 note: required because it's used within this closure
   --> $DIR/not-clone-closure.rs:7:17
diff --git a/tests/ui/not-panic/not-panic-safe-2.stderr b/tests/ui/not-panic/not-panic-safe-2.stderr
index 8c4cf9c98ed..0c399f15a25 100644
--- a/tests/ui/not-panic/not-panic-safe-2.stderr
+++ b/tests/ui/not-panic/not-panic-safe-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
 LL |     assert::<Rc<RefCell<i32>>>();
    |              ^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `Rc<RefCell<i32>>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
 note: required because it appears within the type `RefCell<i32>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
    = note: required for `Rc<RefCell<i32>>` to implement `UnwindSafe`
@@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a
 LL |     assert::<Rc<RefCell<i32>>>();
    |              ^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `Rc<RefCell<i32>>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`
 note: required because it appears within the type `Cell<isize>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
 note: required because it appears within the type `RefCell<i32>`
diff --git a/tests/ui/not-panic/not-panic-safe-3.stderr b/tests/ui/not-panic/not-panic-safe-3.stderr
index 2373ada63f6..53028d6a337 100644
--- a/tests/ui/not-panic/not-panic-safe-3.stderr
+++ b/tests/ui/not-panic/not-panic-safe-3.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
 LL |     assert::<Arc<RefCell<i32>>>();
    |              ^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `Arc<RefCell<i32>>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
 note: required because it appears within the type `RefCell<i32>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
    = note: required for `Arc<RefCell<i32>>` to implement `UnwindSafe`
@@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a
 LL |     assert::<Arc<RefCell<i32>>>();
    |              ^^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `Arc<RefCell<i32>>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`
 note: required because it appears within the type `Cell<isize>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
 note: required because it appears within the type `RefCell<i32>`
diff --git a/tests/ui/not-panic/not-panic-safe-4.stderr b/tests/ui/not-panic/not-panic-safe-4.stderr
index d77cac8f272..b1361cfd87e 100644
--- a/tests/ui/not-panic/not-panic-safe-4.stderr
+++ b/tests/ui/not-panic/not-panic-safe-4.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
 LL |     assert::<&RefCell<i32>>();
    |              ^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `&RefCell<i32>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
 note: required because it appears within the type `RefCell<i32>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
    = note: required for `&RefCell<i32>` to implement `UnwindSafe`
@@ -25,7 +25,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a
 LL |     assert::<&RefCell<i32>>();
    |              ^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `&RefCell<i32>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`
 note: required because it appears within the type `Cell<isize>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
 note: required because it appears within the type `RefCell<i32>`
diff --git a/tests/ui/not-panic/not-panic-safe-5.stderr b/tests/ui/not-panic/not-panic-safe-5.stderr
index 0de9a2cc0cd..fbbd81d6d4c 100644
--- a/tests/ui/not-panic/not-panic-safe-5.stderr
+++ b/tests/ui/not-panic/not-panic-safe-5.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
 LL |     assert::<*const UnsafeCell<i32>>();
    |              ^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `*const UnsafeCell<i32>: UnwindSafe`
+   = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
    = note: required for `*const UnsafeCell<i32>` to implement `UnwindSafe`
 note: required by a bound in `assert`
   --> $DIR/not-panic-safe-5.rs:6:14
diff --git a/tests/ui/not-panic/not-panic-safe-6.stderr b/tests/ui/not-panic/not-panic-safe-6.stderr
index 7714a577f8a..47f28257409 100644
--- a/tests/ui/not-panic/not-panic-safe-6.stderr
+++ b/tests/ui/not-panic/not-panic-safe-6.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `UnsafeCell<i32>` may contain interior mutability and a r
 LL |     assert::<*mut RefCell<i32>>();
    |              ^^^^^^^^^^^^^^^^^ `UnsafeCell<i32>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`, which is required by `*mut RefCell<i32>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<i32>`
 note: required because it appears within the type `RefCell<i32>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
    = note: required for `*mut RefCell<i32>` to implement `UnwindSafe`
@@ -20,7 +20,7 @@ error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a
 LL |     assert::<*mut RefCell<i32>>();
    |              ^^^^^^^^^^^^^^^^^ `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
    |
-   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`, which is required by `*mut RefCell<i32>: UnwindSafe`
+   = help: within `RefCell<i32>`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell<isize>`
 note: required because it appears within the type `Cell<isize>`
   --> $SRC_DIR/core/src/cell.rs:LL:COL
 note: required because it appears within the type `RefCell<i32>`
diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs
index c86e61a61a7..f4c8b91d7da 100644
--- a/tests/ui/offset-of/offset-of-arg-count.rs
+++ b/tests/ui/offset-of/offset-of-arg-count.rs
@@ -3,7 +3,7 @@ use std::mem::offset_of;
 fn main() {
     offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation
     offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation
-    offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too`
+    offset_of!(Container, field, too many arguments); //~ ERROR no rules expected `too`
     offset_of!(S, f); // compiles fine
     offset_of!(S, f,); // also compiles fine
     offset_of!(S, f.); //~ ERROR unexpected token: `)`
diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr
index 4cb24b3d034..0772bb18e0c 100644
--- a/tests/ui/offset-of/offset-of-arg-count.stderr
+++ b/tests/ui/offset-of/offset-of-arg-count.stderr
@@ -16,7 +16,7 @@ LL |     offset_of!(NotEnoughArgumentsWithAComma, );
 note: while trying to match meta-variable `$fields:expr`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
-error: no rules expected the token `too`
+error: no rules expected `too`
   --> $DIR/offset-of-arg-count.rs:6:34
    |
 LL |     offset_of!(Container, field, too many arguments);
diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr
index bcfe796897e..714bf7a0266 100644
--- a/tests/ui/offset-of/offset-of-dst-field.stderr
+++ b/tests/ui/offset-of/offset-of-dst-field.stderr
@@ -58,7 +58,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     offset_of!(Delta<Alpha>, z);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`, which is required by `Alpha: Sized`
+   = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `Alpha`
   --> $DIR/offset-of-dst-field.rs:5:8
    |
diff --git a/tests/ui/offset-of/offset-of-tuple.stderr b/tests/ui/offset-of/offset-of-tuple.stderr
index dd20859e04e..38ce49c9179 100644
--- a/tests/ui/offset-of/offset-of-tuple.stderr
+++ b/tests/ui/offset-of/offset-of-tuple.stderr
@@ -76,7 +76,7 @@ error: suffixes on a tuple index are invalid
 LL |     offset_of!((u8, u8), 1_u8);
    |                          ^^^^ invalid suffix `u8`
 
-error: no rules expected the token `+`
+error: no rules expected `+`
   --> $DIR/offset-of-tuple.rs:11:26
    |
 LL |     offset_of!((u8, u8), +1);
diff --git a/tests/ui/on-unimplemented/slice-index.stderr b/tests/ui/on-unimplemented/slice-index.stderr
index 0f8d105abef..d53ecb9db0c 100644
--- a/tests/ui/on-unimplemented/slice-index.stderr
+++ b/tests/ui/on-unimplemented/slice-index.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32`
 LL |     x[1i32];
    |       ^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[i32]>` is not implemented for `i32`, which is required by `[i32]: Index<_>`
+   = help: the trait `SliceIndex<[i32]>` is not implemented for `i32`
    = help: the trait `SliceIndex<[i32]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `i32`
    = note: required for `[i32]` to implement `Index<i32>`
@@ -15,7 +15,7 @@ error[E0277]: the type `[i32]` cannot be indexed by `RangeTo<i32>`
 LL |     x[..1i32];
    |       ^^^^^^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo<i32>`, which is required by `[i32]: Index<_>`
+   = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo<i32>`
    = help: the following other types implement trait `SliceIndex<T>`:
              `RangeTo<usize>` implements `SliceIndex<[T]>`
              `RangeTo<usize>` implements `SliceIndex<str>`
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
index 7a94c96b79d..fb227bf0e91 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.rs
@@ -9,5 +9,5 @@ macro_rules! accept_pat {
     ($p:pat) => {};
 }
 
-accept_pat!(p | q); //~ ERROR no rules expected the token `|`
-accept_pat!(|p| q); //~ ERROR no rules expected the token `|`
+accept_pat!(p | q); //~ ERROR no rules expected `|`
+accept_pat!(|p| q); //~ ERROR no rules expected `|`
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
index acc2099bbc6..47dac84ee49 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `|`
+error: no rules expected `|`
   --> $DIR/or-patterns-syntactic-fail-2018.rs:12:15
    |
 LL | macro_rules! accept_pat {
@@ -13,7 +13,7 @@ note: while trying to match meta-variable `$p:pat`
 LL |     ($p:pat) => {};
    |      ^^^^^^
 
-error: no rules expected the token `|`
+error: no rules expected `|`
   --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13
    |
 LL | macro_rules! accept_pat {
diff --git a/tests/ui/parser/macro/macro-doc-comments-1.rs b/tests/ui/parser/macro/macro-doc-comments-1.rs
index 8d8103bb1e0..1aaa993e072 100644
--- a/tests/ui/parser/macro/macro-doc-comments-1.rs
+++ b/tests/ui/parser/macro/macro-doc-comments-1.rs
@@ -4,6 +4,6 @@ macro_rules! outer {
 
 outer! {
     //! Inner
-} //~^ ERROR no rules expected the token `!`
+} //~^ ERROR no rules expected `!`
 
 fn main() { }
diff --git a/tests/ui/parser/macro/macro-doc-comments-1.stderr b/tests/ui/parser/macro/macro-doc-comments-1.stderr
index 9d2d1bc0072..6b7e758980c 100644
--- a/tests/ui/parser/macro/macro-doc-comments-1.stderr
+++ b/tests/ui/parser/macro/macro-doc-comments-1.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `!`
+error: no rules expected `!`
   --> $DIR/macro-doc-comments-1.rs:6:5
    |
 LL | macro_rules! outer {
diff --git a/tests/ui/parser/macro/macro-doc-comments-2.rs b/tests/ui/parser/macro/macro-doc-comments-2.rs
index 8f33720ae80..2bee2435ef8 100644
--- a/tests/ui/parser/macro/macro-doc-comments-2.rs
+++ b/tests/ui/parser/macro/macro-doc-comments-2.rs
@@ -4,6 +4,6 @@ macro_rules! inner {
 
 inner! {
     /// Outer
-} //~^ ERROR no rules expected the token `[`
+} //~^ ERROR no rules expected `[`
 
 fn main() { }
diff --git a/tests/ui/parser/macro/macro-doc-comments-2.stderr b/tests/ui/parser/macro/macro-doc-comments-2.stderr
index 22efd995b46..02c12bf9591 100644
--- a/tests/ui/parser/macro/macro-doc-comments-2.stderr
+++ b/tests/ui/parser/macro/macro-doc-comments-2.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `[`
+error: no rules expected `[`
   --> $DIR/macro-doc-comments-2.rs:6:5
    |
 LL | macro_rules! inner {
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.rs b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
index db38fa0d7bc..0e27836b718 100644
--- a/tests/ui/parser/macro/macro-expand-to-match-arm.rs
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.rs
@@ -1,7 +1,7 @@
 macro_rules! arm {
     ($pattern:pat => $block:block) => {
         $pattern => $block
-        //~^ ERROR macro expansion ignores token `=>` and any following
+        //~^ ERROR macro expansion ignores `=>` and any tokens following
         //~| NOTE the usage of `arm!` is likely invalid in pattern context
         //~| NOTE macros cannot expand to match arms
     };
diff --git a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
index e3e7ff89c81..1927d80fd72 100644
--- a/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
+++ b/tests/ui/parser/macro/macro-expand-to-match-arm.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `=>` and any following
+error: macro expansion ignores `=>` and any tokens following
   --> $DIR/macro-expand-to-match-arm.rs:3:18
    |
 LL |         $pattern => $block
diff --git a/tests/ui/parser/macro/macro-incomplete-parse.rs b/tests/ui/parser/macro/macro-incomplete-parse.rs
index 544e4aa7b1b..612196aa4b2 100644
--- a/tests/ui/parser/macro/macro-incomplete-parse.rs
+++ b/tests/ui/parser/macro/macro-incomplete-parse.rs
@@ -2,7 +2,7 @@ macro_rules! ignored_item {
     () => {
         fn foo() {}
         fn bar() {}
-        , //~ ERROR macro expansion ignores token `,`
+        , //~ ERROR macro expansion ignores `,`
     }
 }
 
@@ -13,7 +13,7 @@ macro_rules! ignored_expr {
 }
 
 macro_rules! ignored_pat {
-    () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,`
+    () => ( 1, 2 ) //~ ERROR macro expansion ignores `,`
 }
 
 ignored_item!();
diff --git a/tests/ui/parser/macro/macro-incomplete-parse.stderr b/tests/ui/parser/macro/macro-incomplete-parse.stderr
index 707417b725e..096b5f718ae 100644
--- a/tests/ui/parser/macro/macro-incomplete-parse.stderr
+++ b/tests/ui/parser/macro/macro-incomplete-parse.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/macro-incomplete-parse.rs:5:9
    |
 LL |         ,
@@ -20,7 +20,7 @@ LL |     ignored_expr!();
    |
    = note: this error originates in the macro `ignored_expr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/macro-incomplete-parse.rs:16:14
    |
 LL |     () => ( 1, 2 )
diff --git a/tests/ui/parser/macro/trait-non-item-macros.rs b/tests/ui/parser/macro/trait-non-item-macros.rs
index 97fb564bf64..e93000193b6 100644
--- a/tests/ui/parser/macro/trait-non-item-macros.rs
+++ b/tests/ui/parser/macro/trait-non-item-macros.rs
@@ -1,7 +1,7 @@
 macro_rules! bah {
     ($a:expr) => {
         $a
-    }; //~^ ERROR macro expansion ignores token `2` and any following
+    }; //~^ ERROR macro expansion ignores expression `2` and any tokens following
 }
 
 trait Bar {
diff --git a/tests/ui/parser/macro/trait-non-item-macros.stderr b/tests/ui/parser/macro/trait-non-item-macros.stderr
index db20e6b24aa..1a828483778 100644
--- a/tests/ui/parser/macro/trait-non-item-macros.stderr
+++ b/tests/ui/parser/macro/trait-non-item-macros.stderr
@@ -1,4 +1,4 @@
-error: macro expansion ignores token `2` and any following
+error: macro expansion ignores expression `2` and any tokens following
   --> $DIR/trait-non-item-macros.rs:3:9
    |
 LL |         $a
diff --git a/tests/ui/parser/struct-literal-in-for.stderr b/tests/ui/parser/struct-literal-in-for.stderr
index d2ef2ad7b5a..1c91eba68e3 100644
--- a/tests/ui/parser/struct-literal-in-for.stderr
+++ b/tests/ui/parser/struct-literal-in-for.stderr
@@ -23,7 +23,7 @@ LL | |         x: 3
 LL | |     }.hi() {
    | |__________^ `bool` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `bool`, which is required by `bool: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `bool`
    = note: required for `bool` to implement `IntoIterator`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/proc-macro/attr-invalid-exprs.rs b/tests/ui/proc-macro/attr-invalid-exprs.rs
index 3d8806ee800..ec0b79469a4 100644
--- a/tests/ui/proc-macro/attr-invalid-exprs.rs
+++ b/tests/ui/proc-macro/attr-invalid-exprs.rs
@@ -13,7 +13,7 @@ fn main() {
     //~^ ERROR expected expression, found end of macro arguments
 
     let _ = #[duplicate] "Hello, world!";
-    //~^ ERROR macro expansion ignores token `,` and any following
+    //~^ ERROR macro expansion ignores `,` and any tokens following
 
     let _ = {
         #[no_output]
@@ -22,7 +22,7 @@ fn main() {
 
     let _ = {
         #[duplicate]
-        //~^ ERROR macro expansion ignores token `,` and any following
+        //~^ ERROR macro expansion ignores `,` and any tokens following
         "Hello, world!"
     };
 }
diff --git a/tests/ui/proc-macro/attr-invalid-exprs.stderr b/tests/ui/proc-macro/attr-invalid-exprs.stderr
index f96939bb6ef..0d500c87145 100644
--- a/tests/ui/proc-macro/attr-invalid-exprs.stderr
+++ b/tests/ui/proc-macro/attr-invalid-exprs.stderr
@@ -4,7 +4,7 @@ error: expected expression, found end of macro arguments
 LL |     let _ = #[no_output] "Hello, world!";
    |             ^^^^^^^^^^^^
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/attr-invalid-exprs.rs:15:13
    |
 LL |     let _ = #[duplicate] "Hello, world!";
@@ -16,7 +16,7 @@ help: you might be missing a semicolon here
 LL |     let _ = #[duplicate]; "Hello, world!";
    |                         +
 
-error: macro expansion ignores token `,` and any following
+error: macro expansion ignores `,` and any tokens following
   --> $DIR/attr-invalid-exprs.rs:24:9
    |
 LL |         #[duplicate]
diff --git a/tests/ui/proc-macro/expand-expr.rs b/tests/ui/proc-macro/expand-expr.rs
index 5f7375d7450..e06ddc51a29 100644
--- a/tests/ui/proc-macro/expand-expr.rs
+++ b/tests/ui/proc-macro/expand-expr.rs
@@ -114,8 +114,8 @@ expand_expr_fail!(echo_pm!($)); //~ ERROR: expected expression, found `$`
 
 // We get errors reported and recover during macro expansion if the macro
 // doesn't produce a valid expression.
-expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores token `hello` and any following
-expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores token `;` and any following
+expand_expr_is!("string", echo_tts!("string"; hello)); //~ ERROR: macro expansion ignores `hello` and any tokens following
+expand_expr_is!("string", echo_pm!("string"; hello)); //~ ERROR: macro expansion ignores `;` and any tokens following
 
 // For now, fail if a non-literal expression is expanded.
 expand_expr_fail!(arbitrary_expression() + "etc");
diff --git a/tests/ui/proc-macro/expand-expr.stderr b/tests/ui/proc-macro/expand-expr.stderr
index 2b92472e5ab..8b1df177cfa 100644
--- a/tests/ui/proc-macro/expand-expr.stderr
+++ b/tests/ui/proc-macro/expand-expr.stderr
@@ -22,7 +22,7 @@ error: expected expression, found `$`
 LL | expand_expr_fail!(echo_pm!($));
    |                            ^ expected expression
 
-error: macro expansion ignores token `hello` and any following
+error: macro expansion ignores `hello` and any tokens following
   --> $DIR/expand-expr.rs:117:47
    |
 LL | expand_expr_is!("string", echo_tts!("string"; hello));
@@ -34,7 +34,7 @@ help: you might be missing a semicolon here
 LL | expand_expr_is!("string", echo_tts!("string"; hello););
    |                                                     +
 
-error: macro expansion ignores token `;` and any following
+error: macro expansion ignores `;` and any tokens following
   --> $DIR/expand-expr.rs:118:44
    |
 LL | expand_expr_is!("string", echo_pm!("string"; hello));
diff --git a/tests/ui/range/range-1.stderr b/tests/ui/range/range-1.stderr
index f98420557c6..f77601bc43c 100644
--- a/tests/ui/range/range-1.stderr
+++ b/tests/ui/range/range-1.stderr
@@ -8,7 +8,7 @@ error[E0277]: the trait bound `bool: Step` is not satisfied
   --> $DIR/range-1.rs:9:14
    |
 LL |     for i in false..true {}
-   |              ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`, which is required by `std::ops::Range<bool>: IntoIterator`
+   |              ^^^^^^^^^^^ the trait `Step` is not implemented for `bool`
    |
    = help: the following other types implement trait `Step`:
              Char
diff --git a/tests/ui/recursion/recursive-requirements.stderr b/tests/ui/recursion/recursive-requirements.stderr
index f5cbed0ce34..bb63f7cd0dc 100644
--- a/tests/ui/recursion/recursive-requirements.stderr
+++ b/tests/ui/recursion/recursive-requirements.stderr
@@ -4,7 +4,7 @@ error[E0277]: `*const Bar` cannot be shared between threads safely
 LL |     let _: AssertSync<Foo> = unimplemented!();
    |            ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely
    |
-   = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar`, which is required by `Foo: Sync`
+   = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar`
 note: required because it appears within the type `Foo`
   --> $DIR/recursive-requirements.rs:5:12
    |
@@ -22,7 +22,7 @@ error[E0277]: `*const Foo` cannot be shared between threads safely
 LL |     let _: AssertSync<Foo> = unimplemented!();
    |            ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely
    |
-   = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo`, which is required by `Foo: Sync`
+   = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo`
 note: required because it appears within the type `Bar`
   --> $DIR/recursive-requirements.rs:10:12
    |
diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
new file mode 100644
index 00000000000..7c85249c009
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr
@@ -0,0 +1,19 @@
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+  --> $DIR/repr_align_greater_usize.rs:21:8
+   |
+LL | #[repr(align(32768))]
+   |        ^^^^^^^^^^^^
+   |
+   = note: `isize::MAX` is 32767 for the current target
+
+error[E0589]: alignment must not be greater than `isize::MAX` bytes
+  --> $DIR/repr_align_greater_usize.rs:24:8
+   |
+LL | #[repr(align(65536))]
+   |        ^^^^^^^^^^^^
+   |
+   = note: `isize::MAX` is 32767 for the current target
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs
new file mode 100644
index 00000000000..b47320b6d9b
--- /dev/null
+++ b/tests/ui/repr/repr_align_greater_usize.rs
@@ -0,0 +1,25 @@
+//@ revisions: msp430 aarch32
+//@[msp430] needs-llvm-components: msp430
+//@[msp430] compile-flags: --target=msp430-none-elf
+//@[aarch32] build-pass
+//@[aarch32] needs-llvm-components: arm
+//@[aarch32] compile-flags: --target=thumbv7m-none-eabi
+
+// We should fail to compute alignment for types aligned higher than usize::MAX.
+// We can't handle alignments that require all 32 bits, so this only affects 16-bit.
+
+#![feature(lang_items, no_core)]
+#![no_core]
+#![crate_type = "lib"]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[repr(align(16384))]
+struct Kitten;
+
+#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct Cat;
+
+#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX`
+struct BigCat;
diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
index 4d23922892e..0a703367d96 100644
--- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
+++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `f32: Termination` is not satisfied
 LL | #[test]
    | ------- in this procedural macro expansion
 LL | fn can_parse_zero_as_f32() -> Result<f32, ParseFloatError> {
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32`, which is required by `Result<f32, ParseFloatError>: Termination`
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Termination` is not implemented for `f32`
    |
    = note: required for `Result<f32, ParseFloatError>` to implement `Termination`
 note: required by a bound in `assert_test_result`
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
index b8c0eb3e6d6..4b2fc4a03b6 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
@@ -68,7 +68,7 @@ fn _macros() {
         _ => {}
     }
     use_expr!(let 0 = 1);
-    //~^ ERROR no rules expected the token `let`
+    //~^ ERROR no rules expected keyword `let`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
index 2341dbbbdbd..1c710b04897 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
@@ -131,7 +131,7 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: no rules expected the token `let`
+error: no rules expected keyword `let`
   --> $DIR/feature-gate.rs:70:15
    |
 LL |     macro_rules! use_expr {
diff --git a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr
index eb6abbf8045..7ec018a95cc 100644
--- a/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr
+++ b/tests/ui/rfcs/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr
@@ -4,7 +4,7 @@ error[E0277]: `NotDebug` doesn't implement `Debug`
 LL |     let _: NotDebug = dbg!(NotDebug);
    |                       ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `NotDebug`, which is required by `&NotDebug: Debug`
+   = help: the trait `Debug` is not implemented for `NotDebug`
    = note: add `#[derive(Debug)]` to `NotDebug` or manually `impl Debug for NotDebug`
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `NotDebug` with `#[derive(Debug)]`
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
index bca7564efd8..2087fc42cf1 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
@@ -54,7 +54,7 @@ fn _macros() {
     #[cfg(FALSE)] (let 0 = 1);
     //~^ ERROR expected expression, found `let` statement
     use_expr!(let 0 = 1);
-    //~^ ERROR no rules expected the token `let`
+    //~^ ERROR no rules expected keyword `let`
 }
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
index 2b1a49be3da..7c874ae78a8 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
@@ -14,7 +14,7 @@ LL |     noop_expr!((let 0 = 1));
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 
-error: no rules expected the token `let`
+error: no rules expected keyword `let`
   --> $DIR/feature-gate.rs:56:15
    |
 LL |     macro_rules! use_expr {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
index be4a5231558..130d0296c5e 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.disallowed.stderr
@@ -111,5 +111,23 @@ LL |     while let Some(ref first) = opt && let second = first && let _third = s
    = note: these patterns will always match
    = help: consider moving them into the body
 
-error: aborting due to 12 previous errors
+error: trailing irrefutable pattern in let chain
+  --> $DIR/irrefutable-lets.rs:87:12
+   |
+LL |         && let x = &opt
+   |            ^^^^^^^^^^^^
+   |
+   = note: this pattern will always match
+   = help: consider moving it into the body
+
+error: leading irrefutable pattern in let chain
+  --> $DIR/irrefutable-lets.rs:93:12
+   |
+LL |         if let x = opt.clone().map(|_| 1)
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this pattern will always match
+   = help: consider moving it outside of the construct
+
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
index bd4df337614..e7d69f89773 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/irrefutable-lets.rs
@@ -75,4 +75,24 @@ fn main() {
         && let Range { start: local_start, end: _ } = first
         && let None = local_start {
     }
+
+    // No error. An extra nesting level would be required for the `else if`.
+    if opt == Some(None..None) {
+    } else if let x = opt.clone().map(|_| 1)
+        && x == Some(1)
+    {}
+
+    if opt == Some(None..None) {
+    } else if opt.is_some()
+        && let x = &opt
+        //[disallowed]~^ ERROR trailing irrefutable pattern in let chain
+    {}
+
+    if opt == Some(None..None) {
+    } else {
+        if let x = opt.clone().map(|_| 1)
+        //[disallowed]~^ ERROR leading irrefutable pattern in let chain
+            && x == Some(1)
+        {}
+    }
 }
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
index a544c8ea0d1..d121a194be6 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.rs
@@ -8,7 +8,7 @@ use std::ops::Deref;
 struct Foo(u32);
 impl Foo {
     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
-        //~^ ERROR: `R` cannot be used as the type of `self`
+        //~^ ERROR invalid generic `self` parameter type
         //~| ERROR destructor of `R` cannot be evaluated at compile-time
         self.0
         //~^ ERROR cannot call non-const fn `<R as Deref>::deref` in constant function
diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
index 6ae60e7af47..7252b5890fd 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr
@@ -15,18 +15,16 @@ LL |     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
 LL |     }
    |     - value is dropped here
 
-error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+error[E0801]: invalid generic `self` parameter type: `R`
   --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49
    |
 LL |     const fn get<R: Deref<Target = Self>>(self: R) -> u32 {
    |                                                 ^
    |
-   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
-   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
 error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0015, E0493, E0658.
+Some errors have detailed explanations: E0015, E0493, E0801.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
index 4cc69666b88..5dc3a0b0234 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs.default.stderr
@@ -1,14 +1,168 @@
-error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
-  --> $DIR/arbitrary-self-from-method-substs.rs:8:43
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:9:43
    |
 LL |     fn get<R: Deref<Target = Self>>(self: R) -> u32 {
    |                                           ^
    |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:13:44
+   |
+LL |     fn get1<R: Deref<Target = Self>>(self: &R) -> u32 {
+   |                                            ^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&mut R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:17:44
+   |
+LL |     fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 {
+   |                                            ^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `Rc<R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:21:44
+   |
+LL |     fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&Rc<R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:25:44
+   |
+LL |     fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `Rc<&R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:29:44
+   |
+LL |     fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0658]: `<FR as FindReceiver>::Receiver` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+  --> $DIR/arbitrary-self-from-method-substs.rs:33:37
+   |
+LL |     fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
+   |                                     ^^^^^^^^^^^^
+   |
    = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
    = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error: aborting due to 1 previous error
+error[E0658]: `R` cannot be used as the type of `self` without the `arbitrary_self_types` feature
+  --> $DIR/arbitrary-self-from-method-substs.rs:61:18
+   |
+LL |     fn get(self: R) {}
+   |                  ^
+   |
+   = note: see issue #44874 <https://github.com/rust-lang/rust/issues/44874> for more information
+   = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:92:9
+   |
+LL |     foo.get6(Silly);
+   |         ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
+   |
+note: expected this to be `Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:71:21
+   |
+LL |     type Receiver = std::rc::Rc<Foo>;
+   |                     ^^^^^^^^^^^^^^^^
+   = note: expected struct `Foo`
+              found struct `Rc<Foo>`
+
+error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:96:9
+   |
+LL |     foo.get6(Silly);
+   |         ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
+   |
+note: expected this to be `&Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:71:21
+   |
+LL |     type Receiver = std::rc::Rc<Foo>;
+   |                     ^^^^^^^^^^^^^^^^
+   = note: expected reference `&Foo`
+                 found struct `Rc<Foo>`
+
+error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied
+  --> $DIR/arbitrary-self-from-method-substs.rs:100:7
+   |
+LL | struct Bar<R>(std::marker::PhantomData<R>);
+   | ------------- doesn't satisfy `Bar<_>: Deref`
+...
+LL |     t.get();
+   |       ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
+      `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
+      `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
+      `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
+      `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
+      `Bar<_>: Deref`
+  --> $DIR/arbitrary-self-from-method-substs.rs:60:9
+   |
+LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------
+   |         |               |
+   |         |               unsatisfied trait bound introduced here
+   |         unsatisfied trait bound introduced here
+note: the trait `Deref` must be implemented
+  --> $SRC_DIR/core/src/ops/deref.rs:LL:COL
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `get`, perhaps you need to implement it:
+           candidate #1: `SliceIndex`
+
+error[E0599]: the method `get` exists for reference `&Rc<Bar<_>>`, but its trait bounds were not satisfied
+  --> $DIR/arbitrary-self-from-method-substs.rs:108:7
+   |
+LL | struct Bar<R>(std::marker::PhantomData<R>);
+   | ------------- doesn't satisfy `Bar<_>: Deref`
+...
+LL |     t.get();
+   |       ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>`
+      `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
+      `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
+      `<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>`
+      `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
+      `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
+      `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
+      `Bar<_>: Deref`
+  --> $DIR/arbitrary-self-from-method-substs.rs:60:9
+   |
+LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------
+   |         |               |
+   |         |               unsatisfied trait bound introduced here
+   |         unsatisfied trait bound introduced here
+note: the trait `Deref` must be implemented
+  --> $SRC_DIR/core/src/ops/deref.rs:LL:COL
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `get`, perhaps you need to implement it:
+           candidate #1: `SliceIndex`
+
+error: aborting due to 12 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0271, E0599, E0658, E0801.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
index 44e553f1a06..6e864f44aa3 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
+++ b/tests/ui/self/arbitrary-self-from-method-substs.feature.stderr
@@ -1,9 +1,179 @@
+error[E0801]: invalid generic `self` parameter type: `R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:9:43
+   |
+LL |     fn get<R: Deref<Target = Self>>(self: R) -> u32 {
+   |                                           ^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:13:44
+   |
+LL |     fn get1<R: Deref<Target = Self>>(self: &R) -> u32 {
+   |                                            ^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&mut R`
+  --> $DIR/arbitrary-self-from-method-substs.rs:17:44
+   |
+LL |     fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 {
+   |                                            ^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `Rc<R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:21:44
+   |
+LL |     fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `&Rc<R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:25:44
+   |
+LL |     fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error[E0801]: invalid generic `self` parameter type: `Rc<&R>`
+  --> $DIR/arbitrary-self-from-method-substs.rs:29:44
+   |
+LL |     fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 {
+   |                                            ^^^^^^^^^^^^^^^
+   |
+   = note: type of `self` must not be a method generic parameter type
+   = help: use a concrete type such as `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
 error[E0308]: mismatched types
-  --> $DIR/arbitrary-self-from-method-substs.rs:16:5
+  --> $DIR/arbitrary-self-from-method-substs.rs:76:5
    |
 LL |     foo.get::<&Foo>();
    |     ^^^ expected `&Foo`, found `Foo`
 
-error: aborting due to 1 previous error
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs.rs:78:5
+   |
+LL |     foo.get::<std::rc::Rc<Foo>>();
+   |     ^^^ expected `Rc<Foo>`, found `Foo`
+   |
+   = note: expected struct `Rc<Foo>`
+              found struct `Foo`
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs.rs:84:5
+   |
+LL |     smart_ptr.get::<SmartPtr2<Foo>>();
+   |     ^^^^^^^^^ expected `SmartPtr2<'_, Foo>`, found `SmartPtr<'_, Foo>`
+   |
+   = note: expected struct `SmartPtr2<'_, Foo>`
+              found struct `SmartPtr<'_, Foo>`
+
+error[E0308]: mismatched types
+  --> $DIR/arbitrary-self-from-method-substs.rs:86:5
+   |
+LL |     smart_ptr.get::<&Foo>();
+   |     ^^^^^^^^^ expected `&Foo`, found `SmartPtr<'_, Foo>`
+   |
+   = note: expected reference `&Foo`
+                 found struct `SmartPtr<'_, Foo, >`
+
+error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:92:9
+   |
+LL |     foo.get6(Silly);
+   |         ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == Foo`
+   |
+note: expected this to be `Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:71:21
+   |
+LL |     type Receiver = std::rc::Rc<Foo>;
+   |                     ^^^^^^^^^^^^^^^^
+   = note: expected struct `Foo`
+              found struct `Rc<Foo>`
+
+error[E0271]: type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:96:9
+   |
+LL |     foo.get6(Silly);
+   |         ^^^^ type mismatch resolving `<Silly as FindReceiver>::Receiver == &Foo`
+   |
+note: expected this to be `&Foo`
+  --> $DIR/arbitrary-self-from-method-substs.rs:71:21
+   |
+LL |     type Receiver = std::rc::Rc<Foo>;
+   |                     ^^^^^^^^^^^^^^^^
+   = note: expected reference `&Foo`
+                 found struct `Rc<Foo>`
+
+error[E0599]: the method `get` exists for struct `Rc<Bar<_>>`, but its trait bounds were not satisfied
+  --> $DIR/arbitrary-self-from-method-substs.rs:100:7
+   |
+LL | struct Bar<R>(std::marker::PhantomData<R>);
+   | ------------- doesn't satisfy `Bar<_>: Deref`
+...
+LL |     t.get();
+   |       ^^^ method cannot be called on `Rc<Bar<_>>` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
+      `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
+      `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
+      `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
+      `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
+      `Bar<_>: Deref`
+  --> $DIR/arbitrary-self-from-method-substs.rs:60:9
+   |
+LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------
+   |         |               |
+   |         |               unsatisfied trait bound introduced here
+   |         unsatisfied trait bound introduced here
+note: the trait `Deref` must be implemented
+  --> $SRC_DIR/core/src/ops/deref.rs:LL:COL
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `get`, perhaps you need to implement it:
+           candidate #1: `SliceIndex`
+
+error[E0599]: the method `get` exists for reference `&Rc<Bar<_>>`, but its trait bounds were not satisfied
+  --> $DIR/arbitrary-self-from-method-substs.rs:108:7
+   |
+LL | struct Bar<R>(std::marker::PhantomData<R>);
+   | ------------- doesn't satisfy `Bar<_>: Deref`
+...
+LL |     t.get();
+   |       ^^^ method cannot be called on `&Rc<Bar<_>>` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `<&&Rc<Bar<_>> as Deref>::Target = Bar<&&Rc<Bar<_>>>`
+      `<&Bar<_> as Deref>::Target = Bar<&Bar<_>>`
+      `<&Rc<Bar<_>> as Deref>::Target = Bar<&Rc<Bar<_>>>`
+      `<&mut &Rc<Bar<_>> as Deref>::Target = Bar<&mut &Rc<Bar<_>>>`
+      `<&mut Bar<_> as Deref>::Target = Bar<&mut Bar<_>>`
+      `<&mut Rc<Bar<_>> as Deref>::Target = Bar<&mut Rc<Bar<_>>>`
+      `<Rc<Bar<_>> as Deref>::Target = Bar<Rc<Bar<_>>>`
+      `Bar<_>: Deref`
+  --> $DIR/arbitrary-self-from-method-substs.rs:60:9
+   |
+LL | impl<R: std::ops::Deref<Target = Self>> Bar<R> {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ------
+   |         |               |
+   |         |               unsatisfied trait bound introduced here
+   |         unsatisfied trait bound introduced here
+note: the trait `Deref` must be implemented
+  --> $SRC_DIR/core/src/ops/deref.rs:LL:COL
+   = help: items from traits can only be used if the trait is implemented and in scope
+   = note: the following trait defines an item `get`, perhaps you need to implement it:
+           candidate #1: `SliceIndex`
+
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0271, E0308, E0599, E0801.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/self/arbitrary-self-from-method-substs.rs b/tests/ui/self/arbitrary-self-from-method-substs.rs
index 99977ed9b8c..f2d65859615 100644
--- a/tests/ui/self/arbitrary-self-from-method-substs.rs
+++ b/tests/ui/self/arbitrary-self-from-method-substs.rs
@@ -2,17 +2,109 @@
 #![cfg_attr(feature, feature(arbitrary_self_types))]
 
 use std::ops::Deref;
+use std::marker::PhantomData;
 
 struct Foo(u32);
 impl Foo {
     fn get<R: Deref<Target = Self>>(self: R) -> u32 {
-        //[default]~^ ERROR: `R` cannot be used as the type of `self`
+        //~^ ERROR: invalid generic `self` parameter type
         self.0
     }
+    fn get1<R: Deref<Target = Self>>(self: &R) -> u32 {
+        //~^ ERROR: invalid generic `self` parameter type
+        self.0
+    }
+    fn get2<R: Deref<Target = Self>>(self: &mut R) -> u32 {
+        //~^ ERROR: invalid generic `self` parameter type
+        self.0
+    }
+    fn get3<R: Deref<Target = Self>>(self: std::rc::Rc<R>) -> u32 {
+        //~^ ERROR: invalid generic `self` parameter type
+        self.0
+    }
+    fn get4<R: Deref<Target = Self>>(self: &std::rc::Rc<R>) -> u32 {
+        //~^ ERROR: invalid generic `self` parameter type
+        self.0
+    }
+    fn get5<R: Deref<Target = Self>>(self: std::rc::Rc<&R>) -> u32 {
+        //~^ ERROR: invalid generic `self` parameter type
+        self.0
+    }
+    fn get6<FR: FindReceiver>(self: FR::Receiver, other: FR) -> u32 {
+        //[default]~^ ERROR: `<FR as FindReceiver>::Receiver` cannot be used as the type of `self`
+        42
+    }
+}
+
+
+struct SmartPtr<'a, T: ?Sized>(&'a T);
+
+impl<'a, T: ?Sized> Deref for SmartPtr<'a, T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        unimplemented!()
+    }
+}
+
+struct SmartPtr2<'a, T: ?Sized>(&'a T);
+
+impl<'a, T: ?Sized> Deref for SmartPtr2<'a, T> {
+    type Target = T;
+    fn deref(&self) -> &Self::Target {
+        unimplemented!()
+    }
+}
+
+struct Bar<R>(std::marker::PhantomData<R>);
+
+impl<R: std::ops::Deref<Target = Self>> Bar<R> {
+    fn get(self: R) {}
+    //[default]~^ ERROR: `R` cannot be used as the type of `self`
+}
+
+trait FindReceiver {
+    type Receiver: Deref<Target = Foo>;
+}
+
+struct Silly;
+impl FindReceiver for Silly {
+    type Receiver = std::rc::Rc<Foo>;
 }
 
 fn main() {
     let mut foo = Foo(1);
     foo.get::<&Foo>();
     //[feature]~^ ERROR mismatched types
+    foo.get::<std::rc::Rc<Foo>>();
+    //[feature]~^ ERROR mismatched types
+
+    let smart_ptr = SmartPtr(&foo);
+    let smart_ptr2 = SmartPtr2(&foo);
+    smart_ptr.get(); // this compiles
+    smart_ptr.get::<SmartPtr2<Foo>>();
+    //[feature]~^ ERROR mismatched types
+    smart_ptr.get::<&Foo>();
+    //[feature]~^ ERROR mismatched types
+
+    let mut foo = Foo(1);
+    // This test is slightly contrived in an attempt to generate a mismatched types
+    // error for the self type below, without using the turbofish.
+    foo.get6(Silly);
+    //~^ ERROR type mismatch
+    let mut foo = Foo(1);
+    let foo = &foo;
+    foo.get6(Silly);
+    //~^ ERROR type mismatch
+
+    let t = std::rc::Rc::new(Bar(std::marker::PhantomData));
+    t.get();
+    //~^ ERROR its trait bounds were not satisfied
+    let t = &t;
+    // This is a further attempt at triggering 'type mismatch' errors
+    // from arbitrary self types without resorting to the turbofish.
+    // Ideally, here, t is Thing<Rc<Target=Self>> while we're going to call
+    // it with a &t method receiver. However, this doesn't work since that
+    // type of t becomes recursive and trait bounds can't be satisfied.
+    t.get();
+    //~^ ERROR its trait bounds were not satisfied
 }
diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr
index 746b08fa710..40ac350980e 100644
--- a/tests/ui/specialization/const_trait_impl.stderr
+++ b/tests/ui/specialization/const_trait_impl.stderr
@@ -1,42 +1,42 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:34:16
+  --> $DIR/const_trait_impl.rs:34:9
    |
 LL | impl<T: ~const Default> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:40:16
+  --> $DIR/const_trait_impl.rs:40:9
    |
 LL | impl<T: ~const Default + ~const Sup> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:46:16
+  --> $DIR/const_trait_impl.rs:46:9
    |
 LL | impl<T: ~const Default + ~const Sub> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:40:16
+  --> $DIR/const_trait_impl.rs:40:9
    |
 LL | impl<T: ~const Default + ~const Sup> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:34:16
+  --> $DIR/const_trait_impl.rs:34:9
    |
 LL | impl<T: ~const Default> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const_trait_impl.rs:46:16
+  --> $DIR/const_trait_impl.rs:46:9
    |
 LL | impl<T: ~const Default + ~const Sub> const A for T {
-   |                ^^^^^^^
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/specialization/min_specialization/issue-79224.stderr b/tests/ui/specialization/min_specialization/issue-79224.stderr
index db88be88a81..268fc3a9591 100644
--- a/tests/ui/specialization/min_specialization/issue-79224.stderr
+++ b/tests/ui/specialization/min_specialization/issue-79224.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied
   --> $DIR/issue-79224.rs:18:29
    |
 LL | impl<B: ?Sized> Display for Cow<'_, B> {
-   |                             ^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned`
+   |                             ^^^^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
@@ -14,7 +14,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied
   --> $DIR/issue-79224.rs:20:5
    |
 LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
@@ -26,7 +26,7 @@ error[E0277]: the trait bound `B: Clone` is not satisfied
   --> $DIR/issue-79224.rs:20:13
    |
 LL |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-   |             ^^^^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned`
+   |             ^^^^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
@@ -44,7 +44,7 @@ LL | |
 LL | |
 LL | |         write!(f, "foo")
 LL | |     }
-   | |_____^ the trait `Clone` is not implemented for `B`, which is required by `B: ToOwned`
+   | |_____^ the trait `Clone` is not implemented for `B`
    |
    = note: required for `B` to implement `ToOwned`
 help: consider further restricting this bound
diff --git a/tests/ui/statics/unsized_type2.stderr b/tests/ui/statics/unsized_type2.stderr
index 4e47b37afdc..b18a99fab72 100644
--- a/tests/ui/statics/unsized_type2.stderr
+++ b/tests/ui/statics/unsized_type2.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL | pub static WITH_ERROR: Foo = Foo { version: 0 };
    |                        ^^^ doesn't have a size known at compile-time
    |
-   = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized`
+   = help: within `Foo`, the trait `Sized` is not implemented for `str`
 note: required because it appears within the type `Foo`
   --> $DIR/unsized_type2.rs:5:12
    |
@@ -17,7 +17,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL | pub static WITH_ERROR: Foo = Foo { version: 0 };
    |                              ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Foo`, the trait `Sized` is not implemented for `str`, which is required by `Foo: Sized`
+   = help: within `Foo`, the trait `Sized` is not implemented for `str`
 note: required because it appears within the type `Foo`
   --> $DIR/unsized_type2.rs:5:12
    |
diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
index 59e09e48523..35dd570e91f 100644
--- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
+++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr
@@ -26,7 +26,7 @@ error[E0277]: `(dyn Qux + 'static)` cannot be shared between threads safely
 LL | static FOO: &Lint = &Lint { desc: "desc" };
    |             ^^^^^ `(dyn Qux + 'static)` cannot be shared between threads safely
    |
-   = help: within `&'static Lint`, the trait `Sync` is not implemented for `(dyn Qux + 'static)`, which is required by `&'static Lint: Sync`
+   = help: within `&'static Lint`, the trait `Sync` is not implemented for `(dyn Qux + 'static)`
    = note: required because it appears within the type `&'static (dyn Qux + 'static)`
 note: required because it appears within the type `Lint`
   --> $DIR/unsizing-wfcheck-issue-127299.rs:7:12
diff --git a/tests/ui/str/str-idx.stderr b/tests/ui/str/str-idx.stderr
index 84806cbea0d..e8bbb8058fa 100644
--- a/tests/ui/str/str-idx.stderr
+++ b/tests/ui/str/str-idx.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `str` cannot be indexed by `{integer}`
 LL |     let _: u8 = s[4];
    |                   ^ string indices are ranges of `usize`
    |
-   = help: the trait `SliceIndex<str>` is not implemented for `{integer}`, which is required by `str: Index<_>`
+   = help: the trait `SliceIndex<str>` is not implemented for `{integer}`
    = note: you can use `.chars().nth()` or `.bytes().nth()`
            for more information, see chapter 8 in The Book: <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
    = help: the trait `SliceIndex<[_]>` is implemented for `usize`
@@ -49,7 +49,7 @@ error[E0277]: the type `str` cannot be indexed by `char`
 LL |     let _: u8 = s['c'];
    |                   ^^^ string indices are ranges of `usize`
    |
-   = help: the trait `SliceIndex<str>` is not implemented for `char`, which is required by `str: Index<_>`
+   = help: the trait `SliceIndex<str>` is not implemented for `char`
    = note: required for `str` to implement `Index<char>`
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/str/str-mut-idx.stderr b/tests/ui/str/str-mut-idx.stderr
index 679f783126f..9390d689252 100644
--- a/tests/ui/str/str-mut-idx.stderr
+++ b/tests/ui/str/str-mut-idx.stderr
@@ -30,7 +30,7 @@ error[E0277]: the type `str` cannot be indexed by `usize`
 LL |     s[1usize] = bot();
    |       ^^^^^^ string indices are ranges of `usize`
    |
-   = help: the trait `SliceIndex<str>` is not implemented for `usize`, which is required by `str: Index<_>`
+   = help: the trait `SliceIndex<str>` is not implemented for `usize`
    = help: the trait `SliceIndex<[_]>` is implemented for `usize`
    = help: for that trait implementation, expected `[_]`, found `str`
    = note: required for `str` to implement `Index<usize>`
@@ -73,7 +73,7 @@ error[E0277]: the type `str` cannot be indexed by `char`
 LL |     s['c'];
    |       ^^^ string indices are ranges of `usize`
    |
-   = help: the trait `SliceIndex<str>` is not implemented for `char`, which is required by `str: Index<_>`
+   = help: the trait `SliceIndex<str>` is not implemented for `char`
    = note: required for `str` to implement `Index<char>`
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr
index 6fae6e1316d..680890e880c 100644
--- a/tests/ui/suggestions/derive-clone-for-eq.stderr
+++ b/tests/ui/suggestions/derive-clone-for-eq.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/derive-clone-for-eq.rs:4:17
    |
 LL | #[derive(Clone, Eq)]
-   |                 ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
+   |                 ^^ the trait `Clone` is not implemented for `T`
    |
 note: required for `Struct<T>` to implement `PartialEq`
   --> $DIR/derive-clone-for-eq.rs:7:19
diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr
index 5da85a9d061..bffcb1af487 100644
--- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr
+++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr
@@ -6,7 +6,7 @@ LL |     #[derive(Debug)]
 LL |     struct Outer<T>(Inner<T>);
    |                     ^^^^^^^^ `a::Inner<T>` cannot be formatted using `{:?}`
    |
-   = help: the trait `Debug` is not implemented for `a::Inner<T>`, which is required by `&a::Inner<T>: Debug`
+   = help: the trait `Debug` is not implemented for `a::Inner<T>`
    = note: add `#[derive(Debug)]` to `a::Inner<T>` or manually `impl Debug for a::Inner<T>`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider annotating `a::Inner<T>` with `#[derive(Debug)]`
@@ -25,7 +25,7 @@ error[E0277]: the trait bound `T: c::Trait` is not satisfied
 LL |     #[derive(Debug)]
    |              ----- in this derive macro expansion
 LL |     struct Outer<T>(Inner<T>);
-   |                     ^^^^^^^^ the trait `c::Trait` is not implemented for `T`, which is required by `&c::Inner<T>: Debug`
+   |                     ^^^^^^^^ the trait `c::Trait` is not implemented for `T`
    |
 note: required for `c::Inner<T>` to implement `Debug`
   --> $DIR/derive-macro-missing-bounds.rs:34:28
@@ -49,7 +49,7 @@ error[E0277]: the trait bound `T: d::Trait` is not satisfied
 LL |     #[derive(Debug)]
    |              ----- in this derive macro expansion
 LL |     struct Outer<T>(Inner<T>);
-   |                     ^^^^^^^^ the trait `d::Trait` is not implemented for `T`, which is required by `&d::Inner<T>: Debug`
+   |                     ^^^^^^^^ the trait `d::Trait` is not implemented for `T`
    |
 note: required for `d::Inner<T>` to implement `Debug`
   --> $DIR/derive-macro-missing-bounds.rs:49:13
@@ -71,7 +71,7 @@ error[E0277]: the trait bound `T: e::Trait` is not satisfied
 LL |     #[derive(Debug)]
    |              ----- in this derive macro expansion
 LL |     struct Outer<T>(Inner<T>);
-   |                     ^^^^^^^^ the trait `e::Trait` is not implemented for `T`, which is required by `&e::Inner<T>: Debug`
+   |                     ^^^^^^^^ the trait `e::Trait` is not implemented for `T`
    |
 note: required for `e::Inner<T>` to implement `Debug`
   --> $DIR/derive-macro-missing-bounds.rs:64:13
@@ -93,7 +93,7 @@ error[E0277]: the trait bound `T: f::Trait` is not satisfied
 LL |     #[derive(Debug)]
    |              ----- in this derive macro expansion
 LL |     struct Outer<T>(Inner<T>);
-   |                     ^^^^^^^^ the trait `f::Trait` is not implemented for `T`, which is required by `&f::Inner<T>: Debug`
+   |                     ^^^^^^^^ the trait `f::Trait` is not implemented for `T`
    |
 note: required for `f::Inner<T>` to implement `Debug`
   --> $DIR/derive-macro-missing-bounds.rs:79:20
diff --git a/tests/ui/suggestions/into-str.stderr b/tests/ui/suggestions/into-str.stderr
index ac6e531fee2..d02d3186082 100644
--- a/tests/ui/suggestions/into-str.stderr
+++ b/tests/ui/suggestions/into-str.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&str: From<String>` is not satisfied
   --> $DIR/into-str.rs:4:9
    |
 LL |     foo(String::new());
-   |     --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`, which is required by `String: Into<&str>`
+   |     --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/suggestions/issue-71394-no-from-impl.stderr b/tests/ui/suggestions/issue-71394-no-from-impl.stderr
index 79f5dcf4b73..31f8f1d455a 100644
--- a/tests/ui/suggestions/issue-71394-no-from-impl.stderr
+++ b/tests/ui/suggestions/issue-71394-no-from-impl.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
   --> $DIR/issue-71394-no-from-impl.rs:8:25
    |
 LL |     let _: &[i8] = data.into();
-   |                         ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`, which is required by `&[u8]: Into<_>`
+   |                         ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
    |
    = help: the following other types implement trait `From<T>`:
              `[T; 10]` implements `From<(T, T, T, T, T, T, T, T, T, T)>`
diff --git a/tests/ui/suggestions/issue-88696.stderr b/tests/ui/suggestions/issue-88696.stderr
index a8bc970e055..b4f0793c225 100644
--- a/tests/ui/suggestions/issue-88696.stderr
+++ b/tests/ui/suggestions/issue-88696.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Result<u32, i32>: From<Result<u64, i32>>` is not
   --> $DIR/issue-88696.rs:9:9
    |
 LL |     a().into()
-   |         ^^^^ the trait `From<Result<u64, i32>>` is not implemented for `Result<u32, i32>`, which is required by `Result<u64, i32>: Into<_>`
+   |         ^^^^ the trait `From<Result<u64, i32>>` is not implemented for `Result<u32, i32>`
    |
    = note: required for `Result<u64, i32>` to implement `Into<Result<u32, i32>>`
 
diff --git a/tests/ui/suggestions/issue-96223.stderr b/tests/ui/suggestions/issue-96223.stderr
index 4a77b240f3e..a54a4e7b3be 100644
--- a/tests/ui/suggestions/issue-96223.stderr
+++ b/tests/ui/suggestions/issue-96223.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied
   --> $DIR/issue-96223.rs:49:17
    |
 LL |     icey_bounds(&p);
-   |     ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`, which is required by `Empty: Dummy<EmptyMarker>`
+   |     ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/suggestions/issue-96555.stderr b/tests/ui/suggestions/issue-96555.stderr
index f77681ae80f..1a1e069f09e 100644
--- a/tests/ui/suggestions/issue-96555.stderr
+++ b/tests/ui/suggestions/issue-96555.stderr
@@ -6,7 +6,7 @@ LL |     m::f1().await;
    |     |
    |     this call returns `()`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 help: remove the `.await`
@@ -27,7 +27,7 @@ LL |     m::f2().await;
    |     |
    |     this call returns `()`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 help: remove the `.await`
@@ -48,7 +48,7 @@ LL |     m::f3().await;
    |     |
    |     this call returns `()`
    |
-   = help: the trait `Future` is not implemented for `()`, which is required by `(): IntoFuture`
+   = help: the trait `Future` is not implemented for `()`
    = note: () must be a future or must implement `IntoFuture` to be awaited
    = note: required for `()` to implement `IntoFuture`
 help: remove the `.await`
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
index db16fff826f..d65ad109241 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.stderr
@@ -21,7 +21,7 @@ LL | #[derive(Debug, Copy, Clone)]
    |          ----- in this derive macro expansion
 LL | pub struct AABB<K: Debug> {
 LL |     pub loc: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Debug`
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
 note: required for `Vector2<K>` to implement `Debug`
   --> $DIR/missing-bound-in-derive-copy-impl-2.rs:4:10
@@ -64,7 +64,7 @@ LL | #[derive(Debug, Copy, Clone)]
    |                       ----- in this derive macro expansion
 ...
 LL |     pub size: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone`
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
 note: required for `Vector2<K>` to implement `Clone`
   --> $DIR/missing-bound-in-derive-copy-impl-2.rs:4:23
diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
index cf383b5c8ff..316c2fa0fc9 100644
--- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
+++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl.stderr
@@ -57,7 +57,7 @@ LL | #[derive(Debug, Copy, Clone)]
    |          ----- in this derive macro expansion
 LL | pub struct AABB<K> {
 LL |     pub loc: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Debug`
+   |     ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
 note: required for `Vector2<K>` to implement `Debug`
   --> $DIR/missing-bound-in-derive-copy-impl.rs:3:10
@@ -130,7 +130,7 @@ LL | #[derive(Debug, Copy, Clone)]
    |                       ----- in this derive macro expansion
 ...
 LL |     pub size: Vector2<K>,
-   |     ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`, which is required by `Vector2<K>: Clone`
+   |     ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `K`
    |
 note: required for `Vector2<K>` to implement `Clone`
   --> $DIR/missing-bound-in-derive-copy-impl.rs:3:23
diff --git a/tests/ui/suggestions/path-by-value.stderr b/tests/ui/suggestions/path-by-value.stderr
index 62feafe534d..d870e21043c 100644
--- a/tests/ui/suggestions/path-by-value.stderr
+++ b/tests/ui/suggestions/path-by-value.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL | fn f(p: Path) { }
    |         ^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path`, the trait `Sized` is not implemented for `[u8]`, which is required by `Path: Sized`
+   = help: within `Path`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `Path`
   --> $SRC_DIR/std/src/path.rs:LL:COL
    = help: unsized fn params are gated as an unstable feature
diff --git a/tests/ui/suggestions/path-display.stderr b/tests/ui/suggestions/path-display.stderr
index f9159c45030..46d0b35825b 100644
--- a/tests/ui/suggestions/path-display.stderr
+++ b/tests/ui/suggestions/path-display.stderr
@@ -4,7 +4,7 @@ error[E0277]: `Path` doesn't implement `std::fmt::Display`
 LL |     println!("{}", path);
    |                    ^^^^ `Path` cannot be formatted with the default formatter; call `.display()` on it
    |
-   = help: the trait `std::fmt::Display` is not implemented for `Path`, which is required by `&Path: std::fmt::Display`
+   = help: the trait `std::fmt::Display` is not implemented for `Path`
    = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
    = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/suggestions/suggest-dereferencing-index.stderr b/tests/ui/suggestions/suggest-dereferencing-index.stderr
index 86487cdcc44..2316acbe9da 100644
--- a/tests/ui/suggestions/suggest-dereferencing-index.stderr
+++ b/tests/ui/suggestions/suggest-dereferencing-index.stderr
@@ -4,7 +4,7 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `&usize`
 LL |     let one_item_please: i32 = [1, 2, 3][i];
    |                                          ^ slice indices are of type `usize` or ranges of `usize`
    |
-   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize`, which is required by `[{integer}; 3]: Index<_>`
+   = help: the trait `SliceIndex<[{integer}]>` is not implemented for `&usize`
    = help: the trait `SliceIndex<[{integer}]>` is implemented for `usize`
    = help: for that trait implementation, expected `usize`, found `&usize`
    = note: required for `[{integer}]` to implement `Index<&usize>`
diff --git a/tests/ui/suggestions/suggest-pin-macro.stderr b/tests/ui/suggestions/suggest-pin-macro.stderr
index 68f4099a976..a761a454ad5 100644
--- a/tests/ui/suggestions/suggest-pin-macro.stderr
+++ b/tests/ui/suggestions/suggest-pin-macro.stderr
@@ -2,7 +2,7 @@ error[E0277]: `PhantomPinned` cannot be unpinned
   --> $DIR/suggest-pin-macro.rs:22:17
    |
 LL |     dummy(test1.get_mut());
-   |                 ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`, which is required by `Test: Unpin`
+   |                 ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`
    |
    = note: consider using the `pin!` macro
            consider using `Box::pin` if you need to access the pinned value outside of the current scope
diff --git a/tests/ui/suggestions/suggest-remove-refs-1.stderr b/tests/ui/suggestions/suggest-remove-refs-1.stderr
index 171184bf77d..523f78dffcc 100644
--- a/tests/ui/suggestions/suggest-remove-refs-1.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-1.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
 LL |     for (i, _) in &v.iter().enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
 help: consider removing the leading `&`-reference
    |
diff --git a/tests/ui/suggestions/suggest-remove-refs-2.stderr b/tests/ui/suggestions/suggest-remove-refs-2.stderr
index 4e1994523dc..bbe3261e148 100644
--- a/tests/ui/suggestions/suggest-remove-refs-2.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterat
 LL |     for (i, _) in & & & & &v.iter().enumerate() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
 help: consider removing 5 leading `&`-references
    |
diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr
index 1d180f9d8be..a3e142563ff 100644
--- a/tests/ui/suggestions/suggest-remove-refs-3.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr
@@ -8,7 +8,7 @@ LL | |         .iter()
 LL | |         .enumerate() {
    | |____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`, which is required by `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
 help: consider removing 5 leading `&`-references
    |
diff --git a/tests/ui/suggestions/suggest-remove-refs-4.stderr b/tests/ui/suggestions/suggest-remove-refs-4.stderr
index 7ab34c4af51..ed9fc2dd256 100644
--- a/tests/ui/suggestions/suggest-remove-refs-4.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-4.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator
 LL |     for _i in &foo {}
    |               ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`, which is required by `&&std::slice::Iter<'_, {integer}>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`
    = note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
 help: consider removing 2 leading `&`-references
    |
diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr
index b132c56473e..ae83012c70e 100644
--- a/tests/ui/suggestions/suggest-remove-refs-5.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&mut &mut &mut &mut Vec<i32>` is not an iterator
 LL |     for _ in &mut &mut v {}
    |              ^^^^^^^^^^^ `&mut &mut &mut &mut Vec<i32>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `Vec<i32>`, which is required by `&mut &mut &mut &mut Vec<i32>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `Vec<i32>`
    = note: required for `&mut Vec<i32>` to implement `Iterator`
    = note: 3 redundant requirements hidden
    = note: required for `&mut &mut &mut &mut Vec<i32>` to implement `Iterator`
@@ -21,7 +21,7 @@ error[E0277]: `&mut &mut &mut [u8; 1]` is not an iterator
 LL |     for _ in &mut v {}
    |              ^^^^^^ `&mut &mut &mut [u8; 1]` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `[u8; 1]`, which is required by `&mut &mut &mut [u8; 1]: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `[u8; 1]`
    = note: required for `&mut [u8; 1]` to implement `Iterator`
    = note: 2 redundant requirements hidden
    = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator`
diff --git a/tests/ui/sync/mutexguard-sync.stderr b/tests/ui/sync/mutexguard-sync.stderr
index 6b686741d1f..1501a793d5e 100644
--- a/tests/ui/sync/mutexguard-sync.stderr
+++ b/tests/ui/sync/mutexguard-sync.stderr
@@ -6,7 +6,7 @@ LL |     test_sync(guard);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Sync` is not implemented for `Cell<i32>`, which is required by `MutexGuard<'_, Cell<i32>>: Sync`
+   = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
    = note: required for `MutexGuard<'_, Cell<i32>>` to implement `Sync`
 note: required by a bound in `test_sync`
diff --git a/tests/ui/sync/reentrantlockguard-sync.stderr b/tests/ui/sync/reentrantlockguard-sync.stderr
index ed2e3e2f112..6bedf8f9f2e 100644
--- a/tests/ui/sync/reentrantlockguard-sync.stderr
+++ b/tests/ui/sync/reentrantlockguard-sync.stderr
@@ -6,7 +6,7 @@ LL |     test_sync(guard);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Sync` is not implemented for `Cell<i32>`, which is required by `ReentrantLockGuard<'_, Cell<i32>>: Sync`
+   = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` or `std::sync::atomic::AtomicI32` instead
    = note: required for `ReentrantLockGuard<'_, Cell<i32>>` to implement `Sync`
 note: required by a bound in `test_sync`
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index b2431698cc6..8cff7887661 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -41,7 +41,7 @@ body:
                             Block {
                                 targeted_by_break: false
                                 span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
-                                region_scope: Node(25)
+                                region_scope: Node(3)
                                 safety_mode: Safe
                                 stmts: []
                                 expr:
@@ -51,8 +51,8 @@ body:
                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                         kind: 
                                             Scope {
-                                                region_scope: Node(3)
-                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).3))
+                                                region_scope: Node(4)
+                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
                                                 value:
                                                     Expr {
                                                         ty: bool
@@ -67,8 +67,8 @@ body:
                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                         kind: 
                                                                             Scope {
-                                                                                region_scope: Node(4)
-                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).4))
+                                                                                region_scope: Node(5)
+                                                                                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).5))
                                                                                 value:
                                                                                     Expr {
                                                                                         ty: Foo
@@ -123,16 +123,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(12))
+                                                                                temp_lifetime: Some(Node(13))
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(13)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
+                                                                                        region_scope: Node(14)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(12))
+                                                                                                temp_lifetime: Some(Node(13))
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -140,8 +140,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).12))
-                                                                        scope: Node(12)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
+                                                                        scope: Node(13)
                                                                         span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
                                                                     }
                                                                     Arm {
@@ -175,16 +175,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(18))
+                                                                                temp_lifetime: Some(Node(19))
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(19)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
+                                                                                        region_scope: Node(20)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(18))
+                                                                                                temp_lifetime: Some(Node(19))
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -192,8 +192,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).18))
-                                                                        scope: Node(18)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
+                                                                        scope: Node(19)
                                                                         span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
                                                                     }
                                                                     Arm {
@@ -219,16 +219,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: Some(Node(23))
+                                                                                temp_lifetime: Some(Node(24))
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(24)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
+                                                                                        region_scope: Node(25)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: Some(Node(23))
+                                                                                                temp_lifetime: Some(Node(24))
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -236,8 +236,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).23))
-                                                                        scope: Node(23)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
+                                                                        scope: Node(24)
                                                                         span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
                                                                     }
                                                                 ]
diff --git a/tests/ui/trait-bounds/super-assoc-mismatch.stderr b/tests/ui/trait-bounds/super-assoc-mismatch.stderr
index f2c5eb47e59..780535283a3 100644
--- a/tests/ui/trait-bounds/super-assoc-mismatch.stderr
+++ b/tests/ui/trait-bounds/super-assoc-mismatch.stderr
@@ -53,7 +53,7 @@ error[E0277]: the trait bound `(): Sub` is not satisfied
   --> $DIR/super-assoc-mismatch.rs:29:21
    |
 LL |     type Assoc<T> = ();
-   |                     ^^ the trait `Sub` is not implemented for `()`, which is required by `<u8 as BoundOnGat>::Assoc<u8>: Sub`
+   |                     ^^ the trait `Sub` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/super-assoc-mismatch.rs:7:1
@@ -87,7 +87,7 @@ error[E0277]: the trait bound `(): SubGeneric<u16>` is not satisfied
   --> $DIR/super-assoc-mismatch.rs:55:22
    |
 LL |     type Assoc1<T> = ();
-   |                      ^^ the trait `SubGeneric<u16>` is not implemented for `()`, which is required by `<u8 as MultiAssoc>::Assoc1<()>: SubGeneric<<u8 as MultiAssoc>::Assoc2>`
+   |                      ^^ the trait `SubGeneric<u16>` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/super-assoc-mismatch.rs:43:1
diff --git a/tests/ui/traits/alias/cross-crate.stderr b/tests/ui/traits/alias/cross-crate.stderr
index 52eb7e44f44..8ed05b4758d 100644
--- a/tests/ui/traits/alias/cross-crate.stderr
+++ b/tests/ui/traits/alias/cross-crate.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Rc<u32>: SendSync` is not satisfied
   --> $DIR/cross-crate.rs:14:17
    |
 LL |     use_alias::<Rc<u32>>();
-   |                 ^^^^^^^ the trait `Send` is not implemented for `Rc<u32>`, which is required by `Rc<u32>: SendSync`
+   |                 ^^^^^^^ the trait `Send` is not implemented for `Rc<u32>`
    |
    = note: required for `Rc<u32>` to implement `SendSync`
 note: required by a bound in `use_alias`
@@ -15,7 +15,7 @@ error[E0277]: the trait bound `Rc<u32>: SendSync` is not satisfied
   --> $DIR/cross-crate.rs:14:17
    |
 LL |     use_alias::<Rc<u32>>();
-   |                 ^^^^^^^ the trait `Sync` is not implemented for `Rc<u32>`, which is required by `Rc<u32>: SendSync`
+   |                 ^^^^^^^ the trait `Sync` is not implemented for `Rc<u32>`
    |
    = note: required for `Rc<u32>` to implement `SendSync`
 note: required by a bound in `use_alias`
diff --git a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr
index c73c2f68032..27e23adb92a 100644
--- a/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr
+++ b/tests/ui/traits/alias/issue-108072-unmet-trait-alias-bound.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): IteratorAlias` is not satisfied
   --> $DIR/issue-108072-unmet-trait-alias-bound.rs:10:7
    |
 LL |     f(())
-   |     - ^^ the trait `Iterator` is not implemented for `()`, which is required by `(): IteratorAlias`
+   |     - ^^ the trait `Iterator` is not implemented for `()`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
index dc2de5bb715..667d283bea3 100644
--- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
+++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.rs
@@ -2,7 +2,7 @@ fn strip_lf(s: &str) -> &str {
     s.strip_suffix(b'\n').unwrap_or(s)
     //~^ ERROR the trait bound `u8: Pattern` is not satisfied
     //~| NOTE required by a bound introduced by this call
-    //~| NOTE the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern`
+    //~| NOTE the trait `FnMut(char)` is not implemented for `u8`
     //~| HELP the following other types implement trait `Pattern`:
     //~| NOTE required for `u8` to implement `Pattern`
     //~| NOTE required by a bound in `core::str::<impl str>::strip_suffix`
diff --git a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
index 8351d15fdf3..1cd62d2cbdb 100644
--- a/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
+++ b/tests/ui/traits/bound/assoc-fn-bound-root-obligation.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: Pattern` is not satisfied
   --> $DIR/assoc-fn-bound-root-obligation.rs:2:20
    |
 LL |     s.strip_suffix(b'\n').unwrap_or(s)
-   |       ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`, which is required by `u8: Pattern`
+   |       ------------ ^^^^^ the trait `FnMut(char)` is not implemented for `u8`
    |       |
    |       required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/const-traits/assoc-type.stderr b/tests/ui/traits/const-traits/assoc-type.stderr
index 5c77754200a..672eaf26f72 100644
--- a/tests/ui/traits/const-traits/assoc-type.stderr
+++ b/tests/ui/traits/const-traits/assoc-type.stderr
@@ -17,7 +17,7 @@ note: required by a bound in `Foo::Bar`
   --> $DIR/assoc-type.rs:32:15
    |
 LL |     type Bar: ~const Add;
-   |               ^^^^^^^^^^ required by this bound in `Foo::Bar`
+   |               ^^^^^^ required by this bound in `Foo::Bar`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
index 971e77e372b..52ee04425b2 100644
--- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr
+++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-in-impl.rs:10:16
+  --> $DIR/call-generic-in-impl.rs:10:9
    |
 LL | impl<T: ~const PartialEq> const MyPartialEq for T {
-   |                ^^^^^^^^^
+   |         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-in-impl.rs:10:16
+  --> $DIR/call-generic-in-impl.rs:10:9
    |
 LL | impl<T: ~const PartialEq> const MyPartialEq for T {
-   |                ^^^^^^^^^
+   |         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
index aa90305c648..6dbf3ad2526 100644
--- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr
@@ -17,30 +17,30 @@ LL | impl const PartialEq for S {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:20:32
+  --> $DIR/call-generic-method-chain.rs:20:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:20:32
+  --> $DIR/call-generic-method-chain.rs:20:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:24:40
+  --> $DIR/call-generic-method-chain.rs:24:33
    |
 LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
-   |                                        ^^^^^^^^^
+   |                                 ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-chain.rs:24:40
+  --> $DIR/call-generic-method-chain.rs:24:33
    |
 LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool {
-   |                                        ^^^^^^^^^
+   |                                 ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
index 029915b7646..08877daad79 100644
--- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr
@@ -17,30 +17,30 @@ LL | impl const PartialEq for S {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:20:44
+  --> $DIR/call-generic-method-dup-bound.rs:20:37
    |
 LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
-   |                                            ^^^^^^^^^
+   |                                     ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:20:44
+  --> $DIR/call-generic-method-dup-bound.rs:20:37
    |
 LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool {
-   |                                            ^^^^^^^^^
+   |                                     ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:27:37
+  --> $DIR/call-generic-method-dup-bound.rs:27:30
    |
 LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
-   |                                     ^^^^^^^^^
+   |                              ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-dup-bound.rs:27:37
+  --> $DIR/call-generic-method-dup-bound.rs:27:30
    |
 LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool {
-   |                                     ^^^^^^^^^
+   |                              ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
index 97ce7fe1c2a..ac08c057435 100644
--- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr
+++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr
@@ -17,16 +17,16 @@ LL | impl const PartialEq for S {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-pass.rs:20:32
+  --> $DIR/call-generic-method-pass.rs:20:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/call-generic-method-pass.rs:20:32
+  --> $DIR/call-generic-method-pass.rs:20:25
    |
 LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool {
-   |                                ^^^^^^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
index 6c3c11c6a47..8e836685eb0 100644
--- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
+++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr
@@ -7,30 +7,25 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-bounds-non-const-trait.rs:6:28
+  --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform<T: ~const NonConst>() {}
-   |                            ^^^^^^^^
+   |                     ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-bounds-non-const-trait.rs:6:28
+  --> $DIR/const-bounds-non-const-trait.rs:6:21
    |
 LL | const fn perform<T: ~const NonConst>() {}
-   |                            ^^^^^^^^
+   |                     ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-bounds-non-const-trait.rs:10:21
+  --> $DIR/const-bounds-non-const-trait.rs:10:15
    |
 LL | fn operate<T: const NonConst>() {}
-   |                     ^^^^^^^^
+   |               ^^^^^
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
index 12cc79f5961..25c81ff900f 100644
--- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
+++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-parse-not-item.rs:7:32
+  --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-parse-not-item.rs:7:32
+  --> $DIR/const-closure-parse-not-item.rs:7:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
index f0f033bceef..cb4c994bc2f 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method-fail.rs:14:39
+  --> $DIR/const-closure-trait-method-fail.rs:14:32
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method-fail.rs:14:39
+  --> $DIR/const-closure-trait-method-fail.rs:14:32
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
index 4c5a4d0cdf4..43af435ae64 100644
--- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr
+++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method.rs:14:39
+  --> $DIR/const-closure-trait-method.rs:14:32
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closure-trait-method.rs:14:39
+  --> $DIR/const-closure-trait-method.rs:14:32
    |
 LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 {
-   |                                       ^^^^^^^^^^^^^^^^^
+   |                                ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr
index a81804a50dc..2e9e37ba321 100644
--- a/tests/ui/traits/const-traits/const-closures.stderr
+++ b/tests/ui/traits/const-traits/const-closures.stderr
@@ -1,56 +1,56 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:8:19
+  --> $DIR/const-closures.rs:8:12
    |
 LL |         F: ~const FnOnce() -> u8,
-   |                   ^^^^^^^^^^^^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:9:19
+  --> $DIR/const-closures.rs:9:12
    |
 LL |         F: ~const FnMut() -> u8,
-   |                   ^^^^^^^^^^^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:10:19
+  --> $DIR/const-closures.rs:10:12
    |
 LL |         F: ~const Fn() -> u8,
-   |                   ^^^^^^^^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:8:19
+  --> $DIR/const-closures.rs:8:12
    |
 LL |         F: ~const FnOnce() -> u8,
-   |                   ^^^^^^^^^^^^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:9:19
+  --> $DIR/const-closures.rs:9:12
    |
 LL |         F: ~const FnMut() -> u8,
-   |                   ^^^^^^^^^^^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:10:19
+  --> $DIR/const-closures.rs:10:12
    |
 LL |         F: ~const Fn() -> u8,
-   |                   ^^^^^^^^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:23:27
+  --> $DIR/const-closures.rs:23:20
    |
 LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
-   |                           ^^^^^^^^^^
+   |                    ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-closures.rs:23:27
+  --> $DIR/const-closures.rs:23:20
    |
 LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 {
-   |                           ^^^^^^^^^^
+   |                    ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-drop-bound.stderr b/tests/ui/traits/const-traits/const-drop-bound.stderr
index d94b0542324..3f718645433 100644
--- a/tests/ui/traits/const-traits/const-drop-bound.stderr
+++ b/tests/ui/traits/const-traits/const-drop-bound.stderr
@@ -1,42 +1,42 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:9:68
+  --> $DIR/const-drop-bound.rs:9:61
    |
 LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
-   |                                                                    ^^^^^^^^
+   |                                                             ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:9:68
+  --> $DIR/const-drop-bound.rs:9:61
    |
 LL | const fn foo<T, E>(res: Result<T, E>) -> Option<T> where E: ~const Destruct {
-   |                                                                    ^^^^^^^^
+   |                                                             ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:20:15
+  --> $DIR/const-drop-bound.rs:20:8
    |
 LL |     T: ~const Destruct,
-   |               ^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:21:15
+  --> $DIR/const-drop-bound.rs:21:8
    |
 LL |     E: ~const Destruct,
-   |               ^^^^^^^^
+   |        ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:20:15
+  --> $DIR/const-drop-bound.rs:20:8
    |
 LL |     T: ~const Destruct,
-   |               ^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-bound.rs:21:15
+  --> $DIR/const-drop-bound.rs:21:8
    |
 LL |     E: ~const Destruct,
-   |               ^^^^^^^^
+   |        ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-drop-fail-2.stderr b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
index 27e8053c969..82d6412ded0 100644
--- a/tests/ui/traits/const-traits/const-drop-fail-2.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail-2.stderr
@@ -8,16 +8,16 @@ LL | impl<T: ~const A> const Drop for ConstDropImplWithNonConstBounds<T> {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail-2.rs:20:26
+  --> $DIR/const-drop-fail-2.rs:20:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail-2.rs:20:26
+  --> $DIR/const-drop-fail-2.rs:20:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
index bde13b4d6cf..859fdfae81a 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.precise.stderr
@@ -8,16 +8,16 @@ LL | impl const Drop for ConstImplWithDropGlue {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
index 064ffacca42..20dea28922b 100644
--- a/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop-fail.stock.stderr
@@ -8,16 +8,16 @@ LL | impl const Drop for ConstImplWithDropGlue {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop-fail.rs:23:26
+  --> $DIR/const-drop-fail.rs:23:19
    |
 LL | const fn check<T: ~const Destruct>(_: T) {}
-   |                          ^^^^^^^^
+   |                   ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/const-drop.precise.stderr b/tests/ui/traits/const-traits/const-drop.precise.stderr
index 7b6d185c7cc..381e4d78c28 100644
--- a/tests/ui/traits/const-traits/const-drop.precise.stderr
+++ b/tests/ui/traits/const-traits/const-drop.precise.stderr
@@ -35,19 +35,43 @@ LL |     impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+  --> $DIR/const-drop.rs:67:46
+   |
+LL |     impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `t::ConstDropWithBound`
+  --> $DIR/const-drop.rs:65:38
+   |
+LL |     pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+   |                                      ^^^^^ required by this bound in `ConstDropWithBound`
+
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+  --> $DIR/const-drop.rs:68:22
+   |
+LL |         fn drop(&mut self) {
+   |                      ^^^^
+   |
+note: required by a bound in `t::ConstDropWithBound`
+  --> $DIR/const-drop.rs:65:38
+   |
+LL |     pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+   |                                      ^^^^^ required by this bound in `ConstDropWithBound`
+
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop.rs:18:32
    |
@@ -66,7 +90,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable
 LL + #![feature(effects)]
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0015, E0493.
+Some errors have detailed explanations: E0015, E0277, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const-drop.stock.stderr b/tests/ui/traits/const-traits/const-drop.stock.stderr
index b497c39b08a..399e7849673 100644
--- a/tests/ui/traits/const-traits/const-drop.stock.stderr
+++ b/tests/ui/traits/const-traits/const-drop.stock.stderr
@@ -35,19 +35,43 @@ LL |     impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> {
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-drop.rs:18:22
+  --> $DIR/const-drop.rs:18:15
    |
 LL | const fn a<T: ~const Destruct>(_: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+  --> $DIR/const-drop.rs:67:46
+   |
+LL |     impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
+   |                                              ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required by a bound in `t::ConstDropWithBound`
+  --> $DIR/const-drop.rs:65:38
+   |
+LL |     pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+   |                                      ^^^^^ required by this bound in `ConstDropWithBound`
+
+error[E0277]: the trait bound `T: const SomeTrait` is not satisfied
+  --> $DIR/const-drop.rs:68:22
+   |
+LL |         fn drop(&mut self) {
+   |                      ^^^^
+   |
+note: required by a bound in `t::ConstDropWithBound`
+  --> $DIR/const-drop.rs:65:38
+   |
+LL |     pub struct ConstDropWithBound<T: const SomeTrait>(pub core::marker::PhantomData<T>);
+   |                                      ^^^^^ required by this bound in `ConstDropWithBound`
+
 error[E0493]: destructor of `T` cannot be evaluated at compile-time
   --> $DIR/const-drop.rs:18:32
    |
@@ -68,7 +92,7 @@ help: add `#![feature(effects)]` to the crate attributes to enable
 LL + #![feature(effects)]
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
-Some errors have detailed explanations: E0015, E0493.
+Some errors have detailed explanations: E0015, E0277, E0493.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
index 4bcc17952e6..8f4235dabad 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr
@@ -7,11 +7,6 @@ LL | #![feature(derive_const, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
   --> $DIR/derive-const-non-const-type.rs:10:16
    |
@@ -33,6 +28,6 @@ LL | pub struct S(A);
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
index d471a8253ba..7fc44229e2a 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr
@@ -19,11 +19,6 @@ error[E0635]: unknown feature `const_default_impls`
 LL | #![feature(const_trait_impl, const_cmp, const_default_impls, derive_const, effects)]
    |                                         ^^^^^^^^^^^^^^^^^^^
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `Default` which is not marked with `#[const_trait]`
   --> $DIR/derive-const-use.rs:7:12
    |
@@ -122,7 +117,7 @@ LL | pub struct S((), A);
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 13 previous errors; 1 warning emitted
+error: aborting due to 12 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0015, E0635.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
index 33e7e08bb23..1395947bb15 100644
--- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
+++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr
@@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `PartialEq` which is not marked with `#[const_trait]`
   --> $DIR/derive-const-with-params.rs:7:16
    |
@@ -23,12 +18,6 @@ LL | #[derive_const(PartialEq)]
    = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/derive-const-with-params.rs:7:16
-   |
-LL | #[derive_const(PartialEq)]
-   |                ^^^^^^^^^
-   |
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/derive-const-with-params.rs:8:23
@@ -49,6 +38,6 @@ LL |     a == b
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
index edfdf8b5f78..36184856035 100644
--- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
+++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr
@@ -17,22 +17,17 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-112822-expected-type-for-param.rs:3:32
+  --> $DIR/ice-112822-expected-type-for-param.rs:3:25
    |
 LL | const fn test() -> impl ~const Fn() {
-   |                                ^^^^
+   |                         ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
@@ -54,7 +49,7 @@ LL |                 assert_eq!(first, &b'f');
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
index b08aba9acbc..c6b94fa2230 100644
--- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.rs
@@ -23,4 +23,5 @@ const FOO: () = {
     //~^ ERROR: function takes 0 generic arguments but 1 generic argument was supplied
     <() as Bar<false>>::bar();
     //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR the trait bound `(): const Bar` is not satisfied
 };
diff --git a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
index a3aa970e94d..bd9acc7a6d2 100644
--- a/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
+++ b/tests/ui/traits/const-traits/effects/no-explicit-const-params.stderr
@@ -7,11 +7,6 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/no-explicit-const-params.rs:22:5
    |
@@ -40,6 +35,12 @@ note: trait defined here, with 0 generic parameters
 LL | trait Bar {
    |       ^^^
 
+error[E0277]: the trait bound `(): const Bar` is not satisfied
+  --> $DIR/no-explicit-const-params.rs:24:5
+   |
+LL |     <() as Bar<false>>::bar();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0107]: function takes 0 generic arguments but 1 generic argument was supplied
   --> $DIR/no-explicit-const-params.rs:15:5
    |
@@ -70,4 +71,5 @@ LL | trait Bar {
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
-For more information about this error, try `rustc --explain E0107`.
+Some errors have detailed explanations: E0107, E0277.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
index 5ff1c6c5b9f..97663232fcf 100644
--- a/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
+++ b/tests/ui/traits/const-traits/effects/span-bug-issue-121418.stderr
@@ -17,11 +17,6 @@ LL | #![feature(effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0308]: mismatched types
   --> $DIR/span-bug-issue-121418.rs:9:27
    |
@@ -39,12 +34,12 @@ error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at
 LL |     pub const fn new() -> std::sync::Mutex<dyn T> {}
    |                           ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`, which is required by `Mutex<(dyn T + 'static)>: Sized`
+   = help: within `Mutex<(dyn T + 'static)>`, the trait `Sized` is not implemented for `(dyn T + 'static)`
 note: required because it appears within the type `Mutex<(dyn T + 'static)>`
   --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL
    = note: the return type of a function must have a statically known size
 
-error: aborting due to 4 previous errors; 1 warning emitted
+error: aborting due to 3 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
index d9655c4995f..273f9943212 100644
--- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
+++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr
@@ -7,11 +7,6 @@ LL | #![feature(effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `Foo` which is not marked with `#[const_trait]`
   --> $DIR/spec-effectvar-ice.rs:11:15
    |
@@ -37,10 +32,10 @@ LL | impl<T> const Foo for T where T: const Specialize {}
    = note: adding a non-const method body in the future would be a breaking change
 
 error: `const` can only be applied to `#[const_trait]` traits
-  --> $DIR/spec-effectvar-ice.rs:14:40
+  --> $DIR/spec-effectvar-ice.rs:14:34
    |
 LL | impl<T> const Foo for T where T: const Specialize {}
-   |                                        ^^^^^^^^^^
+   |                                  ^^^^^
 
 error: specialization impl does not specialize any associated items
   --> $DIR/spec-effectvar-ice.rs:14:1
@@ -60,5 +55,5 @@ error: cannot specialize on trait `Specialize`
 LL | impl<T> const Foo for T where T: const Specialize {}
    |                                  ^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
index 15cb84026e4..33914cb306d 100644
--- a/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
+++ b/tests/ui/traits/const-traits/effects/trait-fn-const.stderr
@@ -63,11 +63,6 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
deleted file mode 100644
index 20448f51de2..00000000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.coherence.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs b/tests/ui/traits/const-traits/effects/with-without-next-solver.rs
deleted file mode 100644
index f022af05c50..00000000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// test that we error correctly when effects is used without the next-solver flag.
-//@ revisions: stock coherence full
-//@[coherence] compile-flags: -Znext-solver=coherence
-//@[full] compile-flags: -Znext-solver
-//@[full] check-pass
-
-#![feature(effects)]
-#![allow(incomplete_features)]
-
-fn main() {}
diff --git a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr b/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
deleted file mode 100644
index 20448f51de2..00000000000
--- a/tests/ui/traits/const-traits/effects/with-without-next-solver.stock.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
index 50cdded8d51..9e22422ad3b 100644
--- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
+++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
   --> $DIR/ice-119717-constant-lifetime.rs:6:15
    |
@@ -32,7 +27,7 @@ help: try replacing `_` with the type in the corresponding trait method signatur
 LL |     fn from_residual(t: T) -> T {
    |                               ~
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0121, E0210.
 For more information about an error, try `rustc --explain E0121`.
diff --git a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
index 90771c344b5..1a11aec4b26 100644
--- a/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
+++ b/tests/ui/traits/const-traits/ice-120503-async-const-method.stderr
@@ -55,11 +55,6 @@ LL | #![feature(effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0425]: cannot find function `main8` in this scope
   --> $DIR/ice-120503-async-const-method.rs:12:9
    |
@@ -69,7 +64,7 @@ LL |         main8().await;
 LL | fn main() {}
    | --------- similarly named function `main` defined here
 
-error: aborting due to 6 previous errors; 1 warning emitted
+error: aborting due to 5 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0379, E0407, E0425.
 For more information about an error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/ice-121536-const-method.stderr b/tests/ui/traits/const-traits/ice-121536-const-method.stderr
index 29187654c3c..4fe88f263c8 100644
--- a/tests/ui/traits/const-traits/ice-121536-const-method.stderr
+++ b/tests/ui/traits/const-traits/ice-121536-const-method.stderr
@@ -23,11 +23,6 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0379`.
diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
index 03f88be0093..1178c90fce5 100644
--- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
+++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr
@@ -1,21 +1,16 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-123664-unexpected-bound-var.rs:4:34
+  --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
    |
 LL | const fn with_positive<F: ~const Fn()>() {}
-   |                                  ^^^^
+   |                           ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/ice-123664-unexpected-bound-var.rs:4:34
+  --> $DIR/ice-123664-unexpected-bound-var.rs:4:27
    |
 LL | const fn with_positive<F: ~const Fn()>() {}
-   |                                  ^^^^
+   |                           ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
index 284757c1a89..0b1f8b40898 100644
--- a/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
+++ b/tests/ui/traits/const-traits/ice-124857-combine-effect-const-infer-vars.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0119]: conflicting implementations of trait `Foo` for type `i32`
   --> $DIR/ice-124857-combine-effect-const-infer-vars.rs:11:1
    |
@@ -12,6 +7,6 @@ LL |
 LL | impl<T> const Foo for T where T: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `i32`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
index 0ca16a1be40..db047bfd94d 100644
--- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
+++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]`
   --> $DIR/ice-126148-failed-to-normalize.rs:8:12
    |
@@ -54,7 +49,7 @@ LL |     TryMe?;
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0015, E0046.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
index 2ea203627f4..0135296526f 100644
--- a/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
+++ b/tests/ui/traits/const-traits/impl-with-default-fn-fail.stderr
@@ -1,8 +1,3 @@
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error[E0046]: not all trait items implemented, missing: `req`
   --> $DIR/impl-with-default-fn-fail.rs:13:1
    |
@@ -12,6 +7,6 @@ LL |     fn req(&self);
 LL | impl const Tr for u16 {
    | ^^^^^^^^^^^^^^^^^^^^^ missing `req` in implementation
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0046`.
diff --git a/tests/ui/traits/const-traits/issue-92111.stderr b/tests/ui/traits/const-traits/issue-92111.stderr
index 805cc537014..51c6a22b43b 100644
--- a/tests/ui/traits/const-traits/issue-92111.stderr
+++ b/tests/ui/traits/const-traits/issue-92111.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/issue-92111.rs:20:22
+  --> $DIR/issue-92111.rs:20:15
    |
 LL | const fn a<T: ~const Destruct>(t: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/issue-92111.rs:20:22
+  --> $DIR/issue-92111.rs:20:15
    |
 LL | const fn a<T: ~const Destruct>(t: T) {}
-   |                      ^^^^^^^^
+   |               ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
index 3b3868c4bc8..054a8ac7577 100644
--- a/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
+++ b/tests/ui/traits/const-traits/item-bound-entailment-fails.stderr
@@ -17,7 +17,7 @@ note: required by a bound in `Foo::Assoc`
   --> $DIR/item-bound-entailment-fails.rs:6:20
    |
 LL |     type Assoc<T>: ~const Bar
-   |                    ^^^^^^^^^^ required by this bound in `Foo::Assoc`
+   |                    ^^^^^^ required by this bound in `Foo::Assoc`
 
 error[E0277]: the trait bound `T: ~const Bar` is not satisfied
   --> $DIR/item-bound-entailment-fails.rs:25:21
@@ -29,7 +29,7 @@ note: required by a bound in `Foo::Assoc`
   --> $DIR/item-bound-entailment-fails.rs:6:20
    |
 LL |     type Assoc<T>: ~const Bar
-   |                    ^^^^^^^^^^ required by this bound in `Foo::Assoc`
+   |                    ^^^^^^ required by this bound in `Foo::Assoc`
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
index 08a40fe65bf..837effb7ca4 100644
--- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
+++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr
@@ -1,14 +1,14 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/non-const-op-in-closure-in-const.rs:10:51
+  --> $DIR/non-const-op-in-closure-in-const.rs:10:44
    |
 LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
-   |                                                   ^^^^^^^
+   |                                            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/non-const-op-in-closure-in-const.rs:10:51
+  --> $DIR/non-const-op-in-closure-in-const.rs:10:44
    |
 LL | impl<A, B> const Convert<B> for A where B: ~const From<A> {
-   |                                                   ^^^^^^^
+   |                                            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
index 7cd48ef1d48..c50009e9b8c 100644
--- a/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
+++ b/tests/ui/traits/const-traits/predicate-entailment-fails.stderr
@@ -14,7 +14,7 @@ LL |     type Bar<T> where T: ~const Bar;
    |     ----------- definition of `Bar` from trait
 ...
 LL |     type Bar<T> = () where T: const Bar;
-   |                               ^^^^^^^^^ impl has extra requirement `T: const Bar`
+   |                               ^^^^^ impl has extra requirement `T: const Bar`
 
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/predicate-entailment-fails.rs:18:26
@@ -23,7 +23,7 @@ LL |     fn foo<T>() where T: ~const Bar;
    |     -------------------------------- definition of `foo` from trait
 ...
 LL |     fn foo<T>() where T: const Bar {}
-   |                          ^^^^^^^^^ impl has extra requirement `T: const Bar`
+   |                          ^^^^^ impl has extra requirement `T: const Bar`
 
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/predicate-entailment-fails.rs:29:31
@@ -32,7 +32,7 @@ LL |     type Bar<T> where T: Bar;
    |     ----------- definition of `Bar` from trait
 ...
 LL |     type Bar<T> = () where T: const Bar;
-   |                               ^^^^^^^^^ impl has extra requirement `T: const Bar`
+   |                               ^^^^^ impl has extra requirement `T: const Bar`
 
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/predicate-entailment-fails.rs:32:26
@@ -41,7 +41,7 @@ LL |     fn foo<T>() where T: Bar;
    |     ------------------------- definition of `foo` from trait
 ...
 LL |     fn foo<T>() where T: const Bar {}
-   |                          ^^^^^^^^^ impl has extra requirement `T: const Bar`
+   |                          ^^^^^ impl has extra requirement `T: const Bar`
 
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/predicate-entailment-fails.rs:36:31
@@ -50,7 +50,7 @@ LL |     type Bar<T> where T: Bar;
    |     ----------- definition of `Bar` from trait
 ...
 LL |     type Bar<T> = () where T: ~const Bar;
-   |                               ^^^^^^^^^^ impl has extra requirement `T: ~const Bar`
+   |                               ^^^^^^ impl has extra requirement `T: ~const Bar`
 
 error[E0276]: impl has stricter requirements than trait
   --> $DIR/predicate-entailment-fails.rs:39:26
@@ -59,7 +59,7 @@ LL |     fn foo<T>() where T: Bar;
    |     ------------------------- definition of `foo` from trait
 ...
 LL |     fn foo<T>() where T: ~const Bar {}
-   |                          ^^^^^^^^^^ impl has extra requirement `T: ~const Bar`
+   |                          ^^^^^^ impl has extra requirement `T: ~const Bar`
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
index c51d169dd33..363fbee1f8b 100644
--- a/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
+++ b/tests/ui/traits/const-traits/specialization/const-default-impl-non-const-specialized-impl.stderr
@@ -7,16 +7,11 @@ LL | #![feature(const_trait_impl, effects)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: cannot specialize on const impl with non-const impl
   --> $DIR/const-default-impl-non-const-specialized-impl.rs:19:1
    |
 LL | impl Value for FortyTwo {
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/specializing-constness.stderr b/tests/ui/traits/const-traits/specializing-constness.stderr
index e8c4fb0f0c7..226295bf949 100644
--- a/tests/ui/traits/const-traits/specializing-constness.stderr
+++ b/tests/ui/traits/const-traits/specializing-constness.stderr
@@ -7,16 +7,11 @@ LL | #![feature(const_trait_impl, effects, min_specialization, rustc_attrs)]
    = note: see issue #102090 <https://github.com/rust-lang/rust/issues/102090> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
-   |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
-
 error: cannot specialize on const impl with non-const impl
   --> $DIR/specializing-constness.rs:23:1
    |
 LL | impl<T: Spec + Sup> A for T {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
index 6277966b08e..8de1bb07e90 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr
@@ -11,24 +11,24 @@ LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
index 60660ecc279..82b306aeff6 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr
@@ -1,38 +1,38 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-2.rs:12:19
+  --> $DIR/super-traits-fail-2.rs:12:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
index b39bf8d8e15..1dd4a2ed5a5 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr
@@ -11,38 +11,38 @@ LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:22:24
+  --> $DIR/super-traits-fail-3.rs:22:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
+   |                 ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:22:24
+  --> $DIR/super-traits-fail-3.rs:22:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
+   |                 ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
index 187cd998d95..e619b8bd6ba 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr
@@ -1,38 +1,38 @@
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:14:19
+  --> $DIR/super-traits-fail-3.rs:14:12
    |
 LL | trait Bar: ~const Foo {}
-   |                   ^^^
+   |            ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
index b6747d10e83..0a36d40d931 100644
--- a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
+++ b/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr
@@ -11,16 +11,16 @@ LL | trait Bar: ~const Foo {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:22:24
+  --> $DIR/super-traits-fail-3.rs:22:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
+   |                 ^^^^^^
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/super-traits-fail-3.rs:22:24
+  --> $DIR/super-traits-fail-3.rs:22:17
    |
 LL | const fn foo<T: ~const Bar>(x: &T) {
-   |                        ^^^
+   |                 ^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
index f6a7c7c1746..b316ac75a8a 100644
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.rs
@@ -8,6 +8,7 @@ struct Foo<const N: usize>;
 impl<const N: usize> Foo<N> {
     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
         //~^ ERROR `~const` is not allowed here
+        //~| ERROR the trait bound `A: const Add42` is not satisfied
         Foo
     }
 }
@@ -25,6 +26,7 @@ impl const Add42 for () {
 
 fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
     //~^ ERROR `~const` is not allowed here
+    //~| ERROR the trait bound `A: const Add42` is not satisfied
     Foo
 }
 
diff --git a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
index 84a425f6791..78bf85e9c6d 100644
--- a/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
+++ b/tests/ui/traits/const-traits/tilde-const-and-const-params.stderr
@@ -11,21 +11,29 @@ LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
    |        ^^^
 
 error: `~const` is not allowed here
-  --> $DIR/tilde-const-and-const-params.rs:26:11
+  --> $DIR/tilde-const-and-const-params.rs:27:11
    |
 LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
    |           ^^^^^^
    |
 note: this function is not `const`, so it cannot have `~const` trait bounds
-  --> $DIR/tilde-const-and-const-params.rs:26:4
+  --> $DIR/tilde-const-and-const-params.rs:27:4
    |
 LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
    |    ^^^
 
-error: using `#![feature(effects)]` without enabling next trait solver globally
+error[E0277]: the trait bound `A: const Add42` is not satisfied
+  --> $DIR/tilde-const-and-const-params.rs:27:61
    |
-   = note: the next trait solver must be enabled globally for the effects feature to work correctly
-   = help: use `-Znext-solver` to enable
+LL | fn bar<A: ~const Add42, const N: usize>(_: Foo<N>) -> Foo<{ A::add(N) }> {
+   |                                                             ^^^^^^^^^
+
+error[E0277]: the trait bound `A: const Add42` is not satisfied
+  --> $DIR/tilde-const-and-const-params.rs:9:44
+   |
+LL |     fn add<A: ~const Add42>(self) -> Foo<{ A::add(N) }> {
+   |                                            ^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
index e0cf062ad95..35f3019b6ee 100644
--- a/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
+++ b/tests/ui/traits/const-traits/unsatisfied-const-trait-bound.stderr
@@ -28,7 +28,7 @@ note: required by a bound in `require`
   --> $DIR/unsatisfied-const-trait-bound.rs:8:15
    |
 LL | fn require<T: const Trait>() {}
-   |               ^^^^^^^^^^^ required by this bound in `require`
+   |               ^^^^^ required by this bound in `require`
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/copy-impl-cannot-normalize.stderr b/tests/ui/traits/copy-impl-cannot-normalize.stderr
index a98bb47f54f..3bdb8b70172 100644
--- a/tests/ui/traits/copy-impl-cannot-normalize.stderr
+++ b/tests/ui/traits/copy-impl-cannot-normalize.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: TraitFoo` is not satisfied
   --> $DIR/copy-impl-cannot-normalize.rs:22:18
    |
 LL | impl<T> Copy for Foo<T> {}
-   |                  ^^^^^^ the trait `TraitFoo` is not implemented for `T`, which is required by `Foo<T>: Clone`
+   |                  ^^^^^^ the trait `TraitFoo` is not implemented for `T`
    |
 note: required for `Foo<T>` to implement `Clone`
   --> $DIR/copy-impl-cannot-normalize.rs:12:9
diff --git a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
index fecb05cade7..a5d0e6ab095 100644
--- a/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
+++ b/tests/ui/traits/dont-autoderef-ty-with-escaping-var.stderr
@@ -8,7 +8,7 @@ error[E0277]: the trait bound `for<'a> &'a mut Vec<&'a u32>: Foo<'static, i32>`
   --> $DIR/dont-autoderef-ty-with-escaping-var.rs:17:6
    |
 LL |     <i32 as RefFoo<i32>>::ref_foo(unknown);
-   |      ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`, which is required by `i32: RefFoo<i32>`
+   |      ^^^ the trait `for<'a> Foo<'static, i32>` is not implemented for `&'a mut Vec<&'a u32>`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/dont-autoderef-ty-with-escaping-var.rs:3:1
diff --git a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
index 17fced307ed..07edc4ede76 100644
--- a/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
+++ b/tests/ui/traits/inductive-overflow/supertrait-auto-trait.stderr
@@ -10,7 +10,7 @@ error[E0277]: the trait bound `NoClone: Magic` is not satisfied
   --> $DIR/supertrait-auto-trait.rs:16:23
    |
 LL |     let (a, b) = copy(NoClone);
-   |                  ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone`, which is required by `NoClone: Magic`
+   |                  ---- ^^^^^^^ the trait `Copy` is not implemented for `NoClone`
    |                  |
    |                  required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/issue-43784-supertrait.stderr b/tests/ui/traits/issue-43784-supertrait.stderr
index 4c565c3fa1d..2bf365745a6 100644
--- a/tests/ui/traits/issue-43784-supertrait.stderr
+++ b/tests/ui/traits/issue-43784-supertrait.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
   --> $DIR/issue-43784-supertrait.rs:8:22
    |
 LL | impl<T> Complete for T {}
-   |                      ^ the trait `Copy` is not implemented for `T`, which is required by `T: Partial`
+   |                      ^ the trait `Copy` is not implemented for `T`
    |
 note: required for `T` to implement `Partial`
   --> $DIR/issue-43784-supertrait.rs:1:11
diff --git a/tests/ui/traits/issue-7013.stderr b/tests/ui/traits/issue-7013.stderr
index 5067c7d7dd7..17493663172 100644
--- a/tests/ui/traits/issue-7013.stderr
+++ b/tests/ui/traits/issue-7013.stderr
@@ -4,7 +4,7 @@ error[E0277]: `Rc<RefCell<A>>` cannot be sent between threads safely
 LL |     let a = A {v: Box::new(B{v: None}) as Box<dyn Foo + Send>};
    |                   ^^^^^^^^^^^^^^^^^^^^ `Rc<RefCell<A>>` cannot be sent between threads safely
    |
-   = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`, which is required by `B: Send`
+   = help: within `B`, the trait `Send` is not implemented for `Rc<RefCell<A>>`
 note: required because it appears within the type `Option<Rc<RefCell<A>>>`
   --> $SRC_DIR/core/src/option.rs:LL:COL
 note: required because it appears within the type `B`
diff --git a/tests/ui/traits/issue-71036.stderr b/tests/ui/traits/issue-71036.stderr
index 35d543eb017..2452731f19f 100644
--- a/tests/ui/traits/issue-71036.stderr
+++ b/tests/ui/traits/issue-71036.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied
   --> $DIR/issue-71036.rs:11:1
    |
 LL | impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`, which is required by `&'a &'a T: DispatchFromDyn<&'a &'a U>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T`
    |
    = note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
    = note: required for `&'a &'a T` to implement `DispatchFromDyn<&'a &'a U>`
diff --git a/tests/ui/traits/issue-71136.stderr b/tests/ui/traits/issue-71136.stderr
index d37ad8ae34d..2c03c6bf08e 100644
--- a/tests/ui/traits/issue-71136.stderr
+++ b/tests/ui/traits/issue-71136.stderr
@@ -5,7 +5,7 @@ LL | #[derive(Clone)]
    |          ----- in this derive macro expansion
 LL | struct FooHolster {
 LL |     the_foos: Vec<Foo>,
-   |     ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`, which is required by `Vec<Foo>: Clone`
+   |     ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`
    |
    = note: required for `Vec<Foo>` to implement `Clone`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr
index 726ee5b6146..13568179e81 100644
--- a/tests/ui/traits/issue-91594.stderr
+++ b/tests/ui/traits/issue-91594.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
   --> $DIR/issue-91594.rs:10:19
    |
 LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`, which is required by `Foo: Component<Foo>`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
    |
    = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo`
 note: required for `Foo` to implement `Component<Foo>`
diff --git a/tests/ui/traits/issue-97576.stderr b/tests/ui/traits/issue-97576.stderr
index bee254461f1..2c6cfd83b95 100644
--- a/tests/ui/traits/issue-97576.stderr
+++ b/tests/ui/traits/issue-97576.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `String: From<impl ToString>` is not satisfied
   --> $DIR/issue-97576.rs:8:22
    |
 LL |             bar: bar.into(),
-   |                      ^^^^ the trait `From<impl ToString>` is not implemented for `String`, which is required by `impl ToString: Into<_>`
+   |                      ^^^^ the trait `From<impl ToString>` is not implemented for `String`
    |
    = note: required for `impl ToString` to implement `Into<String>`
 
diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr
index 2a3833beb26..8f5b937e586 100644
--- a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr
+++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr
@@ -49,7 +49,7 @@ LL |     is_send((8, TestType));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`, which is required by `({integer}, dummy1c::TestType): Send`
+   = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
    = note: required because it appears within the type `({integer}, dummy1c::TestType)`
 note: required by a bound in `is_send`
   --> $DIR/negated-auto-traits-error.rs:16:15
@@ -87,7 +87,7 @@ LL |     is_send(Box::new(Outer2(TestType)));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`, which is required by `Box<Outer2<dummy3::TestType>>: Send`
+   = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
 note: required because it appears within the type `Outer2<dummy3::TestType>`
   --> $DIR/negated-auto-traits-error.rs:12:8
    |
@@ -110,7 +110,7 @@ LL |     is_sync(Outer2(TestType));
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Send` is not implemented for `main::TestType`, which is required by `Outer2<main::TestType>: Sync`
+   = help: the trait `Send` is not implemented for `main::TestType`
 note: required for `Outer2<main::TestType>` to implement `Sync`
   --> $DIR/negated-auto-traits-error.rs:14:22
    |
diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
index c2029a5a1c8..55f52181ec9 100644
--- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
+++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     is_send(foo());
    |             ^^^^^ future returned by `foo` is not `Send`
    |
-   = help: the trait `Sync` is not implemented for `NotSync`, which is required by `impl Future<Output = ()>: Send`
+   = help: the trait `Sync` is not implemented for `NotSync`
 note: future is not `Send` as this value is used across an await
   --> $DIR/auto-with-drop_tracking_mir.rs:16:11
    |
diff --git a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr
index b487ceef1d4..bb39d110777 100644
--- a/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr
+++ b/tests/ui/traits/next-solver/builtin-fn-must-return-sized.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL |     foo::<fn() -> str, _>(None, ());
    |           ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`, which is required by `fn() -> str: Fn<_>`
+   = help: within `fn() -> str`, the trait `Sized` is not implemented for `str`
    = note: required because it appears within the type `fn() -> str`
 note: required by a bound in `foo`
   --> $DIR/builtin-fn-must-return-sized.rs:10:11
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
index a81229e5e35..9114bcadac0 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
   --> $DIR/incompleteness-unstable-result.rs:65:19
    |
 LL |     impls_trait::<A<X>, _, _, _>();
-   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
    |
    = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
 note: required for `A<X>` to implement `Trait<_, _, _>`
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
index a81229e5e35..9114bcadac0 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
   --> $DIR/incompleteness-unstable-result.rs:65:19
    |
 LL |     impls_trait::<A<X>, _, _, _>();
-   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`
    |
    = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
 note: required for `A<X>` to implement `Trait<_, _, _>`
diff --git a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr
index 9a18a58debd..a841618ec6f 100644
--- a/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr
+++ b/tests/ui/traits/next-solver/diagnostics/point-at-failing-nested.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
   --> $DIR/point-at-failing-nested.rs:22:17
    |
 LL |     needs_foo::<()>();
-   |                 ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
+   |                 ^^ the trait `Bar` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/point-at-failing-nested.rs:4:1
diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr
index ab1d4a56c02..29703679a86 100644
--- a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr
+++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `(): Foo` is not satisfied
   --> $DIR/where-clause-doesnt-apply.rs:18:15
    |
 LL |     needs_foo(());
-   |     --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo`
+   |     --------- ^^ the trait `Bar` is not implemented for `()`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/next-solver/dyn-incompatibility.stderr b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
index 7f2c0646ef5..a720797efc4 100644
--- a/tests/ui/traits/next-solver/dyn-incompatibility.stderr
+++ b/tests/ui/traits/next-solver/dyn-incompatibility.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>
   --> $DIR/dyn-incompatibility.rs:12:12
    |
 LL |     copy::<dyn Setup<From=T>>(t)
-   |            ^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup`
+   |            ^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `dyn Setup<From = T>`
 note: required by a bound in `copy`
@@ -35,7 +35,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>
   --> $DIR/dyn-incompatibility.rs:12:5
    |
 LL |     copy::<dyn Setup<From=T>>(t)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`
    |
    = note: required because it appears within the type `dyn Setup<From = T>`
 help: consider restricting type parameter `T`
diff --git a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
index 65e7dd2ab34..1f319cc6743 100644
--- a/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
+++ b/tests/ui/traits/next-solver/global-cache-and-parallel-frontend.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Clone` is not satisfied
   --> $DIR/global-cache-and-parallel-frontend.rs:15:17
    |
 LL | #[derive(Clone, Eq)]
-   |                 ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
+   |                 ^^ the trait `Clone` is not implemented for `T`
    |
 note: required for `Struct<T>` to implement `PartialEq`
   --> $DIR/global-cache-and-parallel-frontend.rs:18:19
diff --git a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr
index f7d5d6fcee4..f4deb169516 100644
--- a/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr
+++ b/tests/ui/traits/non_lifetime_binders/bad-sized-cond.stderr
@@ -29,7 +29,7 @@ error[E0277]: `V` is not an iterator
 LL |     bar();
    |     ^^^^^ `V` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `V`, which is required by `V: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `V`
    = note: required for `V` to implement `IntoIterator`
 note: required by a bound in `bar`
   --> $DIR/bad-sized-cond.rs:12:15
@@ -46,7 +46,7 @@ error[E0277]: the size for values of type `V` cannot be known at compilation tim
 LL |     bar();
    |     ^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `V`, which is required by `V: IntoIterator`
+   = help: the trait `Sized` is not implemented for `V`
    = note: required for `V` to implement `IntoIterator`
 note: required by a bound in `bar`
   --> $DIR/bad-sized-cond.rs:12:15
diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr
index 0e0ae6d5990..bad325a6720 100644
--- a/tests/ui/traits/question-mark-result-err-mismatch.stderr
+++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr
@@ -11,7 +11,7 @@ LL | |             e;
 LL | |         })
    | |__________- this can't be annotated with `?` because it has type `Result<_, ()>`
 LL |           .map(|()| "")?;
-   |                        ^ the trait `From<()>` is not implemented for `String`, which is required by `Result<String, String>: FromResidual<Result<Infallible, ()>>`
+   |                        ^ the trait `From<()>` is not implemented for `String`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = note: required for `Result<String, String>` to implement `FromResidual<Result<Infallible, ()>>`
@@ -25,7 +25,7 @@ LL |     let x = foo();
    |             ----- this has type `Result<_, String>`
 ...
 LL |         .map_err(|_| ())?;
-   |          ---------------^ the trait `From<()>` is not implemented for `String`, which is required by `Result<(), String>: FromResidual<Result<Infallible, ()>>`
+   |          ---------------^ the trait `From<()>` is not implemented for `String`
    |          |
    |          this can't be annotated with `?` because it has type `Result<_, ()>`
    |
@@ -50,7 +50,7 @@ LL |           .ok_or_else(|| {
 LL | |             "Couldn't split the test string";
    | |                                             - help: remove this semicolon
 LL | |         })?;
-   | |          -^ the trait `From<()>` is not implemented for `String`, which is required by `Result<String, String>: FromResidual<Result<Infallible, ()>>`
+   | |          -^ the trait `From<()>` is not implemented for `String`
    | |__________|
    |            this can't be annotated with `?` because it has type `Result<_, ()>`
    |
diff --git a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr
index 28a0646a86b..8024ad28d5a 100644
--- a/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr
+++ b/tests/ui/traits/suggest-dereferences/dont-suggest-unsize-deref.stderr
@@ -6,7 +6,7 @@ LL |     use_iterator(i);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>`, which is required by `&dyn IntoIterator<IntoIter = I, Item = i32>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&dyn IntoIterator<IntoIter = I, Item = i32>`
    = note: required for `&dyn IntoIterator<IntoIter = I, Item = i32>` to implement `IntoIterator`
 note: required by a bound in `use_iterator`
   --> $DIR/dont-suggest-unsize-deref.rs:3:8
diff --git a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr
index 85d6cdf779b..f0957e5cd9f 100644
--- a/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr
+++ b/tests/ui/traits/suggest-dereferences/invalid-suggest-deref-issue-127590.stderr
@@ -6,7 +6,7 @@ LL |     for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) {
    |                        |
    |                        required by a bound introduced by this call
    |
-   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
    = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
 note: required by a bound in `std::iter::zip`
   --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL
@@ -22,7 +22,7 @@ error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator
 LL |     for (src, dest) in std::iter::zip(fields.iter(), &variant.iter()) {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
    = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>`
    = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator`
    = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
@@ -35,7 +35,7 @@ LL |     for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone(
    |                        |
    |                        required by a bound introduced by this call
    |
-   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `&std::slice::Iter<'_, {integer}>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
    = note: required for `&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
 note: required by a bound in `std::iter::zip`
   --> $SRC_DIR/core/src/iter/adapters/zip.rs:LL:COL
@@ -51,7 +51,7 @@ error[E0277]: `&std::slice::Iter<'_, {integer}>` is not an iterator
 LL |     for (src, dest) in std::iter::zip(fields.iter(), &variant.iter().clone()) {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&std::slice::Iter<'_, {integer}>` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`, which is required by `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&std::slice::Iter<'_, {integer}>`
    = help: the trait `Iterator` is implemented for `std::slice::Iter<'_, T>`
    = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `Iterator`
    = note: required for `Zip<std::slice::Iter<'_, {integer}>, &std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
diff --git a/tests/ui/traits/suggest-dereferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr
index 0eea6cbcc5a..fd45fa3cf74 100644
--- a/tests/ui/traits/suggest-dereferences/issue-39029.stderr
+++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied
   --> $DIR/issue-39029.rs:16:38
    |
 LL |     let _errors = TcpListener::bind(&bad);
-   |                   -----------------  ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`, which is required by `&NoToSocketAddrs: ToSocketAddrs`
+   |                   -----------------  ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs`
    |                   |
    |                   required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/suggest-dereferences/root-obligation.stderr b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
index 2f5e1c5b537..dafd3469b6f 100644
--- a/tests/ui/traits/suggest-dereferences/root-obligation.stderr
+++ b/tests/ui/traits/suggest-dereferences/root-obligation.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&char: Pattern` is not satisfied
   --> $DIR/root-obligation.rs:6:38
    |
 LL |         .filter(|c| "aeiou".contains(c))
-   |                             -------- ^ the trait `Fn(char)` is not implemented for `char`, which is required by `&char: Pattern`
+   |                             -------- ^ the trait `Fn(char)` is not implemented for `char`
    |                             |
    |                             required by a bound introduced by this call
    |
diff --git a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr
index d1d75625aba..d6033bc6baa 100644
--- a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr
+++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied
   --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30
    |
 LL |     let _b: TargetStruct = a.into();
-   |                              ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct`, which is required by `&{integer}: Into<_>`
+   |                              ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct`
    |
    = note: required for `&{integer}` to implement `Into<TargetStruct>`
 help: consider dereferencing here
diff --git a/tests/ui/traits/unsend-future.stderr b/tests/ui/traits/unsend-future.stderr
index 4462208cb49..25df3419794 100644
--- a/tests/ui/traits/unsend-future.stderr
+++ b/tests/ui/traits/unsend-future.stderr
@@ -4,7 +4,7 @@ error: future cannot be sent between threads safely
 LL |     require_handler(handler)
    |                     ^^^^^^^ future returned by `handler` is not `Send`
    |
-   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const i32`, which is required by `fn() -> impl Future<Output = ()> {handler}: Handler`
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `*const i32`
 note: future is not `Send` as this value is used across an await
   --> $DIR/unsend-future.rs:15:14
    |
diff --git a/tests/ui/try-block/try-block-bad-type.stderr b/tests/ui/try-block/try-block-bad-type.stderr
index e9e6255cd2a..d94962e4031 100644
--- a/tests/ui/try-block/try-block-bad-type.stderr
+++ b/tests/ui/try-block/try-block-bad-type.stderr
@@ -2,7 +2,7 @@ error[E0277]: `?` couldn't convert the error to `TryFromSliceError`
   --> $DIR/try-block-bad-type.rs:7:16
    |
 LL |         Err("")?;
-   |         -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`, which is required by `Result<u32, TryFromSliceError>: FromResidual<Result<Infallible, &str>>`
+   |         -------^ the trait `From<&str>` is not implemented for `TryFromSliceError`
    |         |
    |         this can't be annotated with `?` because it has type `Result<_, &str>`
    |
diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr
index 82877baef3e..fe28912ba00 100644
--- a/tests/ui/try-trait/bad-interconversion.stderr
+++ b/tests/ui/try-trait/bad-interconversion.stderr
@@ -4,7 +4,7 @@ error[E0277]: `?` couldn't convert the error to `u8`
 LL | fn result_to_result() -> Result<u64, u8> {
    |                          --------------- expected `u8` because of this
 LL |     Ok(Err(123_i32)?)
-   |        ------------^ the trait `From<i32>` is not implemented for `u8`, which is required by `Result<u64, u8>: FromResidual<Result<Infallible, i32>>`
+   |        ------------^ the trait `From<i32>` is not implemented for `u8`
    |        |
    |        this can't be annotated with `?` because it has type `Result<_, i32>`
    |
diff --git a/tests/ui/try-trait/issue-32709.stderr b/tests/ui/try-trait/issue-32709.stderr
index 9b77f578437..475bd1ff3ac 100644
--- a/tests/ui/try-trait/issue-32709.stderr
+++ b/tests/ui/try-trait/issue-32709.stderr
@@ -4,7 +4,7 @@ error[E0277]: `?` couldn't convert the error to `()`
 LL | fn a() -> Result<i32, ()> {
    |           --------------- expected `()` because of this
 LL |     Err(5)?;
-   |     ------^ the trait `From<{integer}>` is not implemented for `()`, which is required by `Result<i32, ()>: FromResidual<Result<Infallible, {integer}>>`
+   |     ------^ the trait `From<{integer}>` is not implemented for `()`
    |     |
    |     this can't be annotated with `?` because it has type `Result<_, {integer}>`
    |
diff --git a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
index 5c5506fb853..2ed918eca17 100644
--- a/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
+++ b/tests/ui/type-alias-impl-trait/auto-trait-leakage2.stderr
@@ -9,7 +9,7 @@ LL |     is_send(m::foo());
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>`, which is required by `Foo: Send`
+   = help: within `Foo`, the trait `Send` is not implemented for `Rc<u32>`
 note: required because it appears within the type `Foo`
   --> $DIR/auto-trait-leakage2.rs:7:16
    |
diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs
index 1ff200680be..07206dd2491 100644
--- a/tests/ui/type-alias-impl-trait/escaping-bound-var.rs
+++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.rs
@@ -8,6 +8,7 @@ trait Test<'a> {}
 
 pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
+//~| ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
 
 impl Trait<'_> for () {
     type Assoc = ();
diff --git a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr
index 09f6fba79cf..c9f0618639a 100644
--- a/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr
+++ b/tests/ui/type-alias-impl-trait/escaping-bound-var.stderr
@@ -10,6 +10,18 @@ note: lifetime declared here
 LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
    |                         ^^
 
-error: aborting due to 1 previous error
+error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait`
+  --> $DIR/escaping-bound-var.rs:9:57
+   |
+LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
+   |                                                         ^^
+   |
+note: lifetime declared here
+  --> $DIR/escaping-bound-var.rs:9:25
+   |
+LL | pub type Foo = impl for<'a> Trait<'a, Assoc = impl Test<'a>>;
+   |                         ^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0657`.
diff --git a/tests/ui/type-alias-impl-trait/issue-57700.rs b/tests/ui/type-alias-impl-trait/issue-57700.rs
deleted file mode 100644
index 8746545ecc9..00000000000
--- a/tests/ui/type-alias-impl-trait/issue-57700.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(arbitrary_self_types)]
-#![feature(impl_trait_in_assoc_type)]
-
-use std::ops::Deref;
-
-trait Foo {
-    type Bar: Foo;
-
-    fn foo(self: impl Deref<Target = Self>) -> Self::Bar;
-}
-
-impl<C> Foo for C {
-    type Bar = impl Foo;
-
-    fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
-        self
-        //~^ Error type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-    }
-}
-
-fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/issue-57700.stderr b/tests/ui/type-alias-impl-trait/issue-57700.stderr
deleted file mode 100644
index 7efb05f40b0..00000000000
--- a/tests/ui/type-alias-impl-trait/issue-57700.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-57700.rs:16:9
-   |
-LL |         self
-   |         ^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
index a7840e0a5bf..b5f38074632 100644
--- a/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
+++ b/tests/ui/type-alias-impl-trait/multiple-def-uses-in-one-fn.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `&'static B: From<&A>` is not satisfied
   --> $DIR/multiple-def-uses-in-one-fn.rs:9:45
    |
 LL | fn f<A, B: 'static>(a: &'static A, b: B) -> (X<A, B>, X<B, A>) {
-   |                                             ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`, which is required by `&A: Into<&'static B>`
+   |                                             ^^^^^^^^^^^^^^^^^^ the trait `From<&A>` is not implemented for `&'static B`
    |
    = note: required for `&A` to implement `Into<&'static B>`
 help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
diff --git a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
index 913a35eb9fb..e4de9245951 100644
--- a/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
+++ b/tests/ui/type-alias-impl-trait/underconstrained_generic.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `T: Trait` is not satisfied
   --> $DIR/underconstrained_generic.rs:22:5
    |
 LL |     ()
-   |     ^^ the trait `Trait` is not implemented for `T`, which is required by `(): ProofForConversion<T>`
+   |     ^^ the trait `Trait` is not implemented for `T`
    |
 note: required for `()` to implement `ProofForConversion<T>`
   --> $DIR/underconstrained_generic.rs:13:16
diff --git a/tests/ui/type-alias-impl-trait/variance.rs b/tests/ui/type-alias-impl-trait/variance.rs
index 113f6a4cc44..40e8ec0129a 100644
--- a/tests/ui/type-alias-impl-trait/variance.rs
+++ b/tests/ui/type-alias-impl-trait/variance.rs
@@ -11,11 +11,11 @@ type NotCapturedEarly<'a> = impl Sized; //~ ['a: *, 'a: o]
 type CapturedEarly<'a> = impl Sized + Captures<'a>; //~ ['a: *, 'a: o]
 //~^ ERROR: unconstrained opaque type
 
-type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'b: o, 'a: o]
+type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>; //~ ['a: *, 'a: o, 'b: o]
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
 //~| ERROR: unconstrained opaque type
 
-type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'b: o, 'a: o]
+type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>; //~ ['a: *, 'a: o, 'b: o]
 //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
 //~| ERROR: unconstrained opaque type
 
@@ -31,24 +31,24 @@ trait Foo<'i> {
 }
 
 impl<'i> Foo<'i> for &'i () {
-    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 }
 
 impl<'i> Foo<'i> for () {
-    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ImplicitCapture<'a> = impl Sized; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 
-    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'a: o, 'i: o]
+    type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>; //~ ['i: *, 'a: *, 'i: o, 'a: o]
     //~^ ERROR: unconstrained opaque type
 }
 
diff --git a/tests/ui/type-alias-impl-trait/variance.stderr b/tests/ui/type-alias-impl-trait/variance.stderr
index 489dfe03d44..79ce8148f19 100644
--- a/tests/ui/type-alias-impl-trait/variance.stderr
+++ b/tests/ui/type-alias-impl-trait/variance.stderr
@@ -122,13 +122,13 @@ error: ['a: *, 'a: o]
 LL | type CapturedEarly<'a> = impl Sized + Captures<'a>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ['a: *, 'b: o, 'a: o]
+error: ['a: *, 'a: o, 'b: o]
   --> $DIR/variance.rs:14:56
    |
 LL | type NotCapturedLate<'a> = dyn for<'b> Iterator<Item = impl Sized>;
    |                                                        ^^^^^^^^^^
 
-error: ['a: *, 'b: o, 'a: o]
+error: ['a: *, 'a: o, 'b: o]
   --> $DIR/variance.rs:18:49
    |
 LL | type Captured<'a> = dyn for<'b> Iterator<Item = impl Sized + Captures<'a>>;
@@ -140,37 +140,37 @@ error: ['a: *, 'b: *, T: o, 'a: o, 'b: o]
 LL | type Bar<'a, 'b: 'b, T> = impl Sized;
    |                           ^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:34:32
    |
 LL |     type ImplicitCapture<'a> = impl Sized;
    |                                ^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:37:42
    |
 LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:40:39
    |
 LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:45:32
    |
 LL |     type ImplicitCapture<'a> = impl Sized;
    |                                ^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:48:42
    |
 LL |     type ExplicitCaptureFromHeader<'a> = impl Sized + Captures<'i>;
    |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: ['i: *, 'a: *, 'a: o, 'i: o]
+error: ['i: *, 'a: *, 'i: o, 'a: o]
   --> $DIR/variance.rs:51:39
    |
 LL |     type ExplicitCaptureFromGat<'a> = impl Sized + Captures<'a>;
diff --git a/tests/ui/type/issue-58355.stderr b/tests/ui/type/issue-58355.stderr
index cd8e3538802..b6056f0fd65 100644
--- a/tests/ui/type/issue-58355.stderr
+++ b/tests/ui/type/issue-58355.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn ToString` cannot be known at comp
 LL |     x = Some(Box::new(callback));
    |              ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`, which is required by `fn() -> dyn ToString: Fn()`
+   = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString`
    = note: required because it appears within the type `fn() -> dyn ToString`
    = note: required for the cast from `Box<fn() -> dyn ToString>` to `Box<dyn Fn() -> (dyn ToString + 'static)>`
 
diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr
index 137c7b06396..bd7fd0392c3 100644
--- a/tests/ui/typeck/bad-index-due-to-nested.stderr
+++ b/tests/ui/typeck/bad-index-due-to-nested.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `K: Hash` is not satisfied
   --> $DIR/bad-index-due-to-nested.rs:20:5
    |
 LL |     map[k]
-   |     ^^^ the trait `Hash` is not implemented for `K`, which is required by `HashMap<_, _>: Index<&_>`
+   |     ^^^ the trait `Hash` is not implemented for `K`
    |
 note: required for `HashMap<K, V>` to implement `Index<&K>`
   --> $DIR/bad-index-due-to-nested.rs:7:12
@@ -21,7 +21,7 @@ error[E0277]: the trait bound `V: Copy` is not satisfied
   --> $DIR/bad-index-due-to-nested.rs:20:5
    |
 LL |     map[k]
-   |     ^^^ the trait `Copy` is not implemented for `V`, which is required by `HashMap<_, _>: Index<&_>`
+   |     ^^^ the trait `Copy` is not implemented for `V`
    |
 note: required for `HashMap<K, V>` to implement `Index<&K>`
   --> $DIR/bad-index-due-to-nested.rs:7:12
diff --git a/tests/ui/typeck/issue-90101.stderr b/tests/ui/typeck/issue-90101.stderr
index 796e904a438..2e140461c1d 100644
--- a/tests/ui/typeck/issue-90101.stderr
+++ b/tests/ui/typeck/issue-90101.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `PathBuf: From<Cow<'_, str>>` is not satisfied
   --> $DIR/issue-90101.rs:6:10
    |
 LL |     func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
-   |     ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`, which is required by `Cow<'_, str>: Into<PathBuf>`
+   |     ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`
    |     |
    |     required by a bound introduced by this call
    |
diff --git a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr
index 8410574e311..ab307aadec9 100644
--- a/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr
+++ b/tests/ui/typeck/suggest-similar-impls-for-root-obligation.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `((),): Into<Bar>` is not satisfied
   --> $DIR/suggest-similar-impls-for-root-obligation.rs:14:24
    |
 LL |     let _: Bar = ((),).into();
-   |                        ^^^^ the trait `Foo<'_>` is not implemented for `((),)`, which is required by `((),): Into<_>`
+   |                        ^^^^ the trait `Foo<'_>` is not implemented for `((),)`
    |
    = help: the trait `Foo<'_>` is implemented for `()`
    = help: for that trait implementation, expected `()`, found `((),)`
diff --git a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr
index f5311b6e8ed..b9fca1a1b54 100644
--- a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr
+++ b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr
@@ -17,7 +17,7 @@ error[E0277]: `UnsafeCell<u8>` cannot be shared between threads safely
 LL |     is_sync::<MyTypeWUnsafe>();
    |               ^^^^^^^^^^^^^ `UnsafeCell<u8>` cannot be shared between threads safely
    |
-   = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell<u8>`, which is required by `MyTypeWUnsafe: Sync`
+   = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell<u8>`
 note: required because it appears within the type `MyTypeWUnsafe`
   --> $DIR/typeck-default-trait-impl-negation-sync.rs:21:8
    |
@@ -35,7 +35,7 @@ error[E0277]: `Managed` cannot be shared between threads safely
 LL |     is_sync::<MyTypeManaged>();
    |               ^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely
    |
-   = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed`, which is required by `MyTypeManaged: Sync`
+   = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed`
 note: required because it appears within the type `MyTypeManaged`
   --> $DIR/typeck-default-trait-impl-negation-sync.rs:25:8
    |
diff --git a/tests/ui/typeck/typeck-unsafe-always-share.stderr b/tests/ui/typeck/typeck-unsafe-always-share.stderr
index 3eb792b82e0..154e504996b 100644
--- a/tests/ui/typeck/typeck-unsafe-always-share.stderr
+++ b/tests/ui/typeck/typeck-unsafe-always-share.stderr
@@ -36,7 +36,7 @@ LL |     test(ms);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`, which is required by `MySync<NoSync>: Sync`
+   = help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`
 note: required because it appears within the type `MySync<NoSync>`
   --> $DIR/typeck-unsafe-always-share.rs:8:8
    |
diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs
index bddc8c80a7b..77ec70d43d5 100644
--- a/tests/ui/underscore-ident-matcher.rs
+++ b/tests/ui/underscore-ident-matcher.rs
@@ -5,5 +5,5 @@ macro_rules! identity {
 }
 
 fn main() {
-    let identity!(_) = 10; //~ ERROR no rules expected the token `_`
+    let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_`
 }
diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/underscore-ident-matcher.stderr
index a663f34cde1..0c3f980cf6c 100644
--- a/tests/ui/underscore-ident-matcher.stderr
+++ b/tests/ui/underscore-ident-matcher.stderr
@@ -1,4 +1,4 @@
-error: no rules expected the token `_`
+error: no rules expected reserved identifier `_`
   --> $DIR/underscore-ident-matcher.rs:8:19
    |
 LL | macro_rules! identity {
diff --git a/tests/ui/union/projection-as-union-type-error-2.stderr b/tests/ui/union/projection-as-union-type-error-2.stderr
index 39cdf30d860..3b073ca1fb4 100644
--- a/tests/ui/union/projection-as-union-type-error-2.stderr
+++ b/tests/ui/union/projection-as-union-type-error-2.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `u8: NotImplemented` is not satisfied
   --> $DIR/projection-as-union-type-error-2.rs:18:8
    |
 LL |     a: <Foo as Identity>::Identity,
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`, which is required by `u8: Identity`
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NotImplemented` is not implemented for `u8`
    |
 help: this trait has no implementations, consider adding one
   --> $DIR/projection-as-union-type-error-2.rs:9:1
diff --git a/tests/ui/unsized-locals/issue-50940-with-feature.stderr b/tests/ui/unsized-locals/issue-50940-with-feature.stderr
index 4c06566709e..b39eb2e70bb 100644
--- a/tests/ui/unsized-locals/issue-50940-with-feature.stderr
+++ b/tests/ui/unsized-locals/issue-50940-with-feature.stderr
@@ -13,7 +13,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t
 LL |     A as fn(str) -> A<str>;
    |     ^ doesn't have a size known at compile-time
    |
-   = help: within `A<str>`, the trait `Sized` is not implemented for `str`, which is required by `A<str>: Sized`
+   = help: within `A<str>`, the trait `Sized` is not implemented for `str`
 note: required because it appears within the type `A<str>`
   --> $DIR/issue-50940-with-feature.rs:5:12
    |
diff --git a/tests/ui/unsized-locals/rust-call.stderr b/tests/ui/unsized-locals/rust-call.stderr
index b2e13b553e9..9eb0f3dabcc 100644
--- a/tests/ui/unsized-locals/rust-call.stderr
+++ b/tests/ui/unsized-locals/rust-call.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     f(*slice);
    |       ^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]`, which is required by `([u8],): Sized`
+   = help: within `([u8],)`, the trait `Sized` is not implemented for `[u8]`
    = note: required because it appears within the type `([u8],)`
    = note: argument required to be sized due to `extern "rust-call"` ABI
 
diff --git a/tests/ui/unsized-locals/unsized-exprs.stderr b/tests/ui/unsized-locals/unsized-exprs.stderr
index 6da37749fac..8a2ecf0f6c3 100644
--- a/tests/ui/unsized-locals/unsized-exprs.stderr
+++ b/tests/ui/unsized-locals/unsized-exprs.stderr
@@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     udrop::<(i32, [u8])>((42, *foo()));
    |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]`, which is required by `({integer}, [u8]): Sized`
+   = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]`
    = note: required because it appears within the type `({integer}, [u8])`
    = note: tuples must have a statically known size to be initialized
 
@@ -14,7 +14,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     udrop::<A<[u8]>>(A { 0: *foo() });
    |                      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized`
+   = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `A<[u8]>`
   --> $DIR/unsized-exprs.rs:3:8
    |
@@ -28,7 +28,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation
 LL |     udrop::<A<[u8]>>(A(*foo()));
    |                      ^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`, which is required by `A<[u8]>: Sized`
+   = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `A<[u8]>`
   --> $DIR/unsized-exprs.rs:3:8
    |
diff --git a/tests/ui/unsized/unsized-enum2.stderr b/tests/ui/unsized/unsized-enum2.stderr
index 48cca6eb4bd..71cf782120e 100644
--- a/tests/ui/unsized/unsized-enum2.stderr
+++ b/tests/ui/unsized/unsized-enum2.stderr
@@ -320,7 +320,7 @@ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot b
 LL |     VI(Path1),
    |        ^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)`, which is required by `Path1: Sized`
+   = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)`
 note: required because it appears within the type `Path1`
   --> $DIR/unsized-enum2.rs:16:8
    |
@@ -343,7 +343,7 @@ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot b
 LL |     VJ{x: Path2},
    |           ^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)`, which is required by `Path2: Sized`
+   = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)`
 note: required because it appears within the type `Path2`
   --> $DIR/unsized-enum2.rs:17:8
    |
@@ -366,7 +366,7 @@ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot b
 LL |     VK(isize, Path3),
    |               ^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)`, which is required by `Path3: Sized`
+   = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)`
 note: required because it appears within the type `Path3`
   --> $DIR/unsized-enum2.rs:18:8
    |
@@ -389,7 +389,7 @@ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot b
 LL |     VL{u: isize, x: Path4},
    |                     ^^^^^ doesn't have a size known at compile-time
    |
-   = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)`, which is required by `Path4: Sized`
+   = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)`
 note: required because it appears within the type `Path4`
   --> $DIR/unsized-enum2.rs:19:8
    |
diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.stderr
index 93449d60e9d..4b696dc1d1d 100644
--- a/tests/ui/wf/hir-wf-check-erase-regions.stderr
+++ b/tests/ui/wf/hir-wf-check-erase-regions.stderr
@@ -4,7 +4,7 @@ error[E0277]: `&'a T` is not an iterator
 LL |     type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `Flatten<std::slice::Iter<'a, T>>: Iterator`
+   = help: the trait `Iterator` is not implemented for `&'a T`
    = help: the trait `Iterator` is implemented for `&mut I`
    = note: required for `Flatten<std::slice::Iter<'a, T>>` to implement `Iterator`
 note: required by a bound in `std::iter::IntoIterator::IntoIter`
@@ -16,7 +16,7 @@ error[E0277]: `&'a T` is not an iterator
 LL |     type IntoIter = std::iter::Flatten<std::slice::Iter<'a, T>>;
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&'a T`
    = help: the trait `Iterator` is implemented for `&mut I`
    = note: required for `&'a T` to implement `IntoIterator`
 note: required by a bound in `Flatten`
@@ -28,7 +28,7 @@ error[E0277]: `&'a T` is not an iterator
 LL |     fn into_iter(self) -> Self::IntoIter {
    |                           ^^^^^^^^^^^^^^ `&'a T` is not an iterator
    |
-   = help: the trait `Iterator` is not implemented for `&'a T`, which is required by `&'a T: IntoIterator`
+   = help: the trait `Iterator` is not implemented for `&'a T`
    = help: the trait `Iterator` is implemented for `&mut I`
    = note: required for `&'a T` to implement `IntoIterator`
 note: required by a bound in `Flatten`
diff --git a/tests/ui/wf/wf-const-type.stderr b/tests/ui/wf/wf-const-type.stderr
index d73642729ea..dd6e97755bd 100644
--- a/tests/ui/wf/wf-const-type.stderr
+++ b/tests/ui/wf/wf-const-type.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-const-type.rs:10:12
    |
 LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
@@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-const-type.rs:10:12
    |
 LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |            ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
@@ -39,7 +39,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-const-type.rs:10:50
    |
 LL | const FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |                                                  ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |                                                  ^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
index 07e90538b85..6eba6b7abec 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
@@ -22,8 +22,8 @@ fn main() {
         Some(()) => &S,
         None => &R,  //~ ERROR E0308
     }
-    let t: &dyn Trait = match opt() { //~ ERROR E0038
+    let t: &dyn Trait = match opt() {
         Some(()) => &S, //~ ERROR E0038
-        None => &R,
+        None => &R, //~ ERROR E0038
     };
 }
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
index d7366e12256..6cd4ebf8412 100644
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
@@ -31,14 +31,10 @@ LL | trait Trait: Sized {}
    = note: required for the cast from `&S` to `&dyn Trait`
 
 error[E0038]: the trait `Trait` cannot be made into an object
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25
+  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
    |
-LL |       let t: &dyn Trait = match opt() {
-   |  _________________________^
-LL | |         Some(()) => &S,
-LL | |         None => &R,
-LL | |     };
-   | |_____^ `Trait` cannot be made into an object
+LL |         None => &R,
+   |                 ^^ `Trait` cannot be made into an object
    |
 note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
diff --git a/tests/ui/wf/wf-static-type.stderr b/tests/ui/wf/wf-static-type.stderr
index 36234f3fd17..53b90c69960 100644
--- a/tests/ui/wf/wf-static-type.stderr
+++ b/tests/ui/wf/wf-static-type.stderr
@@ -2,7 +2,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-static-type.rs:10:13
    |
 LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
@@ -20,7 +20,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-static-type.rs:10:13
    |
 LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |             ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
@@ -39,7 +39,7 @@ error[E0277]: the trait bound `NotCopy: Copy` is not satisfied
   --> $DIR/wf-static-type.rs:10:51
    |
 LL | static FOO: IsCopy<Option<NotCopy>> = IsCopy { t: None };
-   |                                                   ^^^^ the trait `Copy` is not implemented for `NotCopy`, which is required by `Option<NotCopy>: Copy`
+   |                                                   ^^^^ the trait `Copy` is not implemented for `NotCopy`
    |
    = note: required for `Option<NotCopy>` to implement `Copy`
 note: required by a bound in `IsCopy`
diff --git a/triagebot.toml b/triagebot.toml
index 2e8851e7ec2..7f4def6a11b 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -725,9 +725,6 @@ please modify the tool then regenerate the library source file with the tool
 instead of editing the library source file manually.
 """
 
-[mentions."src/librustdoc/clean/types.rs"]
-cc = ["@camelid"]
-
 [mentions."src/librustdoc/html/static"]
 message = "Some changes occurred in HTML/CSS/JS."
 cc = [
@@ -938,9 +935,6 @@ cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 [mentions."tests/ui/stack-protector"]
 cc = ["@rust-lang/project-exploit-mitigations", "@rcvalle"]
 
-[mentions."tests/ui/check-cfg"]
-cc = ["@Urgau"]
-
 [mentions."compiler/rustc_middle/src/mir/coverage.rs"]
 message = "Some changes occurred in coverage instrumentation."
 cc = ["@Zalathar"]
@@ -972,7 +966,6 @@ cc = ["@kobzol"]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"
 users_on_vacation = [
-    "BoxyUwU",
     "fmease",
     "jyn514",
     "oli-obk",